diff options
Diffstat (limited to 'mpeglib/lib')
323 files changed, 50223 insertions, 0 deletions
diff --git a/mpeglib/lib/Makefile.am b/mpeglib/lib/Makefile.am new file mode 100644 index 00000000..74a7d181 --- /dev/null +++ b/mpeglib/lib/Makefile.am @@ -0,0 +1,36 @@ +# player - Makefile.am + +SUBDIRS = frame util input output decoder \ + splay oggvorbis mpegplay mpgplayer tplay yuv + +MMXFILES = + + +EXTRA_DIST = README + + +THIS_EXTRALIBS = mpgplayer/libmpgplayer.la \ + mpegplay/libmpegplay.la \ + splay/libsplay.la \ + oggvorbis/liboggvorbisbase.la \ + tplay/libtplay.la \ + decoder/libdecoder.la \ + output/liboutput.la \ + input/libinput.la \ + util/libutil.la \ + frame/libframe.la \ + yuv/libyuvPlugin.la + + + +lib_LTLIBRARIES = libmpeg.la + +libmpeg_la_SOURCES = dummy.cpp + + +libmpeg_la_LDFLAGS = $(all_libraries) \ + -release $(THIS_LIB_VERSION) + + +libmpeg_la_LIBADD = $(THIS_EXTRALIBS) $(MMXFILES) \ + $(THIS_LIB_LIBS) diff --git a/mpeglib/lib/README b/mpeglib/lib/README new file mode 100644 index 00000000..91a3b071 --- /dev/null +++ b/mpeglib/lib/README @@ -0,0 +1,80 @@ + + +HOW TO WRITE A PLUGIN +===================== + +we need a audio cd player and a grabber and <insert your cool plugin here> +The Plugin approach is minimalistic. + +The plugin interface only supports one thing: + +* open a stream play it and then close it. + +nothing more. + + +For this you have a class "decoderPlugin.cpp" derive your decoder +from this class and then overwrite the decoder_loop method. +Thats it. + +The typical structure in decoder loop look like this: + +void decoder_loop() { + +1. make instance of decoder and connect it to the input/output +2. go in loop and check sometime a few mutex variables +3. leave loop and destroy your decoder + +} + +For this your have 3 examples how it can be done. +I think splayPlugin.cpp and mpegPlugin.cpp are clean/good +examples for "education". + + +If your decoder supports "seek" you are a bit on your own. +You can look in splayPlugin.cpp how it is handled there. +If your decoder supports seek you must overwrite the seek method. + +Ok, now you have your raw plugin. +If you want to make it a real KDE compliant player with arts integration +you need to write an arts plugin. + + + +further readings +====================== + +* This interface doesn´t offer a gui based config dialog + + To my mind a configuration dialog does not belong into a decoder plugin. + And that´s the main reason why other solutions are not portable: + The plugin interface depend on a widget lib. + + +* This version has a completely reworked plugin interface. + I removed the C bindings. And now the interface is C++. + This made it much more readable. + This should make it a bit easier to inlcude new decoders. + For example look in the directories for mainXYZ.cpp + +inputPlugin: + inputInterfaces like file,http,buffered(loopback) ,cdi +outPlugin : + output for audio/video +playerPlugin: + this is the base class fo new decoders +splay : + mpeg I Layer 1,2,3 audio decoder +mpegplay : + mpeg I video decoder +mpgplayer : + mpeg I audio/video decoder +tplay : + wav decoder +vorbisPlugin: + vorbis decoder.(GPLed mp3 replacement, better compression, + better sound ->www.xiph.org) + + +
\ No newline at end of file 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 diff --git a/mpeglib/lib/dummy.cpp b/mpeglib/lib/dummy.cpp new file mode 100644 index 00000000..94bd1cb7 --- /dev/null +++ b/mpeglib/lib/dummy.cpp @@ -0,0 +1,6 @@ + + + +static int dummy() { + return 0; +} diff --git a/mpeglib/lib/frame/IOFrameQueue.cpp b/mpeglib/lib/frame/IOFrameQueue.cpp new file mode 100644 index 00000000..9a13f1fa --- /dev/null +++ b/mpeglib/lib/frame/IOFrameQueue.cpp @@ -0,0 +1,60 @@ +/* + queues frames in a "empty" and "data" queue + Copyright (C) 2001 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 "IOFrameQueue.h" + + +IOFrameQueue::IOFrameQueue(int size) { + empty=new FrameQueue(size); + data=new FrameQueue(size); + +} + + +IOFrameQueue::~IOFrameQueue() { + delete empty; + delete data; +} + + +// +// empty queue +// +int IOFrameQueue::emptyQueueCanRead() { + return empty->canRead(); +} + + +int IOFrameQueue::emptyQueueCanWrite() { + return empty->canWrite(); +} + + + + +// +// data queue +// +int IOFrameQueue::dataQueueCanRead() { + return data->canRead(); +} + + +int IOFrameQueue::dataQueueCanWrite() { + return data->canWrite(); +} + + + + + diff --git a/mpeglib/lib/frame/IOFrameQueue.h b/mpeglib/lib/frame/IOFrameQueue.h new file mode 100644 index 00000000..d56f25aa --- /dev/null +++ b/mpeglib/lib/frame/IOFrameQueue.h @@ -0,0 +1,60 @@ +/* + queues frames in a "empty" and "data" queue + Copyright (C) 2001 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 __IOFRAMEQUEUE_H +#define __IOFRAMEQUEUE_H + +#include "frameQueue.h" +#include <kdemacros.h> + +/** + This class can store up to <size> frames. + The frames are marked "empty" these frames can be re-used + and filled with data. + The other queue stores "data" frames. These frames can + be dequeued and then are be passed to the "empty" queue. + + Note: you need to _fill_ the empty queue with allocated frames, + after constructions. The pointers then are owned by this + class (== deleted in destructor) + +*/ + +class KDE_EXPORT IOFrameQueue { + + + public: + IOFrameQueue(int size); + ~IOFrameQueue(); + + // + // empty queue + // + int emptyQueueCanRead(); + int emptyQueueCanWrite(); + + + // + // data queue + // + int dataQueueCanRead(); + int dataQueueCanWrite(); + + + protected: + FrameQueue* empty; + FrameQueue* data; + +}; +#endif diff --git a/mpeglib/lib/frame/Makefile.am b/mpeglib/lib/frame/Makefile.am new file mode 100644 index 00000000..753b5f18 --- /dev/null +++ b/mpeglib/lib/frame/Makefile.am @@ -0,0 +1,33 @@ + +# ---- @OS_TYPE@/@ARCH_TYPE@ ---- + +INCLUDES = $(all_includes) + +EXTRA_DIST = README + +kmpgincludedir = $(includedir)/$(THIS_LIB_NAME)/frame + +kmpginclude_HEADERS = pcmFrame.h audioFrame.h \ + floatFrame.h frameQueue.h frame.h \ + IOFrameQueue.h audioFrameQueue.h \ + framer.h rawDataBuffer.h rawFrame.h + +noinst_LTLIBRARIES = libframe.la + +libframe_la_SOURCES = pcmFrame.cpp \ + audioFrame.cpp floatFrame.cpp frame.cpp \ + frameQueue.cpp IOFrameQueue.cpp\ + audioFrameQueue.cpp framer.cpp \ + rawDataBuffer.cpp rawFrame.cpp + + + + + + + + + + + + diff --git a/mpeglib/lib/frame/README b/mpeglib/lib/frame/README new file mode 100644 index 00000000..9e21059f --- /dev/null +++ b/mpeglib/lib/frame/README @@ -0,0 +1,68 @@ + + + +Frames +====== + + +Frames are needed for passing data between decoders around. +A decoder gets an mpeg audio encoded frame as input and +writes data to an audioFrame (pcm/float) + + frame + | + audioFrame + / \ + pcmFrame floatFrame + + +FrameQueues +=========== + +FrameQueues are needed for storing some frames. (For example +you store 100 pre-decoded pcmFrames.) +A FrameQueue is a queue, simply not more. + +IOFrameQueues +============= + +IOFrameQueues deal with the problem, that you first start +with an empty FrameQueue (this is a FrameQueue which contains +prealloceated data, but the data is empty (eg:all pcm samples zero) +Only after converting an "empty" Frame by a decoder (mp3decoder) +the frame if "full" (== Frame with data) +So: IOFrameQueues mark frames with + +i) empty +ii) data + +You can get an empty Frame from the empty-frame-queue and +then enqueue it in the data-frame-queue. +After the frame was used (played) we dequeue it from the +data queue and put them back in the empty queue. +You can see IOFrameQueues as a ringbuffer. +(get free space. write to it. read data. mark space as free,....) + + + FrameQueue + | + IOFrameQueue + / + audioFrameQueue + + +AudioFrameQueue +=============== + +A IOFrameQueue, which allows converting "dataFrames back to continous +stream". +What is this? +Lets say an application wants only 20 byte from a dataFrame which +contains 3KB of data? +There must be some mechanism to read less or more data from the +queue. And the data should be written to a continus memory +segment. +AudioFrameQueue deals with this problem.You can read data from +the queue to a given pointer location. + + diff --git a/mpeglib/lib/frame/audioFrame.cpp b/mpeglib/lib/frame/audioFrame.cpp new file mode 100644 index 00000000..55464afa --- /dev/null +++ b/mpeglib/lib/frame/audioFrame.cpp @@ -0,0 +1,111 @@ +/* + abstract definition of an audio frame + Copyright (C) 2001 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 "audioFrame.h" + +#include <iostream> + +using namespace std; + +AudioFrame::AudioFrame() { + + stereo=-1; + frequencyHZ=-1; + + sampleSize=-1; + lBigEndian=-1; + lSigned=-1; + setFrameType(_FRAME_AUDIO_BASE); +} + + +AudioFrame::~AudioFrame() { +} + + +int AudioFrame::getLen() { + cout << "direct virtual call AudioFrame::getLen"<<endl; + return 0; +} + + +void AudioFrame::setLen(int ) { + cout << "direct virtual call AudioFrame::setLen"<<endl; +} + + +int AudioFrame::getSize() { + cout << "direct virtual call AudioFrame::getSize"<<endl; + return 0; +} + + +void AudioFrame::putFloatData(float* ,int ) { + cout << "direct virtual call AudioFrame::putFloatData"<<endl; +} + +void AudioFrame::putFloatData(float* ,float* ,int ) { + cout << "direct virtual call AudioFrame::putFloatData L/R version"<<endl; +} + +void AudioFrame::clearrawdata() { + cout << "direct virtual call AudioFrame::clearrawdata"<<endl; +} + +void AudioFrame::setFrameFormat(int stereo,int freq) { + this->stereo=stereo; + this->frequencyHZ=freq; +} + + + +int AudioFrame::isFormatEqual(AudioFrame* compare) { + if(compare->getStereo() != stereo) { + return false; + } + if(compare->getSampleSize() != sampleSize) { + return false; + } + if(compare->getBigEndian() != lBigEndian) { + return false; + } + if(compare->getFrequenceHZ() != frequencyHZ) { + return false; + } + if(compare->getSigned() != lSigned) { + return false; + } + return true; +} + +void AudioFrame::print(const char* msg) { + cout << "PCMFrame::print:"<<msg<<endl; + cout << "stereo:"<<stereo<<endl; + cout << "sampleSize:"<<sampleSize<<endl; + cout << "lBigEndian:"<<lBigEndian<<endl; + cout << "frequencyHZ:"<<frequencyHZ<<endl; + cout << "lSigned:"<<lSigned<<endl; +} + + +void AudioFrame::copyFormat(AudioFrame* dest) { + if (dest->getFrameType() != _FRAME_AUDIO_BASE) { + cout << "cannot copy frameFormat into frametype!= _FRAME_AUDIO_BASE"<<endl; + exit(0); + } + dest->setFrameFormat(getStereo(),getFrequenceHZ()); + dest->sampleSize=getSampleSize(); + dest->lBigEndian=getBigEndian(); + dest->lSigned=getSigned(); +} diff --git a/mpeglib/lib/frame/audioFrame.h b/mpeglib/lib/frame/audioFrame.h new file mode 100644 index 00000000..b1c586c3 --- /dev/null +++ b/mpeglib/lib/frame/audioFrame.h @@ -0,0 +1,83 @@ +/* + abstract definition of an audio frame + Copyright (C) 2001 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 __AUDIOFRAME_H +#define __AUDIOFRAME_H + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef WORDS_BIGENDIAN +#define AUDIOFRAME_BIGENDIAN 1 +#else +#define AUDIOFRAME_BIGENDIAN 0 +#endif + + +#include "frame.h" +#include <kdemacros.h> +#define SCALFACTOR SHRT_MAX +#define MP3FRAMESIZE (2*2*2*32*18) + + +class KDE_EXPORT AudioFrame : public Frame { + + int stereo; + int frequencyHZ; + + public: + AudioFrame(); + virtual ~AudioFrame(); + + // info about "import" data + void setFrameFormat(int stereo,int freq); + + inline int getStereo() { return stereo; } + inline int getFrequenceHZ() { return frequencyHZ; } + + // these return values depend on the implementation + // how the data is stored internally after "import" + inline int getSampleSize() { return sampleSize; } + inline int getBigEndian() { return lBigEndian; } + inline int getSigned() { return lSigned; } + + // info about output + virtual int getLen(); + virtual void setLen(int len); + virtual int getSize(); + virtual void clearrawdata(); + + // data import + virtual void putFloatData(float* data,int len); + virtual void putFloatData(float* left,float* right,int len); + + + int isFormatEqual(AudioFrame* compare); + // Note: this can only be called with _real_ AudioFrame's as dest + void copyFormat(AudioFrame* dest); + + void print(const char* msg); + + protected: + int sampleSize; + int lBigEndian; + int lSigned; + +}; + + +#endif diff --git a/mpeglib/lib/frame/audioFrameQueue.cpp b/mpeglib/lib/frame/audioFrameQueue.cpp new file mode 100644 index 00000000..16488748 --- /dev/null +++ b/mpeglib/lib/frame/audioFrameQueue.cpp @@ -0,0 +1,339 @@ +/* + queues audio frames in an IOQueue, allows streaming from frames + Copyright (C) 2001 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 "audioFrameQueue.h" + +#define _FLOAT_2_TRANSFER 1 +#define _FLOAT_1_TRANSFER 2 +#define _INT_2_TRANSFER 3 +#define _INT_1_TRANSFER 4 +#define _FORWARD_TRANSFER 5 + +#include <iostream> + +using namespace std; + +AudioFrameQueue::AudioFrameQueue(int queueSize, + int frameSize, + int frameType):IOFrameQueue(queueSize) { + switch(frameType) { + case _FRAME_AUDIO_PCM: { + // fill queue with elements + while(emptyQueueCanWrite()) { + PCMFrame* pcmFrame=new PCMFrame(frameSize); + emptyQueueEnqueue(pcmFrame); + } + break; + } + case _FRAME_AUDIO_FLOAT: { + // fill queue with elements + while(emptyQueueCanWrite()) { + FloatFrame* floatFrame=new FloatFrame(frameSize); + emptyQueueEnqueue(floatFrame); + } + break; + } + default: + cout << "unknown frameType:"<<Frame::getFrameName(frameType) + <<" in AudioFrameQueue"<<endl; + exit(0); + } + len=0; + currentAudioFrame=new AudioFrame(); + currentRead=0; + this->frameType=frameType; +} + + +AudioFrameQueue::~AudioFrameQueue() { + delete currentAudioFrame; +} + + +void AudioFrameQueue::emptyQueueEnqueue(AudioFrame* frame) { + empty->enqueue(frame); +} + + +AudioFrame* AudioFrameQueue::emptyQueueDequeue() { + return (AudioFrame*)empty->dequeue(); +} + + +void AudioFrameQueue::dataQueueEnqueue(AudioFrame* frame) { + if (data->getFillgrade() == 0) { + frame->copyFormat(currentAudioFrame); + } + + len+=frame->getLen(); + data->enqueue(frame); + +} + + +AudioFrame* AudioFrameQueue::dataQueueDequeue() { + AudioFrame* back=(AudioFrame*)data->dequeue(); + currentRead=0; + len-=back->getLen(); + back->copyFormat(currentAudioFrame); + return back; +} + +AudioFrame* AudioFrameQueue::getCurrent() { + return currentAudioFrame; +} + + +int AudioFrameQueue::getLen() { + return len-currentRead; +} + + +int AudioFrameQueue::copy(float* left,float* right,int wantLen) { + if (frameType != _FRAME_AUDIO_FLOAT) { + cout << "AudioFrameQueue::copy class is frameType short int"<<endl; + exit(0); + } + // whats mux? + // well the routines are badly broken and need a rewrite + // mux deals with the problem that + // if the src is stereo we expect the left/right pointers + // to have half the size of wantlen*2 + // ridicouls complex? + // right, as I said, this needs a clean solution + int mux=1; + + if (currentAudioFrame->getStereo()) { + wantLen*=2; + mux=2; + } + + int back=copygeneric((char*)left,(char*)right, + wantLen,_FLOAT_2_TRANSFER,mux); + if (currentAudioFrame->getStereo()) back/=2; + + return back; +} + +int AudioFrameQueue::copy(short int* left,short int* right,int wantLen) { + if (frameType != _FRAME_AUDIO_PCM) { + cout << "AudioFrameQueue::copy class is frameType float"<<endl; + exit(0); + } + // for this mux ugly hack read above + int mux=1; + + if (currentAudioFrame->getStereo()) { + wantLen*=2; + mux=2; + } + int back=copygeneric((char*)left,(char*)right, + wantLen,_INT_2_TRANSFER,mux); + if (currentAudioFrame->getStereo()) back/=2; + + return back; +} + +int AudioFrameQueue::copy(short int* dest,int wantLen) { + if (frameType != _FRAME_AUDIO_PCM) { + cout << "AudioFrameQueue::copy class is frameType int single"<<endl; + exit(0); + } + int back=copygeneric((char*)dest,(char*)NULL, + wantLen,_INT_1_TRANSFER,1); + return back; +} + +int AudioFrameQueue::copy(float* dest,int wantLen) { + if (frameType != _FRAME_AUDIO_FLOAT) { + cout << "AudioFrameQueue::copy class is frameType float single"<<endl; + exit(0); + } + int back=copygeneric((char*)dest,(char*)NULL, + wantLen,_FLOAT_1_TRANSFER,1); + return back; +} + +void AudioFrameQueue::forwardStreamSingle(int forwardLen) { + int back=copygeneric((char*)NULL,(char*)NULL, + forwardLen,_FORWARD_TRANSFER,1); + if (back != forwardLen) { + cout << "error while forwarding stream"<<endl; + exit(0); + } +} + +void AudioFrameQueue::forwardStreamDouble(int forwardLen) { + + int mux=1; + + if (currentAudioFrame->getStereo()) { + forwardLen*=2; + } + int back=copygeneric((char*)NULL,(char*)NULL, + forwardLen,_FORWARD_TRANSFER,mux); + + if (back != forwardLen) { + cout << "error while forwarding stream"<<endl; + exit(0); + } +} + + +int AudioFrameQueue::copygeneric(char* left,char* right, + int wantLen,int version,int mux) { + + + int processed=currentRead; + + if (wantLen > (len-processed)) { + wantLen=len-processed; + } + int pos=0; + int doLen=wantLen; + while(doLen > 0) { + AudioFrame* current=(AudioFrame*)data->peekqueue(pos); + int totallen=current->getLen(); + int restlen=totallen-processed; + int copylen=doLen; + if (doLen > restlen) { + copylen=restlen; + } + doLen-=copylen; + + switch(version) { + case _FLOAT_2_TRANSFER: + transferFrame((float*)left, + (float*)right, + (FloatFrame*) current,processed,copylen); + left+=copylen/mux*(sizeof(float)); + right+=copylen/mux*(sizeof(float)); + break; + case _FLOAT_1_TRANSFER: + transferFrame((float*)left, + (FloatFrame*) current,processed,copylen); + left+=copylen*sizeof(short int); + break; + case _INT_2_TRANSFER: + transferFrame((short int*)left, + (short int*)right, + (PCMFrame*) current,processed,copylen); + left+=copylen/mux*(sizeof(short int)); + right+=copylen/mux*(sizeof(short int)); + break; + case _INT_1_TRANSFER: + transferFrame((short int*)left, + (PCMFrame*) current,processed,copylen); + left+=copylen*sizeof(short int); + break; + case _FORWARD_TRANSFER: + break; + default: + cout << "unknown transfer method AudioFrameQueue::copygeneric"<<endl; + exit(0); + } + processed+=copylen; + if ( processed == totallen) { + processed=0; + if (version == _FORWARD_TRANSFER) { + current=dataQueueDequeue(); + emptyQueueEnqueue(current); + } else { + pos++; + } + } + } + if (version == _FORWARD_TRANSFER) { + currentRead=processed; + } + if (doLen < 0) { + cout << "error while copy in AudioFrameQueue"<<endl; + exit(0); + } + return wantLen; +} + + +void AudioFrameQueue::transferFrame(float* left,float* right, + FloatFrame* current,int start,int len) { + float* ptr=current->getData()+start; + switch(currentAudioFrame->getStereo()) { + case true: + len=len/2; + while(len) { + *left++=*ptr++; + *right++=*ptr++; + len--; + } + break; + case false: + while(len) { + *left++=*ptr; + *right++=*ptr++; + len--; + } + break; + default: + cout << "bad stereo value AudioFrameQueue::transferFrame (float)"<<endl; + exit(0); + } +} + +void AudioFrameQueue::transferFrame(short int* left,short int* right, + PCMFrame* current,int start,int len) { + short int* ptr=current->getData()+start; + switch(currentAudioFrame->getStereo()) { + case true: + len=len/2; + while(len) { + *left++=*ptr++; + *right++=*ptr++; + len--; + } + break; + case false: + while(len) { + *left++=*ptr; + *right++=*ptr++; + len--; + } + break; + default: + cout << "bad stereo value AudioFrameQueue::transferFrame (int)"<<endl; + exit(0); + } +} + + +void AudioFrameQueue::transferFrame(short int* dest, + PCMFrame* current,int start,int len) { + short int* ptr=current->getData()+start; + memcpy(dest,ptr,len*sizeof(short int)); + +} + + +void AudioFrameQueue::transferFrame(float* dest, + FloatFrame* current,int start,int len) { + float* ptr=current->getData()+start; + memcpy(dest,ptr,len*sizeof(float)); + +} + + +void AudioFrameQueue::clear() { + while(dataQueueCanRead()) { + AudioFrame* current=dataQueueDequeue(); + emptyQueueEnqueue(current); + } +} diff --git a/mpeglib/lib/frame/audioFrameQueue.h b/mpeglib/lib/frame/audioFrameQueue.h new file mode 100644 index 00000000..7e7a01c0 --- /dev/null +++ b/mpeglib/lib/frame/audioFrameQueue.h @@ -0,0 +1,75 @@ +/* + queues audio frames in an IOQueue, allows streaming from frames + Copyright (C) 2001 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 __AUDIOFRAMEQUE_H +#define __AUDIOFRAMEQUE_H + +#include "IOFrameQueue.h" +#include "floatFrame.h" +#include "pcmFrame.h" + +#include <kdemacros.h> + +/** + This class solves the problem that we produce audioFrames + in a packet, but often we want that these packets looks + like a stream. + This class can convert from packets back to a stream. +*/ + +class KDE_EXPORT AudioFrameQueue : public IOFrameQueue { + + int frameType; + int len; + AudioFrame* currentAudioFrame; + int currentRead; + + public: + AudioFrameQueue(int queueSize,int frameSize,int frameType); + ~AudioFrameQueue(); + + void emptyQueueEnqueue(AudioFrame* frame); + AudioFrame* emptyQueueDequeue(); + + void dataQueueEnqueue(AudioFrame* frame); + AudioFrame* dataQueueDequeue(); + + // Meta info about stream + AudioFrame* getCurrent(); + + // Data info about "stream" (calculated from the packets) + int getLen(); + + // copy from packets to destination + int copy(float* left,float* right,int len); + int copy(short int* left,short int* right,int len); + void forwardStreamDouble(int len); + + int copy(short int* dest,int len); + int copy(float* dest,int len); + void forwardStreamSingle(int len); + + void clear(); + + private: + void transferFrame(float* left,float* right,FloatFrame*,int start,int len); + void transferFrame(short int* left,short int* right, + PCMFrame*,int start,int len); + void transferFrame(short int* dest, + PCMFrame*,int start,int len); + void transferFrame(float* dest, + FloatFrame*,int start,int len); + int copygeneric(char* left,char* right,int wantLen,int version,int mux); +}; +#endif diff --git a/mpeglib/lib/frame/floatFrame.cpp b/mpeglib/lib/frame/floatFrame.cpp new file mode 100644 index 00000000..5e17d1e1 --- /dev/null +++ b/mpeglib/lib/frame/floatFrame.cpp @@ -0,0 +1,50 @@ +/* + stores frames as floats. + Copyright (C) 2001 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 "floatFrame.h" + +#include <iostream> + +using namespace std; + +FloatFrame::FloatFrame(int size) { + data=new float[size]; + len=0; + this->size=size; + this->sampleSize=sizeof(float)*8; + this->lSigned=true; + this->lBigEndian=AUDIOFRAME_BIGENDIAN; + setFrameType(_FRAME_AUDIO_FLOAT); +} + + +FloatFrame::~FloatFrame() { + delete [] data; +} + + +void FloatFrame::putFloatData(float* in,int lenCopy) { + if ((len+lenCopy) > size) { + cout << "cannot copy putFloatData. Does not fit"<<endl; + exit(0); + } + memcpy(data+len,in,lenCopy*sizeof(float)); + len+=lenCopy; + + +} + + +void FloatFrame::putFloatData(float* left,float* right,int len) { + cout << "not yet implemented"<<endl; +} diff --git a/mpeglib/lib/frame/floatFrame.h b/mpeglib/lib/frame/floatFrame.h new file mode 100644 index 00000000..4d817021 --- /dev/null +++ b/mpeglib/lib/frame/floatFrame.h @@ -0,0 +1,46 @@ +/* + stores frames as floats. + Copyright (C) 2001 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 __FLOATFRAME_H +#define __FLOATFRAME_H + +#include "audioFrame.h" + +// this format has a sampleSize of sizeof(float), signed, endian==machine + +class FloatFrame : public AudioFrame { + + float* data; + int len; + int size; + + + public: + FloatFrame(int size); + ~FloatFrame(); + + int getLen() { return len; } + void setLen(int len) { this->len=len; } + int getSize() { return size; } + float* getData() { return data; } + + void putFloatData(float* data,int len); + void putFloatData(float* left,float* right,int len); + + void clearrawdata() { len=0; } + + + +}; +#endif diff --git a/mpeglib/lib/frame/frame.cpp b/mpeglib/lib/frame/frame.cpp new file mode 100644 index 00000000..c6a43969 --- /dev/null +++ b/mpeglib/lib/frame/frame.cpp @@ -0,0 +1,73 @@ +/* + base class for frames + Copyright (C) 2001 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 "frame.h" + + +Frame::Frame() { + type=_FRAME_UNK; +} + + +Frame::~Frame() { +} + + +const char* Frame::getMajorFrameName(int type) { + int majorID=type >> 12; + switch(majorID) { + case _FRAME_UNK: + return "_FRAME_UNK"; + case _FRAME_RAW: + return "_FRAME_RAW"; + case _FRAME_AUDIO: + return "_FRAME_AUDIO"; + case _FRAME_VIDEO: + return "_FRAME_VIDEO"; + case _FRAME_PAKET: + return "_FRAME_PAKET"; + default: + return "unknown major frameType"; + } + return "never happens Frame::getMajorFrameName"; +} + + + +const char* Frame::getFrameName(int type) { + switch(type) { + // Raw + case _FRAME_RAW_BASE: + return "_FRAME_RAW_BASE"; + case _FRAME_RAW_OGG: + return "_FRAME_RAW_OGG"; + + + // Audio + case _FRAME_AUDIO_BASE: + return "_FRAME_AUDIO_BASE"; + case _FRAME_AUDIO_PCM: + return "_FRAME_AUDIO_PCM"; + case _FRAME_AUDIO_FLOAT: + return "_FRAME_AUDIO_FLOAT"; + + + + // Rest + default: + return "cannot find name"; + } + return "never happens Frame::getFrameName"; +} + diff --git a/mpeglib/lib/frame/frame.h b/mpeglib/lib/frame/frame.h new file mode 100644 index 00000000..301b997c --- /dev/null +++ b/mpeglib/lib/frame/frame.h @@ -0,0 +1,101 @@ +/* + base class for frames + Copyright (C) 2001 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 __FRAME_H +#define __FRAME_H + + +#include <stdio.h> +#include <limits.h> +#include <stdlib.h> +#include <string.h> + + + +/** + The base class for frames. Every derived class from this class + must belong to some "major" class type and it must have an unique + id for itsself. Even if it is a base class it must have a unique id. + + How does this work. We have an int for the Frame id. In the int + itsself we but the majorid as well. + The Start codes are all multiple of 2 so for example + 0..127 belongs to FRAME UNK + 128..255 belongs to FRAME RAW + + So we can with a simple shift operation find out the major class +*/ +#define _FRAME_SHIFT 7 +#define _FRAME_ID_MAX 128 //(2^_FRAME_SHIFT) + + +// Major Frame classes +#define _FRAME_UNK 0 +#define _FRAME_RAW 1 +#define _FRAME_AUDIO 2 +#define _FRAME_VIDEO 3 +#define _FRAME_PAKET 4 + +// start ids of minor classes + +#define _FRAME_UNK_START (0) +#define _FRAME_RAW_START (_FRAME_ID_MAX) +#define _FRAME_AUDIO_START (_FRAME_ID_MAX*2) +#define _FRAME_VIDEO_START (_FRAME_ID_MAX*2*2) +#define _FRAME_PAKET_START (_FRAME_ID_MAX*2*2*2) + +// Minor Frame type IDs + + +// Raw +#define _FRAME_RAW_BASE (_FRAME_RAW_START+1) +#define _FRAME_RAW_OGG (_FRAME_RAW_START+2) +#define _FRAME_RAW_MPEG_I_VIDEO (_FRAME_RAW_START+3) +#define _FRAME_RAW_MPEG_SYSTEM (_FRAME_RAW_START+4) + + +// Audio: +#define _FRAME_AUDIO_BASE (_FRAME_AUDIO_START+1) +#define _FRAME_AUDIO_PCM (_FRAME_AUDIO_START+2) +#define _FRAME_AUDIO_FLOAT (_FRAME_AUDIO_START+3) + +// Video: +#define _FRAME_VIDEO_BASE (_FRAME_VIDEO_START+1) +#define _FRAME_VIDEO_YUV (_FRAME_VIDEO_START+2) +#define _FRAME_VIDEO_RGB_8 (_FRAME_VIDEO_START+3) +#define _FRAME_VIDEO_RGB_16 (_FRAME_VIDEO_START+4) +#define _FRAME_VIDEO_RGB_32 (_FRAME_VIDEO_START+5) + +// Packet: +#define _FRAME_PACKET_SYNC (_FRAME_PAKET_START+1) +#define _FRAME_PACKET_PACKET_CONTAINER (_FRAME_PAKET_START+2) + + + + +class Frame { + int type; + + public: + Frame(); + ~Frame(); + inline int getMajorFrameType() { return (type>>_FRAME_SHIFT);} + inline int getFrameType() { return type; } + inline void setFrameType(int type) { this->type=type; } + + + static const char* getMajorFrameName(int type); + static const char* getFrameName(int type); +}; +#endif diff --git a/mpeglib/lib/frame/frameQueue.cpp b/mpeglib/lib/frame/frameQueue.cpp new file mode 100644 index 00000000..fe524976 --- /dev/null +++ b/mpeglib/lib/frame/frameQueue.cpp @@ -0,0 +1,101 @@ +/* + queues frames + Copyright (C) 2001 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 "frameQueue.h" + +#include <iostream> + +using namespace std; + +FrameQueue::FrameQueue(int maxsize) { + this->size=maxsize; + entries = new Frame*[size]; + int i; + for(i=0;i<size;i++) { + entries[i]=NULL; + } + fillgrade=0; + writepos=0; + readpos=0; +} + + +FrameQueue::~FrameQueue() { + int i; + for(i=0;i<size;i++) { + if (entries[i] != NULL) { + delete entries[i]; + } + } + delete entries; +} + +int FrameQueue::canRead() { + return (fillgrade > 0); +} + + +int FrameQueue::canWrite() { + return (fillgrade < size); +} + + +int FrameQueue::getFillgrade() { + return fillgrade; +} + + +void FrameQueue::enqueue(Frame* frame) { + if(canWrite() == false) { + cout << "FrameQueue full cannot enqueue"<<endl; + exit(0); + } + fillgrade++; + entries[writepos]=frame; + writepos++; + if (writepos == size) { + writepos=0; + } +} + + +Frame* FrameQueue::dequeue() { + if(canRead() == false) { + cout << "FrameQueue empty cannot dequeue"<<endl; + exit(0); + } + Frame* back=entries[readpos]; + // invalide this frame, we do not longer own it! + entries[readpos]=NULL; + fillgrade--; + readpos++; + if (readpos == size) { + readpos=0; + } + return back; +} + +Frame* FrameQueue::peekqueue(int pos) { + if(fillgrade-pos <= 0) { + cout << "FrameQueue : cannot peek this positon"<<endl; + cout << "fillgrade:"<<fillgrade<<endl; + cout << "pos:"<<pos<<endl; + exit(0); + } + int getpos=(readpos+pos) % size; + + + Frame* back=entries[getpos]; + return back; +} + diff --git a/mpeglib/lib/frame/frameQueue.h b/mpeglib/lib/frame/frameQueue.h new file mode 100644 index 00000000..27747aa3 --- /dev/null +++ b/mpeglib/lib/frame/frameQueue.h @@ -0,0 +1,43 @@ +/* + queues frames + Copyright (C) 2001 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 __FRAMEQUEUE_H +#define __FRAMEQUEUE_H + +#include "frame.h" + +class FrameQueue { + + Frame** entries; + int fillgrade; + int size; + int writepos; + int readpos; + + + public: + FrameQueue(int maxsize); + ~FrameQueue(); + + int getFillgrade(); + int canRead(); + int canWrite(); + void enqueue(Frame* frame); + Frame* dequeue(); + Frame* peekqueue(int pos); + + +}; +#endif diff --git a/mpeglib/lib/frame/framer.cpp b/mpeglib/lib/frame/framer.cpp new file mode 100644 index 00000000..d380b2ec --- /dev/null +++ b/mpeglib/lib/frame/framer.cpp @@ -0,0 +1,241 @@ +/* + base class for converting raw data(stream) into some frametype. + Copyright (C) 2001 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 "framer.h" + + + +#define PROCESS_FIND 0 +#define PROCESS_READ 1 + +#include <iostream> + +using namespace std; + +Framer::Framer(int outsize) { + unsigned char* outptr=new unsigned char[outsize]; + init(outsize,outptr,true); +} + + +Framer::Framer(int outsize,unsigned char* outptr) { + if (outptr == NULL) { + cout << "Framer::Framer outptr NULL"<<endl; + exit(0); + } + if (outsize <= 0) { + cout << "Framer::Framer size <= 0"<<endl; + exit(0); + } + init(outsize,outptr,false); +} + + +void Framer::init(int outsize,unsigned char* outptr,int lDeleteOutPtr) { + buffer_data=outptr; + this->lDeleteOutPtr=lDeleteOutPtr; + input_info=new RawDataBuffer(NULL,0); + buffer_info=new RawDataBuffer(buffer_data,outsize); + lConstruct=true; + reset(); +} + + +Framer::~Framer() { + if (lDeleteOutPtr) { + delete[] buffer_data; + } + delete buffer_info; + delete input_info; +} + + +int Framer::canStore() { + return buffer_info->untilend(); +} + +int Framer::restBytes() { + return (input_info->size()-input_info->pos()); +} + + +void Framer::store(unsigned char* start,int bytes) { + if (buffer_info->pos()+bytes > buffer_info->size()) { + cout << "too much bytes inserted. cannot store that"<<endl; + exit(0); + } + if (main_state != FRAME_NEED) { + cout << "cannot store data, when not in MPEGAUDIOFRAME_NEED"<<endl; + exit(0); + } + input_info->set(start,bytes,0); + int fillgrade=input_info->untilend(); + if (fillgrade > 0) { + main_state=FRAME_WORK; + } +} + + +int Framer::work() { + if (main_state != FRAME_WORK) { + cout << "cannot find_frame, when not in MPEGAUDIOFRAME_WORK"<<endl; + exit(0); + } + if (lAutoNext) { + next(); + } + switch(process_state) { + case PROCESS_FIND: + if (find_frame(input_info,buffer_info) == true) { + setState(PROCESS_READ); + } + break; + case PROCESS_READ: + if (read_frame(input_info,buffer_info) == true) { + main_state=FRAME_HAS; + } + break; + default: + cout << "unknown process state in work. "<<endl; + printMainStates("printing states"); + exit(0); + } + // do not go to NEED if we have a frame and now the input is empty + if (main_state == FRAME_WORK) { + if (input_info->eof()) { + main_state=FRAME_NEED; + } + } + if (main_state == FRAME_HAS) return true; + return false; +} + + +void Framer::reset() { + unsync(buffer_info,true); + lAutoNext=false; + main_state=FRAME_NEED; + input_info->set(NULL,0,0); + buffer_info->setpos(0); + setState(PROCESS_FIND); +} + + +void Framer::next() { + unsync(buffer_info,false); + lAutoNext=false; + main_state=FRAME_WORK; + setState(PROCESS_FIND); +} + + +int Framer::getState() { + int back=main_state; + if (main_state == FRAME_HAS) { + // autonext when we devlivered one frame + lAutoNext=true; + main_state=FRAME_WORK; + setState(PROCESS_FIND); + } + if (lConstruct == true) { + lConstruct=false; + unsync(buffer_info,true); + } + return back; +} + + +void Framer::setState(int state) { + this->process_state=state; +} + + + +unsigned char* Framer::outdata() { + return buffer_info->ptr(); +} + + +unsigned char* Framer::indata() { + return buffer_info->current(); +} + +int Framer::len() { + return buffer_info->pos(); +} + + + +void Framer::printMainStates(const char* msg) { + cout << msg<<endl; + switch(main_state) { + case FRAME_NEED: + cout << "main_state: FRAME_NEED"<<endl; + break; + case FRAME_WORK: + cout << "main_state: FRAME_WORK"<<endl; + break; + case FRAME_HAS: + cout << "main_state: FRAME_HAS"<<endl; + break; + default: + cout << "unknown illegal main_state:"<<main_state<<endl; + } + + switch(process_state) { + case PROCESS_FIND: + cout << "process_state: PROCESS_FIND"<<endl; + break; + case PROCESS_READ: + cout << "process_state: PROCESS_READ"<<endl; + break; + default: + cout << "unknown illegal process_state:"<<process_state<<endl; + } + printPrivateStates(); + + +} + + + + +int Framer::find_frame(RawDataBuffer* ,RawDataBuffer* ) { + cout << "direct virtual call Framer::find_frame"<<endl; + return false; +} + + +int Framer::read_frame(RawDataBuffer* ,RawDataBuffer* ) { + cout << "direct virtual call Framer::read_frame"<<endl; + return false; +} + +void Framer::unsync(RawDataBuffer* ,int ) { + if (lConstruct == false) { + // invalidate header in buffer + cout << "direct virtual call Framer::unsync"<<endl; + } +} + + +void Framer::printPrivateStates() { + cout << "direct virtual call Framer::printPrivateStates"<<endl; +} + + +void Framer::setRemoteFrameBuffer(unsigned char* outptr,int size) { + + input_info->set(NULL,0,0); + buffer_info->set(outptr,size,0); +} diff --git a/mpeglib/lib/frame/framer.h b/mpeglib/lib/frame/framer.h new file mode 100644 index 00000000..51c4b26e --- /dev/null +++ b/mpeglib/lib/frame/framer.h @@ -0,0 +1,182 @@ +/* + base class for converting raw data(stream) into some frametype. + Copyright (C) 2001 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 __FRAMER_H +#define __FRAMER_H + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <kdemacros.h> + +#define FRAME_NEED 0 +#define FRAME_WORK 1 +#define FRAME_HAS 2 + + +#include "rawDataBuffer.h" + + +/** + If we want to have a "push" interface, this means the decoder + does not read from an input interface, we must be sure + that we have a valid mpeg audio frame, before we feed + this whole frame to the decoder. + + This class tells you how many bytes it can read and + gives you information wether we have a valid frame or not. + + This class has three public states: + + FRAME_NEED + / \ + / \ + / \ + FRAME_WORK <----------> FRAME_HAS + + + after the "FRAME_HAS" state we devliver _excatly_ one time + this state, and then automatically go to "FRAME_WORK" state. + + + You can reset() the class which empties the buffer and then + starts searching for a new sync code, or you can + do a next() which searches for the sync code, without + emptying the buffer (this is done automatically, + after the first call, when we was ins state "FRAME_HAS" + + Note: i) You need a reset() if a "seek" occurs in your stream + ii) First call to the class must be "getState" which does the + Post-Constructor setup in derived classes! + + The FRAME_NEED state is entered if the input buffer is empty + you then need to "push" data in this class. + The FRAME_NEED state is necessary to avoid an additonal memcpy + and a ringbuffer.(This safes "overhead"/"cpu cycles") +*/ + + + + +class KDE_EXPORT Framer { + + // this is our destination buffer for the output frame + // this buffer must be able to store the maximum size + // a frame of this type can have. + // Examples: + // avi-Chunk : 65KB + // mpeg audio: 4KB is always enough + // mpeg video: 224K (spec says this) + + // this can be a remote buffer or a local one + unsigned char* buffer_data; + RawDataBuffer* buffer_info; + + // state from FIND->READ->HAS + int process_state; + // state between NEED <-> PROCESS + int main_state; + + RawDataBuffer* input_info; + int lAutoNext; + + // stores if we have alloceated outdata or not + int lDeleteOutPtr; + // internal: unsync not done + int lConstruct; + + public: + // allocate local output buffer + Framer(int outsize); + + // outbuffer is remote. + Framer(int outsize,unsigned char* outptr); + + virtual ~Framer(); + + // + // process states (transitions) [START] + // + + // stores pointer to input and len + void store(unsigned char* start,int bytes); + int work(); + void reset(); + void next(); + // returns pointer to outbuffer (frameheader+data) + unsigned char* outdata(); + + // returns pointer to inbuffer (raw data) + // Note: this ptr is not fixed! It may vary from time to time + // Cannot be stores in a variable! + unsigned char* indata(); + + + // + // process states (transitions) [END] + // + + + // + // state helper functions [START] + // + int getState(); + // returns number of bytes. + int canStore(); + + // returns length of frame == len(frameheader+data) + int len(); + + // returns number of bytes still in input(needed for a/v sync) + int restBytes(); + // + // state helper functions [END] + // + + // debugging + void printMainStates(const char* msg); + + private: + void init(int outsize,unsigned char* outptr,int lDeleteOutptr); + + void setState(int state); + + // + // Overload functions for specialized framers [START] + // + + // return true, if frame header found + virtual int find_frame(RawDataBuffer* input,RawDataBuffer* store); + // return true, if frame data read. + virtual int read_frame(RawDataBuffer* input,RawDataBuffer* store); + // makes buffer invalid, reset to begin of "find_frame" + virtual void unsync(RawDataBuffer* store,int lReset); + // debugging + virtual void printPrivateStates(); + + // + // Overload functions for specialized framers [END] + // + + protected: + // this can be used, if the outptr come from a different framer + // (eg: OGG framer). You then need to call the construtor with + // some "dummy" size. + void setRemoteFrameBuffer(unsigned char* outptr,int size); + +}; + + +#endif diff --git a/mpeglib/lib/frame/pcmFrame.cpp b/mpeglib/lib/frame/pcmFrame.cpp new file mode 100644 index 00000000..24ab9792 --- /dev/null +++ b/mpeglib/lib/frame/pcmFrame.cpp @@ -0,0 +1,140 @@ +/* + pcm frame description. + Copyright (C) 2001 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 "pcmFrame.h" + +#include <iostream> + +using namespace std; + +#ifndef WORDS_BIGENDIAN +// this is fast on INTEL, but maybe not work on other little +// endian machines. (are there any?) +#define convMacro(in,dtemp,tmp) \ + in[0]*=SCALFACTOR; \ + dtemp = ((((65536.0 * 65536.0 * 16)+(65536.0 * 0.5))* 65536.0))+(in[0]); \ + tmp = ((*(int *)&dtemp) - 0x80000000); \ + in++; \ + if(tmp>32767) { \ + tmp=32767; \ + } else if (tmp<-32768) { \ + tmp =-0x8000; \ + } + +#else /* big endian conversion: _AIX */ +static inline void convMacro(float*& in, double dtemp, int& tmp) +{ + in[0]*=SCALFACTOR; + tmp = (int)*in; + in++; + if(tmp>32767) { + tmp=32767; + } else if (tmp<-32768) { + tmp =-0x8000; + } + tmp = ((tmp & 0xff) << 8) | ((tmp >> 8) & 0xff); +} +#endif /* _AIX */ + + +PCMFrame::PCMFrame(int size) { + data=new short int[size]; + len=0; + this->size=size; + // this format has a sampleSize of 16, signed, endian==machine + this->sampleSize=sizeof(short int)*8; + this->lSigned=true; + this->lBigEndian=AUDIOFRAME_BIGENDIAN; + setFrameType(_FRAME_AUDIO_PCM); +} + + +PCMFrame::~PCMFrame() { + delete [] data; +} + + +void PCMFrame::putFloatData(float* left,float* right,int copyLen) { + int destSize=0; + if (left != NULL) destSize++; + if (right != NULL) destSize++; + destSize*=copyLen; + if ((len+destSize) > size) { + cout << "cannot copy putFloatData L/R version . Does not fit"<<endl; + cout << "size:"<<size<<endl; + cout << "len:"<<len<<endl; + cout << "destSize:"<<destSize<<endl; + exit(0); + } + double dtemp; + int tmp; + int i=copyLen; + switch(getStereo()) { + case 1: + while(i > 0) { + convMacro(left,dtemp,tmp); + data[len++]=(short int)tmp; + convMacro(right,dtemp,tmp); + data[len++]=(short int)tmp; + i--; + } + break; + case 0: + if (left != NULL) { + int i=copyLen; + while(i > 0) { + convMacro(left,dtemp,tmp); + data[len++]=(short int)tmp; + i--; + // right channel empty + len++; + } + } + if (right != NULL) { + int i=copyLen; + len=len-destSize; + while(i > 0) { + // select right channel + len++; + convMacro(right,dtemp,tmp); + data[len++]=(short int)tmp; + i--; + // left channel already copied + } + } + break; + default: + cout << "unknown stereo value in pcmFrame"<<endl; + exit(0); + } +} + +void PCMFrame::putFloatData(float* in,int lenCopy) { + + if ((len+lenCopy) > size) { + cout << "cannot copy putFloatData. Does not fit"<<endl; + exit(0); + } + double dtemp; + int tmp; + while(lenCopy > 0) { + convMacro(in,dtemp,tmp); + data[len++]=(short int)tmp; + lenCopy--; + } + +} + + + diff --git a/mpeglib/lib/frame/pcmFrame.h b/mpeglib/lib/frame/pcmFrame.h new file mode 100644 index 00000000..a19941bc --- /dev/null +++ b/mpeglib/lib/frame/pcmFrame.h @@ -0,0 +1,45 @@ +/* + pcm frame description. + Copyright (C) 2001 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 __PCMFRAME_H +#define __PCMFRAME_H + + +#include "audioFrame.h" +#include <kdemacros.h> +// this format has a sampleSize of 16, signed, endian==machine + +class KDE_EXPORT PCMFrame : public AudioFrame { + + short int* data; + int len; + int size; + + public: + PCMFrame(int size); + ~PCMFrame(); + + int getLen() { return len; } + void setLen(int len) { this->len=len; } + int getSize() { return size; } + short int* getData() { return data; } + + void putFloatData(float* data,int len); + void putFloatData(float* left,float* right,int len); + + void clearrawdata() { len=0; } + + +}; +#endif diff --git a/mpeglib/lib/frame/rawDataBuffer.cpp b/mpeglib/lib/frame/rawDataBuffer.cpp new file mode 100644 index 00000000..f8635211 --- /dev/null +++ b/mpeglib/lib/frame/rawDataBuffer.cpp @@ -0,0 +1,21 @@ +/* + stores simple buffer information. does not allocate anything + Copyright (C) 2001 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 "rawDataBuffer.h" + +// hm + +RawDataBuffer::~RawDataBuffer() { +} + + diff --git a/mpeglib/lib/frame/rawDataBuffer.h b/mpeglib/lib/frame/rawDataBuffer.h new file mode 100644 index 00000000..755818ea --- /dev/null +++ b/mpeglib/lib/frame/rawDataBuffer.h @@ -0,0 +1,48 @@ +/* + stores simple buffer information. does not allocate anything + Copyright (C) 2001 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 __RAWDATABUFFER_H +#define __RAWDATABUFFER_H + + +class RawDataBuffer { + + int _size; + unsigned char* _ptr; + int _pos; + + public: + RawDataBuffer(unsigned char* ptr,int size) { set(ptr,size,0); } + ~RawDataBuffer(); + + + + unsigned char* ptr() { return _ptr; } + unsigned char* current() { return _ptr+_pos; } + int size() { return _size; } + int pos() { return _pos; } + int untilend() { return _size-_pos; } + int eof() { return _pos>=_size; } + + void inc() { this->_pos++; } + void inc(int val) { this->_pos+=val; } + void setpos(int val) { this->_pos=val; } + void setptr(unsigned char* ptr) { this->_ptr=ptr; } + void setsize(int size) { this->_size=size; } + + void set(unsigned char* ptr, + int size,int pos) { setpos(pos);setptr(ptr);setsize(size);} + +}; +#endif diff --git a/mpeglib/lib/frame/rawFrame.cpp b/mpeglib/lib/frame/rawFrame.cpp new file mode 100644 index 00000000..fbe662c5 --- /dev/null +++ b/mpeglib/lib/frame/rawFrame.cpp @@ -0,0 +1,90 @@ +/* + base class for raw frames (encoded data, where only the type is known) + Copyright (C) 2001 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 "rawFrame.h" + +#include <iostream> + +using namespace std; + +RawFrame::RawFrame(int size) { + init(_FRAME_RAW_BASE,size); +} + + +RawFrame::RawFrame(int type,int size) { + init(type,size); +} + + +RawFrame::~RawFrame() { + if (data != NULL) { + if (lRemoteData==false) { + delete data; + } + } +} + + +void RawFrame::print(const char* msg) { + cout << msg<<endl; + cout << "major Frametype:"<<Frame::getFrameName(getFrameType()); + cout << "size:"<<getSize(); + cout << "len:"<<getLen(); + +} + + +void RawFrame::init(int type,int size) { + + if (size < 0) { + cout << "size <= 0 in RawFrame::RawFrame"<<endl; + exit(-1); + } + setFrameType(type); + int majorType=getMajorFrameType(); + if (majorType != _FRAME_RAW) { + cout << "invalid Major Frametype:"<<Frame::getFrameName(getFrameType()) + << " for this class"<<endl; + printf("ID:0x%x dec:%d majorID:%d\n",type,type,majorType); + cout << "RawFrame::init"<<endl; + exit(-1); + } + if (size == 0) { + data=NULL; + this->size=0; + } + if (size > 0) { + data=new unsigned char[size]; + if (data != NULL) { + cout <<"malloc error RawFrame"<<endl; + exit(-1); + } + this->size=size; + } + setLen(0); + lRemoteData=false; +} + + +void RawFrame::setRemoteData(unsigned char* data,int size) { + if (this->data != NULL) { + if (lRemoteData==false) { + delete this->data; + } + } + lRemoteData=true; + this->data=data; + this->size=size; +} diff --git a/mpeglib/lib/frame/rawFrame.h b/mpeglib/lib/frame/rawFrame.h new file mode 100644 index 00000000..e1a05e9e --- /dev/null +++ b/mpeglib/lib/frame/rawFrame.h @@ -0,0 +1,75 @@ +/* + base class for raw frames (encoded data, where only the type is known) + Copyright (C) 2001 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 __RAW_FRAME_H +#define __RAW_FRAME_H + +#include "frame.h" + +/** + Raw frames represents bitstreams. They most likely have have now + real value for anyone but a decoder. + In general you simply allocate a rawFrame with a given size, This + size should make sure, that the bitstream packet does fit into + the frame. Sometime, in derived classes you can set thes pointer + to the allocated directly by calling the protected method: setRemoteData. +*/ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef WORDS_BIGENDIAN +#define RAWFRAME_BIGENDIAN 1 +#else +#define RAWFRAME_BIGENDIAN 0 +#endif + + +class RawFrame : public Frame { + + unsigned char* data; + int size; + int len; + int lRemoteData; + + public: + RawFrame(int size); + RawFrame(int type,int size); + ~RawFrame(); + + // access start of frameData + unsigned char* getData() { return data; } + + // current size in byte + int getLen() { return len; } + void setLen(int bytes) { this->len=bytes; } + + // maximum size of allocated memory + int getSize() { return size; } + + + void print(const char* msg); + + private: + void init(int type,int size); + + protected: + void setRemoteData(unsigned char* data,int size); +}; + + + +#endif diff --git a/mpeglib/lib/input/Makefile.am b/mpeglib/lib/input/Makefile.am new file mode 100644 index 00000000..f7e849eb --- /dev/null +++ b/mpeglib/lib/input/Makefile.am @@ -0,0 +1,37 @@ +# libinputplugin - Makefile.am + +EXTRA_DIST = cdromAccess_Linux.cpp cdromAccess_Empty.cpp \ + cdigrap.cpp README + +INCLUDES = $(all_includes) + +noinst_LTLIBRARIES = libinput.la + +noinst_HEADERS = cdromToc.h cdromRawAccess.h \ + simpleRingBuffer.h fileAccessWrapper.h + +kmpgincludedir = $(includedir)/$(THIS_LIB_NAME)/input + +kmpginclude_HEADERS = inputStream.h fileInputStream.h \ + inputPlugin.h \ + cdromInputStream.h bufferInputStream.h \ + inputDetector.h httpInputStream.h \ + threadSafeInputStream.h cddaInputStream.h + + + +libinput_la_SOURCES = inputStream.cpp fileInputStream.cpp \ + inputPlugin.cpp \ + cdromToc.cpp cdromRawAccess.cpp \ + cdromInputStream.cpp \ + bufferInputStream.cpp \ + simpleRingBuffer.cpp \ + cdromAccess.cpp inputDetector.cpp \ + httpInputStream.cpp \ + threadSafeInputStream.cpp \ + cddaInputStream.cpp \ + fileAccessWrapper.cpp + +# workaround for compile errors caused by linux/cdrom.h. +# Linux kernel headers suck donkeyballs. +KDE_CXXFLAGS = $(ENABLE_PERMISSIVE_FLAG) diff --git a/mpeglib/lib/input/README b/mpeglib/lib/input/README new file mode 100644 index 00000000..844a17bb --- /dev/null +++ b/mpeglib/lib/input/README @@ -0,0 +1,15 @@ + + +Here is the abstraction of the inputplugin. +Its a base class, with the usual open/seek/read methods. +The only nice thing is the factory inputPlugin which +creates you for a given url the correct class. + + +All inputStreams can take a timeStamp. Its necessary for +audio/video sync, but this must be supported +by the outputplugin and the playerPlugin! +Video is not that easy as audio :( + + + diff --git a/mpeglib/lib/input/bufferInputStream.cpp b/mpeglib/lib/input/bufferInputStream.cpp new file mode 100644 index 00000000..68e502ff --- /dev/null +++ b/mpeglib/lib/input/bufferInputStream.cpp @@ -0,0 +1,288 @@ +/* + reads input data + 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 "bufferInputStream.h" +#include "simpleRingBuffer.h" + + +BufferInputStream::BufferInputStream(int size,int minlinSize, + const char* name) { + ringBuffer=new SimpleRingBuffer(size,minlinSize); + leof=false; + bytePos=0; + fillgrade=0; + setUrl(name); + lLock=false; + abs_thread_mutex_init(&writeInMut); +} + + +BufferInputStream::~BufferInputStream() { + delete ringBuffer; + abs_thread_mutex_destroy(&writeInMut); +} + + +int BufferInputStream::open(const char*) { + leof=false; + setBlocking(true); + return true; +} + +void BufferInputStream::close() { + leof=true; + setBlocking(false); +} + +int BufferInputStream::eof() { + return (leof && (fillgrade==0)); +} + +int BufferInputStream::isOpen() { + return !leof; +} + +void BufferInputStream::setBlocking(int lblock) { + ringBuffer->setCanWaitForSpace(lblock); + ringBuffer->setCanWaitForData(lblock); +} + +int BufferInputStream::getHold() { + return lLock; +} + + +void BufferInputStream::setHold(int lLock) { + if (lLock) { + lockBuffer(); + } else { + unlockBuffer(); + } + this->lLock=lLock; +} + +int BufferInputStream::read(char* ptr,int size) { + int i=0; + int n=size; + int canCopy=n; + char* readPtr; + // here we read even if leof is true + // we make sure that we empty the whole buffer! + while((eof()==false) && (n > 0)) { + canCopy=n; + ringBuffer->getReadArea(readPtr,canCopy); + if (canCopy <= 0){ + ringBuffer->waitForData(1); + continue; + } + if (n < canCopy) { + canCopy=n; + } + memcpy((char*)ptr+i,readPtr,canCopy); + i=i+canCopy; + n=n-canCopy; + ringBuffer->forwardReadPtr(canCopy); + ringBuffer->forwardLockPtr(canCopy); + lockBuffer(); + bytePos+=canCopy; + fillgrade-=canCopy; + unlockBuffer(); + } + return i; +} + + +int BufferInputStream::write(char* ptr,int len,TimeStamp* stamp) { + int i=0; + int n=len; + int canWrite=n; + char* writePtr; + + 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)) { + canWrite=n; + ringBuffer->getWriteArea(writePtr,canWrite); + if (canWrite <= 0){ + ringBuffer->waitForSpace(1); + continue; + } + if (canWrite > n) { + canWrite=n; + } + memcpy(writePtr,(char*)ptr+i,canWrite); + i=i+canWrite; + n=n-canWrite; + ringBuffer->forwardWritePtr(canWrite); + lockBuffer(); + fillgrade+=canWrite; + unlockBuffer(); + } + + return i; +} + + + +int BufferInputStream::write(InputStream* input,int len,TimeStamp* stamp) { + int i=0; + int n=len; + int canWrite=n; + int didWrite; + char* writePtr; + + 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)) { + canWrite=n; + ringBuffer->getWriteArea(writePtr,canWrite); + if (canWrite <= 0){ + ringBuffer->waitForSpace(1); + continue; + } + if (canWrite > n) { + canWrite=n; + } + didWrite=input->read(writePtr,canWrite); + if (input->eof()) break; + i=i+didWrite; + n=n-didWrite; + ringBuffer->forwardWritePtr(didWrite); + lockBuffer(); + fillgrade+=canWrite; + unlockBuffer(); + } + + return i; +} + + + +long BufferInputStream::getByteLength() { + return ringBuffer->getFillgrade(); +} + +int BufferInputStream::getFillgrade() { + return ringBuffer->getFillgrade(); +} + + +int BufferInputStream::getFreeRead() { + return ringBuffer->getFreeRead(); +} + + +int BufferInputStream::getFreeSpace() { + return ringBuffer->getFreeWrite(); +} + + + +long BufferInputStream::getBytePosition() { + return bytePos; +} + +void BufferInputStream::setBytePosition(long bytePos) { + this->bytePos=bytePos; +} + + +int BufferInputStream::seek(long) { + return false; +} + + +void BufferInputStream::clear() { + + ringBuffer->emptyBuffer(); + ringBuffer->exitWaitForData(); + ringBuffer->exitWaitForSpace(); + timeStampArray->clear(); + + lockBuffer(); + bytePos=0; + fillgrade=0; + unlockBuffer(); + +} + + + + +// remote read extension +int BufferInputStream::readRemote(char** ptr,int size) { + int n=0; + char* readPtr; + while((eof()==false)) { + n=size; + ringBuffer->getReadArea(readPtr,n); + if (n < size){ + ringBuffer->waitForData(size); + if (ringBuffer->getCanWaitForData()==false) { + break; + } + continue; + } + break; + } + *ptr=readPtr; + return n; +} + + +void BufferInputStream::forwardReadPtr(int bytes) { + + ringBuffer->forwardReadPtr(bytes); + ringBuffer->forwardLockPtr(bytes); + lockBuffer(); + bytePos+=bytes; + fillgrade-=bytes; + unlockBuffer(); + getTimeStamp(bytePos); +} + + +void BufferInputStream::setCanWaitForData(int lBlock) { + ringBuffer->setCanWaitForData(lBlock); +} + + +void BufferInputStream::lockBuffer() { + abs_thread_mutex_lock(&writeInMut); +} + + +void BufferInputStream::unlockBuffer() { + abs_thread_mutex_unlock(&writeInMut); +} + + +int BufferInputStream::getSize() { + return ringBuffer->getSize(); +} + + diff --git a/mpeglib/lib/input/bufferInputStream.h b/mpeglib/lib/input/bufferInputStream.h new file mode 100644 index 00000000..3bd3e691 --- /dev/null +++ b/mpeglib/lib/input/bufferInputStream.h @@ -0,0 +1,88 @@ +/* + reads input data + 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 __BUFFERINPUTSTREAM_H +#define __BUFFERINPUTSTREAM_H + +#include "../util/abstract/abs_thread.h" + +#include "inputStream.h" + + +class SimpleRingBuffer; + +class BufferInputStream : public InputStream { + + SimpleRingBuffer* ringBuffer; + int leof; + long bytePos; + int fillgrade; + int lLock; + abs_thread_mutex_t writeInMut; + + public: + BufferInputStream(int size,int minlinSize,const char* name); + ~BufferInputStream(); + + int open(const char* name); + void close(); + + int isOpen(); + + + int eof(); + void setBlocking(int lblock); + int read(char* ptr,int size); + + // reads from a buffer + int write(char* ptr,int len,TimeStamp* stamp); + + // this method directy read from another inputstream (faster); + int write(InputStream* ptr,int len,TimeStamp* stamp); + + int seek(long bytePos); + + + long getByteLength(); + long getBytePosition(); + + void setBytePosition(long bytePos); + int getFillgrade(); + int getSize(); + int getFreeRead(); + int getFreeSpace(); + + void clear(); + + // remote read extension + // Note you _need_ to call always both methods + // readRemote and forwardReadPtr even if bytes==0!!! + // (we hold a resizeLock during this operation) + int readRemote(char** ptr,int size); + void forwardReadPtr(int bytes); + void setCanWaitForData(int lBlock); + + + // this method is only safe to call by the writer in the buffer + // a reader never should call this (segfault possible) + void resizeBuffer(int changeSize); + + // for pause/play over loopback + int getHold(); + void setHold(int lLock); + + private: + void lockBuffer(); + void unlockBuffer(); + +}; +#endif diff --git a/mpeglib/lib/input/cddaInputStream.cpp b/mpeglib/lib/input/cddaInputStream.cpp new file mode 100644 index 00000000..9bc8f5f2 --- /dev/null +++ b/mpeglib/lib/input/cddaInputStream.cpp @@ -0,0 +1,225 @@ +/* + cdda input class based on cdparanoia + 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 + + */ + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef CDDA_PARANOIA + +#include <iostream> + +using namespace std; + +#include "cddaInputStream.h" +#include "inputDetector.h" + + +void paranoiaCallback(long, int) { + //cout << "long:"<<a<<" int:"<<b<<endl; +} + +CDDAInputStream::CDDAInputStream() { + drive = NULL; + paranoia=NULL; + device=NULL; + track=1; +} + + +CDDAInputStream::~CDDAInputStream() { + close(); +} + +// here we should encdoe the track Nr. as well +// eg: /dev/cdrom#1 +int CDDAInputStream::getTrackAndDevice(const char* url) { + int matches=0; + // dest = "cdda:/dev/cdrom/track01.cda" + char* noprotoString=InputDetector::removeProtocol(url); + // noprotoString="/dev/cdrom/track01.cda" + char* filename=InputDetector::getFilename(noprotoString); + // filename="track01.cda" + char* filenameNoExt=InputDetector::getWithoutExtension(filename); + // filenameNoExt="track01" + char* dir=InputDetector::removeExtension(noprotoString,filename); + // dir="/dev/cdrom/" + device=InputDetector::removeSlash(dir); + track=1; + if (filenameNoExt != NULL) { + matches=sscanf(filenameNoExt,"track%02d",&track); + } + if (matches == 0) { + cout << "no trackNumber found using default"<<endl; + } + cout << "device:"<<device<<" track:"<<track<<endl; + + if (noprotoString != NULL) { + delete noprotoString; + } + if (filename != NULL) { + delete filename; + } + if (filenameNoExt != NULL) { + delete filenameNoExt; + } + if (dir != NULL) { + delete dir; + } + if (device == NULL) { + cout << "no device found, using any"<<endl; + return false; + } + return true; +} + +int CDDAInputStream::open(const char* dest) { + if (getTrackAndDevice(dest) == true) { + drive = cdda_identify(device, CDDA_MESSAGE_PRINTIT, 0); + } + + if (drive == NULL) { + cout << "cdda_identify failed trying to find a device"<<endl; + drive=cdda_find_a_cdrom(CDDA_MESSAGE_PRINTIT, 0); + } + if (drive == NULL) { + cout << "nope. nothing found. give up"<<endl; + return false; + } + cout << "cdda_open -s"<<endl; + if (cdda_open(drive) != 0) { + cout << "cdda_open(drive) failed"<<endl; + close(); + return false; + } + cout << "cdda_open -e"<<endl; + + // debug things a bit + int trackCount = drive->tracks; + for (int i = 1; i <= trackCount; i++) { + if (IS_AUDIO(drive, i)) { + printf("track%02d.cda\n", i); + } else { + printf("no audio:%d\n",i); + } + } + + paranoia = paranoia_init(drive); + if (paranoia == NULL) { + cout << "paranoia init failed"<<endl; + close(); + return false; + } + + firstSector=cdda_track_firstsector(drive, track); + lastSector=cdda_track_lastsector(drive, track); + currentSector=firstSector; + // paranoia && drive != NULL -> initialized! + + int paranoiaLevel = PARANOIA_MODE_FULL ^ PARANOIA_MODE_NEVERSKIP; + paranoia_modeset(paranoia, paranoiaLevel); + cdda_verbose_set(drive, CDDA_MESSAGE_PRINTIT, CDDA_MESSAGE_PRINTIT); + paranoia_seek(paranoia, firstSector, SEEK_SET); + + return true; +} + + +void CDDAInputStream::close() { + if (isOpen() == false) { + return; + } + cdda_close(drive); + drive=NULL; + if (paranoia != NULL) { + paranoia_free(paranoia); + paranoia = 0; + } + if (device != NULL) { + delete device; + device=NULL; + } +} + + +int CDDAInputStream::isOpen() { + return (drive != NULL); +} + + +int CDDAInputStream::eof() { + if (isOpen()==false) { + return true; + } + if (currentSector >= lastSector) { + return true; + } + return false; +} + + +int CDDAInputStream::read(char* dest,int len) { + if (len != 2*CD_FRAMESIZE_RAW) { + cout << "len must be 2*CD_FRAMESIZE_RAW"<<endl; + exit(0); + } + int16_t * buf = paranoia_read(paranoia, paranoiaCallback); + currentSector++; + if (buf == NULL) { + cout << "paranoia_read failed"<<endl; + close(); + return 0; + } + memcpy(dest,buf,sizeof(int16_t)*CD_FRAMESIZE_RAW); + return CD_FRAMESIZE_RAW; +} + + +int CDDAInputStream::seek(long bytePos) { + int byteLength=getByteLength(); + float ratio=(float)bytePos/(float)(byteLength+1); + float wantSector=ratio*(float)((lastSector-firstSector)); + if (isOpen()) { + currentSector=(int)wantSector; + cout << "paranoia_seek:"<<currentSector<<endl; + paranoia_seek(paranoia, currentSector, SEEK_SET); + } + return true; +} + +void CDDAInputStream::clear() { + cout << "direct virtual call CDDAInputStream::clear:"<<endl; +} + + +long CDDAInputStream::getByteLength() { + int sectors=lastSector-firstSector; + int bytes=sectors*CD_FRAMESIZE_RAW*sizeof(int16_t); + cout << "getByteLength:"<<bytes<<endl; + return bytes; +} + + +long CDDAInputStream::getBytePosition() { + int readSectors=currentSector-firstSector; + int bytes=readSectors*CD_FRAMESIZE_RAW*sizeof(int16_t); + return bytes; +} + +#endif +//CDDA_PARANOIA + + + + + diff --git a/mpeglib/lib/input/cddaInputStream.h b/mpeglib/lib/input/cddaInputStream.h new file mode 100644 index 00000000..55989c65 --- /dev/null +++ b/mpeglib/lib/input/cddaInputStream.h @@ -0,0 +1,85 @@ +/* + cdda input class based on cdparanoia + 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 __CDDAINPUTSTREAM_H +#define __CDDAINPUTSTREAM_H + + +#include "inputStream.h" + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifndef CDDA_PARANOIA +class CDDAInputStream : public InputStream { +}; +#else + +#include <sys/types.h> +typedef int16_t size16; +typedef int32_t size32; + +extern "C" { +#include <cdda_interface.h> +#include <cdda_paranoia.h> +void paranoiaCallback(long, int); +} +//#define CDDA_INCLUDE + + +class CDDAInputStream : public InputStream { + +//#ifdef CDDA_INCLUDE + cdrom_paranoia * paranoia; + struct cdrom_drive * drive; +//#else +// void * drive; +// void * paranoia; +//#endif + + + char* device; + int track; + + int firstSector; + int lastSector; + int currentSector; + + public: + CDDAInputStream(); + ~CDDAInputStream(); + + int open(const char* dest); + void close(); + int isOpen(); + + int eof(); + int read(char* ptr,int size); + int seek(long bytePos); + // clears possible input buffers + // (called by the decoderPlugin after a resyncCommit) + void clear(); + + long getByteLength(); + long getBytePosition(); + private: + int getTrackAndDevice(const char* url); + +}; +#endif +//CDDA_PARANOIA + +#endif diff --git a/mpeglib/lib/input/cdigrap.cpp b/mpeglib/lib/input/cdigrap.cpp new file mode 100644 index 00000000..37d9de0e --- /dev/null +++ b/mpeglib/lib/input/cdigrap.cpp @@ -0,0 +1,100 @@ +/** + graps cdis + + Compile with + + g++ -o cdigrap cdigrap.cpp -lmpeg + +*/ +#ifdef CONFIG_H +#include "config.h" +#endif +#include "inputPlugin.h" + +#if defined(HAVE_GETOPT_H) +#include <getopt.h> +#endif + +void usage() { + cout << "cdigrab grabs video cds"<<endl; + cout << "Usage : cdigrab [s:b:f:h] cdi:/device"<<endl; + cout << endl; + cout << "-s : bytes start a positions <bytes>"<<endl; + cout << "-b : set block size (default: 32768)"<<endl; + cout << "-f : set filename (default: a.cdi)"<<endl; + cout << "-h : help"<<endl; + cout << "THIS SOFTWARE COMES WITH ABSOLUTELY NO WARRANTY! " \ + << "USE AT YOUR OWN RISK!"<<endl; + cout << endl; +} + + +int main(int argn,char** args) { + + + if (argn <= 1) { + usage(); + exit(0); + } + long startBytes=0; + int len=32768; + char *fname = strdup("a.cdi"); + int c; + + while(1) { + c = getopt (argn, args, "s:b:f:h"); + if (c == -1) break; + switch(c) { + case 'h': { + usage(); + exit(0); + } + case 's': { + startBytes=atoi(optarg); + break; + } + case 'b': { + len=atoi(optarg); + break; + } + case 'f': { + fname = strdup(optarg); + break; + } + default: + printf ("?? getopt returned character code 0%o ??\n", c); + usage(); + exit(-1); + } + } + if (optind >= argn ) { + usage(); + exit(-1); + } + + InputStream* in=InputPlugin::createInputStream(args[optind]); + + in->open(args[optind]); + + if (startBytes != 0) { + cout << "seeking to :"<<startBytes<<endl; + in->seek(startBytes); + } + char* buffer=new char[len]; + int cnt=0; + FILE* f=fopen(fname,"a+"); + while(1) { + if (in->eof() == true) { + cout << "******* plugin->getStreamState() EOF"<<endl; + break; + } + in->read(buffer,len); + fwrite(buffer,len,1,f); + cnt++; + cout << "grapped:"<<cnt*len<<endl; + } + fclose(f); +} + + + diff --git a/mpeglib/lib/input/cdromAccess.cpp b/mpeglib/lib/input/cdromAccess.cpp new file mode 100644 index 00000000..98d49779 --- /dev/null +++ b/mpeglib/lib/input/cdromAccess.cpp @@ -0,0 +1,54 @@ +/* + * system dependent wrapper for access to cdrom + * 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 + * + * $Id$ + * + */ + +#ifdef HAVE_CONFIG_H + #include <config.h> +#endif + + + +#ifdef OS_AIX + #include "cdromAccess_Empty.cpp" +#endif + +#ifdef OS_Linux + #include <sys/types.h> + #include "cdromAccess_Linux.cpp" +#endif + +#ifdef OS_BSD + #include "cdromAccess_Empty.cpp" +#endif + +#if defined(OS_IRIX) || defined(OS_IRIX64) + #include "cdromAccess_Empty.cpp" +#endif + +#ifdef OS_HPUX + #include "cdromAccess_Empty.cpp" +#endif + +#ifdef OS_SunOS + #include "cdromAccess_Empty.cpp" +#endif + +#ifdef __BEOS__ + #include "cdromAccess_Empty.cpp" +#endif + +#ifdef WIN32 + #include "cdromAccess_Empty.cpp" +#endif + + diff --git a/mpeglib/lib/input/cdromAccess_Empty.cpp b/mpeglib/lib/input/cdromAccess_Empty.cpp new file mode 100644 index 00000000..63da4b69 --- /dev/null +++ b/mpeglib/lib/input/cdromAccess_Empty.cpp @@ -0,0 +1,47 @@ +/* + system dependent wrapper for access to cdrom (no system) + 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 "cdromToc.h" +#include "cdromRawAccess.h" + +#include <iostream> +using namespace std; + + +int CDRomToc::getStartEnd(FILE* file,int& startToc,int& endToc) { + cout << "CDRomToc::getStartEnd not implemented on your system"<<endl; + return false; +} + + +int CDRomToc::readToc(FILE* file,int num,int& min,int& sec, int& frame) { + cout << "CDRomToc::readToc not implemented on your system"<<endl; + return false; +} + + +int CDRomToc::readLeadOut(FILE* file,int& min,int& sec, int& frame) { + cout << "CDRomToc::reatLeadOut not implemented on your system"<<endl; + return false; +} + + + +int CDRomRawAccess::readDirect(int minute,int second, int frame) { + + + cout << "no CDRomRawAccess::read implemented for your system"<<endl; + lData=false; + return true; +} + diff --git a/mpeglib/lib/input/cdromAccess_Linux.cpp b/mpeglib/lib/input/cdromAccess_Linux.cpp new file mode 100644 index 00000000..a3bde622 --- /dev/null +++ b/mpeglib/lib/input/cdromAccess_Linux.cpp @@ -0,0 +1,124 @@ +/* + system dependent wrapper for access to cdrom (Linux) + 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 + + */ + +#ifdef __STRICT_ANSI__ +#undef __STRICT_ANSI__ +#define _ANSI_WAS_HERE_ +#endif +#include <linux/types.h> +#include <linux/cdrom.h> +#ifdef _ANSI_WAS_HERE_ +#define __STRICT_ANSI__ +#endif +#include <sys/ioctl.h> + +#include "cdromToc.h" +#include "cdromRawAccess.h" + +#include <iostream> + +using namespace std; + +/** + here you find an example how to port the access method + to your system. +*/ + + +int CDRomToc::getStartEnd(FILE* file,int& startToc,int& endToc) { + struct cdrom_tochdr tochdr; + int fd=fileno(file); + if (ioctl(fd, CDROMREADTOCHDR, &tochdr) == -1) { + perror("ioctl cdromreadtochdr"); + return false; + } + + startToc=tochdr.cdth_trk0; + endToc=tochdr.cdth_trk1; + return true; +} + + +int CDRomToc::readToc(FILE* file,int num,int& min,int& sec, int& frame) { + struct cdrom_tocentry tocent; + int fd=fileno(file); + tocent.cdte_track = num; + tocent.cdte_format = CDROM_MSF; + if (ioctl(fd, CDROMREADTOCENTRY, &tocent) == -1 ) { + perror("ioctl cdromreadtocentry"); + return false; + } + min=tocent.cdte_addr.msf.minute; + sec=tocent.cdte_addr.msf.second; + frame=tocent.cdte_addr.msf.frame; + return true; +} + + +int CDRomToc::readLeadOut(FILE* file,int& min,int& sec, int& frame) { + struct cdrom_tocentry tocent; + int fd=fileno(file); + tocent.cdte_track = CDROM_LEADOUT; + tocent.cdte_format = CDROM_MSF; + if (ioctl(fd, CDROMREADTOCENTRY, &tocent) == -1 ) { + perror("ioctl cdromreadLeadoutn"); + return false; + } + min=tocent.cdte_addr.msf.minute; + sec=tocent.cdte_addr.msf.second; + frame=tocent.cdte_addr.msf.frame; + return true; +} + + + +int CDRomRawAccess::readDirect(int minute,int second, int frame) { + + // this comes from smpeg + // smpeg is an mpeg I player from lokigames www.lokigames.com + + struct cdrom_msf *msf; + int fd=fileno(cdfile); + + msf = (struct cdrom_msf*) data; + msf->cdmsf_min0 = minute; + msf->cdmsf_sec0 = second; + msf->cdmsf_frame0 = frame; + if (ioctl(fd, CDROMREADMODE2, msf) == -1) { + perror("ioctl cdromreadmode2"); + cout << "min:"<<minute + << " sec:"<<second + << " frame:"<<frame<<endl; + return false; + } else { + //cout << "read success ****************"<<endl; + } + + char* subheader=data+sizeof(int); + + + if ((subheader[1]==1) && + (((subheader[2]==0x62) && + (subheader[3]==0x0f)) || ((subheader[2]==0x64) && + (subheader[3]==0x7f)))) { + lData=true; + dataStart=sizeof(int)+4; + } else { + lData=false; + } + + len=2324; + + + return true; +} + diff --git a/mpeglib/lib/input/cdromInputStream.cpp b/mpeglib/lib/input/cdromInputStream.cpp new file mode 100644 index 00000000..1cf3f905 --- /dev/null +++ b/mpeglib/lib/input/cdromInputStream.cpp @@ -0,0 +1,309 @@ +/* + reads input data from cdrom + 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 "cdromInputStream.h" +#include "cdromRawAccess.h" +#include "cdromToc.h" +#include <string.h> +#include "inputDetector.h" + +#include <iostream> + +using namespace std; + +CDRomInputStream::CDRomInputStream() { + cdRomToc=new CDRomToc(); + cdRomRawAccess=new CDRomRawAccess(cdRomToc); + + buflen=0; + bufCurrent=NULL; + + currentMinute=0; + currentSecond=2; + currentFrame=0; + byteCounter=0; +} + + +CDRomInputStream::~CDRomInputStream() { + delete cdRomRawAccess; + delete cdRomToc; +} + + +int CDRomInputStream::readCurrent() { + int ok=cdRomRawAccess->read(currentMinute,currentSecond,currentFrame); + if (ok==false) { + if (cdRomRawAccess->eof() == false) { + int pos=cdRomToc->getNextTocEntryPos(currentMinute, + currentSecond, + currentFrame); + + // now try to read a few sectors + int cnt=0; + int back=false; + + while(1) { + // jump forward + int i; + for(i=0;i<_CDROM_FRAMES-currentFrame;i++) { + next_sector(); + } + cout << "trying next ..."<<endl; + ok=cdRomRawAccess->read(currentMinute,currentSecond,currentFrame); + if (ok) { + bufCurrent=cdRomRawAccess->getBufferStart(); + buflen=cdRomRawAccess->getBufferLen(); + return true; + } + cnt++; + if (cnt > 100) { + break; + } + } + cout << "last possible jump"<<endl; + if (pos > 1) { + TocEntry* tocEntry=cdRomToc->getTocEntry(pos-1); + currentMinute=tocEntry->minute; + currentSecond=tocEntry->second; + currentFrame=tocEntry->frame; + back=cdRomRawAccess->read(currentMinute,currentSecond,currentFrame); + if (back) { + bufCurrent=cdRomRawAccess->getBufferStart(); + buflen=cdRomRawAccess->getBufferLen(); + } + } + return back; + } + return false; + } + bufCurrent=cdRomRawAccess->getBufferStart(); + buflen=cdRomRawAccess->getBufferLen(); + return true; +} + + +int CDRomInputStream::getByteDirect() { + int back; + if (buflen==0) { + fillBuffer(); + } + if (buflen==0){ + return EOF; + } + back=*bufCurrent; + buflen--; + bufCurrent++; + byteCounter++; + return back; +} + + +int CDRomInputStream::read(char* ptr,int size) { + char* dest=(char*)ptr; + int bytesRead=0; + int doRead=size; + int canRead; + + while(eof() == false) { + if (buflen == 0) { + if (fillBuffer() == false) { + return 0; + } + continue; + } + canRead=buflen; + if (doRead < canRead) { + canRead=doRead; + } + memcpy((void*)dest,(void*)bufCurrent,canRead); + buflen-=canRead; + bufCurrent+=canRead; + bytesRead+=canRead; + dest+=canRead; + doRead-=canRead; + if (doRead == 0) { + byteCounter+=bytesRead; + return bytesRead; + } + } + return 0; +} + +int CDRomInputStream::eof() { + return cdRomRawAccess->eof(); +} + + + + +long CDRomInputStream::getBytePosition() { + return byteCounter; +} + + +void CDRomInputStream::print() { +} + + +void CDRomInputStream::next_sector() { + currentFrame++; + if (currentFrame>=_CDROM_FRAMES) { + currentFrame = 0; + currentSecond++; + if (currentSecond>=_CDROM_SECS) { + currentSecond = 0; + currentMinute++; + } + } +} + +int CDRomInputStream::open(const char* file) { + cout << "CDRomInputStream::open:"<<file<<endl; + char* noExtension=InputDetector::getWithoutExtension(file); + cout << "CDRomInputStream::noExt:"<<noExtension<<endl; + if (noExtension == NULL) { + return false; + } + cdRomToc->open(noExtension); + cdRomRawAccess->open(noExtension); + if (isOpen()==false) { + return false; + } + setUrl(noExtension); + int entries=cdRomToc->getTocEntries(); + cdRomToc->print(); + if (entries == 1) { + cerr << "only lead out"<<endl; + } + + // cdRomRawAccess->insertTocEntry(0,2,0); + //cdRomToc->insertTocEntry(1,13,5); + + TocEntry* tocEntry=cdRomToc->getTocEntry(0); + currentMinute=tocEntry->minute; + currentSecond=tocEntry->second; + currentFrame=tocEntry->frame; + delete noExtension; + + return readCurrent(); +} + + +void CDRomInputStream::close() { + cdRomRawAccess->close(); + byteCounter=0; + setUrl(NULL); +} + + +int CDRomInputStream::isOpen() { + return cdRomRawAccess->isOpen(); +} + + + + +long CDRomInputStream::getBytePos(int min,int sec) { + long back; + // 2324 is the size of a cdfram + back=sec*_CDROM_FRAMES*2324; + back=back+min*60*_CDROM_FRAMES*2324; + cout << "CDRomInputStream::getByteLength"<<back<<endl; + return back; +} + +long CDRomInputStream::getByteLength() { + // we get the length out of the toc and then multiply like hell + long totalSecs=cdRomToc->getEndSecond(); + long min=totalSecs/60; + long sec=totalSecs-60*min; + + long back=getBytePos(min,sec); + + return back; +} + + +int CDRomInputStream::seek(long posInBytes) { + int entries=cdRomToc->getTocEntries(); + + TocEntry* firstEntry; + if (entries == 0) { + return false; + } + if (posInBytes < 0) { + return false; + } + firstEntry=cdRomToc->getTocEntry(0); + + long startByte=getBytePos(firstEntry->minute,firstEntry->second+1); + + posInBytes=posInBytes+startByte; + + + float fmin=(float)posInBytes/(float)(60*_CDROM_FRAMES*2324); + int min=(int)fmin; + + + long sec=posInBytes-min*(60*_CDROM_FRAMES*2324); + sec=sec/(_CDROM_FRAMES*2324); + + byteCounter=posInBytes; + if (cdRomRawAccess->read(min,sec,0)==false) { + return false; + } + setTimePos(min*60+sec); + + return true; +} + + +int CDRomInputStream::setTimePos(int second) { + currentFrame=0; + currentMinute=second/60; + currentSecond=second%60; + + return fillBuffer(); +} + + + + + +int CDRomInputStream::fillBuffer() { + int maxNoData=30; + int cnt=0; + if (buflen==0) { + while (cnt < maxNoData) { + next_sector(); + if (readCurrent() == false) { + return false; + } + if (cdRomRawAccess->isData() == false) { + // cerr << "no data"<<endl; + cnt++; + } else { + return true; + } + } + return false; + } + return true; +} + + + + + + diff --git a/mpeglib/lib/input/cdromInputStream.h b/mpeglib/lib/input/cdromInputStream.h new file mode 100644 index 00000000..cda18efe --- /dev/null +++ b/mpeglib/lib/input/cdromInputStream.h @@ -0,0 +1,88 @@ +/* + reads input data from cdrom + 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 __VIDEOCDINPUTSTREAM_H +#define __VIDEOCDINPUTSTREAM_H + + + +#include "inputStream.h" + + + +#define _CDROM_FRAMES 75 +#define _CDROM_SECS 60 + + +/** + This is necessary because CD-I or VCD disks are not correctly + mounted by the linux kernel. + Windows seems to do it correct (sometimes, the other time it nearly crash) + During my test I found out that CD-I and VCD seems to be different. + One works with the CD-I loader the other with the VCD loader. + + This class tries to find out if its a CD-I / VCD stream. + Then you can set the interface and load from this interface. + + This class depends on the reader routines from xreadcdi/ xreadvcd, + Author: Ales Makarov <xmakarov@sun.felk.cvut.cz> + FTP : ftp://mca.sh.cvut.cz/pub/readvcd/ + + The code is used in a few other packages, in which I looked as well. + +*/ + +class CDRomRawAccess; +class CDRomToc; + +class CDRomInputStream : public InputStream{ + + CDRomRawAccess* cdRomRawAccess; + CDRomToc* cdRomToc; + + int buflen; + char* bufCurrent; + + int currentFrame; + int currentMinute; + int currentSecond; + long byteCounter; + + public: + CDRomInputStream(); + ~CDRomInputStream(); + + int open(const char* dest); + void close(); + int isOpen(); + + int eof(); + int read(char* ptr,int size); + int seek(long bytePos); + + long getByteLength(); + long getBytePosition(); + + void print(); + + private: + long getBytePos(int min,int sec); + + int setTimePos(int posInTime); + int getByteDirect(); + void next_sector(); + int readCurrent(); + int fillBuffer(); +}; +#endif diff --git a/mpeglib/lib/input/cdromRawAccess.cpp b/mpeglib/lib/input/cdromRawAccess.cpp new file mode 100644 index 00000000..b0df4747 --- /dev/null +++ b/mpeglib/lib/input/cdromRawAccess.cpp @@ -0,0 +1,113 @@ +/* + reads raw input data from cdrom (system dependent) + 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 <iostream> + +#include "cdromRawAccess.h" + +using namespace std; + +CDRomRawAccess::CDRomRawAccess(CDRomToc* cdromToc) { + cdfile=NULL; + lOpen=false; + leof=true; + this->cdromToc=cdromToc; + lData=false; + dataStart=0; + len=0; +} + + +CDRomRawAccess::~CDRomRawAccess() { + close(); +} + + + +char* CDRomRawAccess::getBufferStart() { + return (char*)(data+dataStart); +} + +int CDRomRawAccess::getBufferLen() { + if (eof()) { + return 0; + } + return len; +} + +int CDRomRawAccess::open(const char* filename) { + if (isOpen()) { + close(); + } + if (filename==NULL) { + filename=(char*)"/dev/cdrom"; + } + if (strlen(filename) <= 1) { + filename="/dev/cdrom"; + } + char* openfile=strchr(filename,'/'); + cout << "openfile:"<<openfile<<endl; + cdfile=fopen(openfile, "rb"); + lOpen=false; + + if (cdfile == NULL) { + perror("open CDRomRawAccess"); + } else { + lOpen=true; + leof=false; + } + return lOpen; +} + + +int CDRomRawAccess::eof() { + return leof; +} + + +int CDRomRawAccess::read(int minute,int second, int frame) { + if (isOpen()==false) { + cerr << "CDRomRawAccess not open"<<endl; + return false; + } + + int lInRange=cdromToc->isInRange(minute,second,frame); + if (lInRange == false) { + if (minute*60+second+1 > cdromToc->getEndSecond()) { + leof=true; + } + return false; + } + return readDirect(minute,second,frame); +} + + +void CDRomRawAccess::close() { + if (isOpen()) { + fclose(cdfile); + lOpen=false; + leof=true; + } +} + +int CDRomRawAccess::isData() { + return lData; +} + +int CDRomRawAccess::isOpen() { + return lOpen; +} + + + + diff --git a/mpeglib/lib/input/cdromRawAccess.h b/mpeglib/lib/input/cdromRawAccess.h new file mode 100644 index 00000000..d089a85b --- /dev/null +++ b/mpeglib/lib/input/cdromRawAccess.h @@ -0,0 +1,67 @@ +/* + reads raw input data from cdrom (system dependent) + 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 __CDROMRAWACCESS_H +#define __CDROMRAWACCESS_H + +#include "cdromToc.h" +#include "inputStream.h" + + +/** + Here we have a system wrapper for raw cdrom access. + Currently this is tested on Linux. +*/ + + + + + +class CDRomRawAccess { + + CDRomToc* cdromToc; + char data[2352]; + int dataStart; + int len; + int lData; + + public: + CDRomRawAccess(CDRomToc* cdromToc); + virtual ~CDRomRawAccess(); + + // overload this for new Systems + virtual int readDirect(int minute,int second, int frame); + + // wrapper for readDirect + int read(int minute,int second, int frame); + + char* getBufferStart(); + int getBufferLen(); + + int open(const char* filename); + int eof(); + void close(); + int isOpen(); + + int isData(); + + private: + FILE* cdfile; + int lOpen; + int leof; + int buflen; +}; + +#endif + + diff --git a/mpeglib/lib/input/cdromToc.cpp b/mpeglib/lib/input/cdromToc.cpp new file mode 100644 index 00000000..919ecdc8 --- /dev/null +++ b/mpeglib/lib/input/cdromToc.cpp @@ -0,0 +1,234 @@ +/* + reads toc from cdrom (system dependent) + 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 "cdromToc.h" + +#include <iostream> + +using namespace std; + +CDRomToc::CDRomToc() { + maxEntries=0; +} + + +CDRomToc::~CDRomToc() { +} + + +void CDRomToc::insertTocEntry(int minute,int second,int frame) { + int i; + int j; + if (isElement(minute,second,frame)) { + return; + } + + i=getNextTocEntryPos(minute,second,frame); + + // now shift from i to end + if (maxEntries == 100) { + cerr << "maximum of toc entries reached"<<endl; + exit(0); + } + for (j=maxEntries;j>i;j--) { + tocEntries[j].minute=tocEntries[j-1].minute; + tocEntries[j].second=tocEntries[j-1].second; + tocEntries[j].frame=tocEntries[j-1].frame; + } + maxEntries++; + + tocEntries[i].minute=minute; + tocEntries[i].second=second; + tocEntries[i].frame=frame; + calculateRange(); +} + + +int CDRomToc::getNextTocEntryPos(int minute,int second,int frame) { + int i; + if (maxEntries == 0) { + return 0; + } + + for (i=0;i<maxEntries;i++) { + if (tocEntries[i].minute <= minute) { + continue; + } else { + break; + } + if (tocEntries[i].second <= second) { + continue; + } else { + break; + } + if (tocEntries[i].frame <= frame) { + continue; + } + break; + } + return i; +} + + + +int CDRomToc::isElement(int minute,int second,int frame) { + int i; + + for (i=0;i<maxEntries;i++) { + if (tocEntries[i].minute == minute) { + if (tocEntries[i].second == second) { + if (tocEntries[i].frame == frame) { + return true; + } + } + } + } + return false; +} + + + + + + +int CDRomToc::getTocEntries() { + return maxEntries; +} + + +TocEntry* CDRomToc::getTocEntry(int entry) { + return &(tocEntries[entry]); +} + + +void CDRomToc::print() { + int i; + cerr << "******* printing TOC [START]"<<endl; + for(i=0;i<maxEntries;i++) { + cerr << "i:"<<i + <<" M:"<<tocEntries[i].minute + <<" S:"<<tocEntries[i].second + <<" F:"<<tocEntries[i].frame<<endl; + } + cerr << "******* printing TOC [END}"<<endl; +} + + +int CDRomToc::isInRange(int minute,int second,int) { + long val=minute*60+second; + if (val < startByte) { + return false; + } + if (val > endByte) { + return false; + } + return true; +} + +int CDRomToc::calculateRange() { + + + if (maxEntries < 2) { + cout << "no two elemts in toc"<<endl; + return false; + } + startByte=tocEntries[0].minute*60*+tocEntries[0].second; + + // do a safty end because of the kernel bug + int minute=tocEntries[maxEntries-1].minute; + int second=tocEntries[maxEntries-1].second-20; + if (second < 0) { + minute--; + second=60+second; + } + if (minute < 0) { + endByte=0; + return true; + } + + endByte=minute*60+second; + + return true; + +} + + +int CDRomToc::getEndSecond() { + return endByte; +} + + + + +int CDRomToc::open(const char* openfile) { + int i; + int pos=0; + maxEntries=0; + const char* filename=strchr(openfile,'/'); + FILE* file =fopen(filename, "rb"); + if (file == NULL) { + perror("open"); + return false; + } + cout << "reading toc on:"<<filename<<" openfile:"<<openfile<<endl; + + int startToc=0; + int endToc=0; + + if (getStartEnd(file,startToc,endToc) == false) { + cout << "getStartEnd in CDRomToc failed"<<endl; + fclose(file); + return false; + } + cout << "startToc:"<<startToc<<" endToc:"<<endToc<<endl; + cout << "reading toc -2"<<endl; + /* read individual tracks */ + int min; + int sec; + int frame; + + for (i=startToc; i<=endToc; i++) { + int min; + int sec; + int frame; + + if (readToc(file,i,min,sec,frame) == false) { + cout << "error in CDRomToc::readToc"<<endl; + fclose(file); + return false; + } + cout << "min:"<<min<<endl; + cout << "sec:"<<sec<<endl; + cout << "frame:"<<frame<<endl; + + insertTocEntry(min,sec,frame); + pos++; + } + + + /* read the lead-out track */ + if (readLeadOut(file,min,sec,frame) == false) { + cout << "error in CDRomToc::reatLeadOut"<<endl; + return false; + } + pos++; + insertTocEntry(min,sec,frame); + + maxEntries=pos; + + fclose(file); + + return true; +} + diff --git a/mpeglib/lib/input/cdromToc.h b/mpeglib/lib/input/cdromToc.h new file mode 100644 index 00000000..20b60e10 --- /dev/null +++ b/mpeglib/lib/input/cdromToc.h @@ -0,0 +1,65 @@ +/* + reads toc from cdrom (system dependent) + 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 __CDROMTOC_H +#define __CDROMTOC_H + +extern "C" { +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +} + +struct TocEntry { + int minute; + int second; + int frame; +}; + + +class CDRomToc { + + TocEntry tocEntries[100]; + int maxEntries; + int startByte; + int endByte; + + public: + CDRomToc(); + virtual ~CDRomToc(); + int open(const char* device); + int getTocEntries(); + TocEntry* getTocEntry(int entry); + void insertTocEntry(int minute,int second,int frame); + int getNextTocEntryPos(int minute,int second,int frame); + int isInRange(int minute,int second,int frame); + int isElement(int minute,int second,int frame); + + int getEndSecond(); + + void print(); + + private: + // platform specific calls. + int getStartEnd(FILE* file,int& start, int& end); + int readToc(FILE* file,int num,int& min,int& sec, int& frame); + int readLeadOut(FILE* file,int& min,int& sec, int& frame); + + + + + int calculateRange(); + +}; + +#endif diff --git a/mpeglib/lib/input/fileAccessWrapper.cpp b/mpeglib/lib/input/fileAccessWrapper.cpp new file mode 100644 index 00000000..246807a8 --- /dev/null +++ b/mpeglib/lib/input/fileAccessWrapper.cpp @@ -0,0 +1,65 @@ +/* + wraps an inputStream for the splayFileBuffer. + Copyright (C) 2001 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 "fileAccessWrapper.h" + +#include <iostream> + +using namespace std; + +FileAccessWrapper::FileAccessWrapper(InputStream* input) { + this->input=input; +} + + +FileAccessWrapper::~FileAccessWrapper() { + +} + + +int FileAccessWrapper::open(const char*) { + cout << "FileAccessWrapper open not implemented"<<endl; + exit(0); +} + + +void FileAccessWrapper::close() { + cout << "FileAccessWrapper close not implemented"<<endl; + exit(0); +} + + +int FileAccessWrapper::read(char* dest,int len) { + return input->read(dest,len); +} + +int FileAccessWrapper::eof() { + return input->eof(); +} + + +int FileAccessWrapper::seek(long pos) { + return input->seek(pos); +} + + +long FileAccessWrapper::getBytePosition() { + return input->getBytePosition(); +} + + +long FileAccessWrapper::getByteLength() { + return input->getByteLength(); +} + diff --git a/mpeglib/lib/input/fileAccessWrapper.h b/mpeglib/lib/input/fileAccessWrapper.h new file mode 100644 index 00000000..d7882abb --- /dev/null +++ b/mpeglib/lib/input/fileAccessWrapper.h @@ -0,0 +1,41 @@ +/* + wraps an inputStream for the splayFileBuffer. + Copyright (C) 2001 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 __FILEACCESSWRAPPER_H +#define __FILEACCESSWRAPPER_H + + +#include "../util/file/fileAccess.h" +#include "inputStream.h" + + +class FileAccessWrapper : public FileAccess { + + InputStream* input; + + public: + FileAccessWrapper(InputStream* input); + virtual ~FileAccessWrapper(); + + int open(const char* file); + void close(); + int read(char* dest,int len); + int eof(); + int seek(long pos); + long getBytePosition(); + long getByteLength(); + +}; + + +#endif diff --git a/mpeglib/lib/input/fileInputStream.cpp b/mpeglib/lib/input/fileInputStream.cpp new file mode 100644 index 00000000..77c31ed6 --- /dev/null +++ b/mpeglib/lib/input/fileInputStream.cpp @@ -0,0 +1,148 @@ +/* + reads input data + 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 "fileInputStream.h" + +#include <iostream> + +using namespace std; + +FileInputStream::FileInputStream() { + file=NULL; + lopen=false; + fileLen=0; +} + + +FileInputStream::~FileInputStream() { + close(); +} + + +int FileInputStream::open(const char* dest) { + + close(); + if (dest == NULL) { + return false; + } + setUrl(dest); + if (strlen(dest) == 1) { + if (strncmp(dest,"-",1)==0) { + file=::fdopen(0,"rb"); + } + } + // load out of current dir if no full path is given + if (file == NULL) { + file=fopen(dest,"rb"); + } + fileLen=0; + if (file == NULL) { + cout <<"cannot open file:"<< dest<<endl; + + } else { + lopen=true; + struct stat fileStat; + stat(dest,&fileStat); + fileLen=(long)fileStat.st_size; + } + int back=(file!=NULL); + return back; +} + + +void FileInputStream::close() { + if (isOpen()) { + ::fclose(file); + file=NULL; + lopen=false; + } +} + + +int FileInputStream::isOpen() { + return lopen; +} + + +int FileInputStream::eof() { + if (isOpen()==false){ + return true; + } + int back=true; + if (file != NULL) { + back=feof(file); + } + + return back; +} + + +int FileInputStream::read(char* ptr,int size) { + int bytesRead=-1; + if (isOpen()) { + if (size <= 0) { + cout << "size is <= 0!"<<endl; + return 0; + } + if (file != NULL) { + bytesRead=fread(ptr,1,size,file); + } + } else { + cerr << "read on not open file want:"<<size<<endl; + return 0; + } + return bytesRead; +} + + +int FileInputStream::seek(long posInBytes) { + int back=true; + if (isOpen()==false) { + return false; + } + long pos=-1; + if (file != NULL) { + pos=fseek(file,posInBytes,SEEK_SET); + } + + if (pos < 0) { + cout <<"seek error in FileInputStream::seek"<<endl; + back=false; + } + return back; +} + + +long FileInputStream::getByteLength() { + return fileLen; +} + + +long FileInputStream::getBytePosition() { + int back=0; + if (isOpen()) { + if (file != NULL) { + back=ftell(file); + } + } + return back; +} + + + +void FileInputStream::print() { + printf("pos in file:%8x\n",(int)getBytePosition()); +} + + diff --git a/mpeglib/lib/input/fileInputStream.h b/mpeglib/lib/input/fileInputStream.h new file mode 100644 index 00000000..ea421a55 --- /dev/null +++ b/mpeglib/lib/input/fileInputStream.h @@ -0,0 +1,46 @@ +/* + reads input data + 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 __FILEINPUTSTREAM_H +#define __FILEINPUTSTREAM_H + + + +#include "inputStream.h" + + + +class FileInputStream : public InputStream{ + + FILE* file; + int lopen; + long fileLen; + public: + FileInputStream(); + ~FileInputStream(); + + int open(const char* dest); + void close(); + int isOpen(); + + int eof(); + int read(char* ptr,int size); + int seek(long bytePos); + + long getByteLength(); + long getBytePosition(); + + void print(); + +}; +#endif diff --git a/mpeglib/lib/input/httpInputStream.cpp b/mpeglib/lib/input/httpInputStream.cpp new file mode 100644 index 00000000..df2f09c4 --- /dev/null +++ b/mpeglib/lib/input/httpInputStream.cpp @@ -0,0 +1,327 @@ +/* + reads input data + 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 "httpInputStream.h" + +#ifndef INADDR_NONE +#define INADDR_NONE 0xffffffff +#endif + +#include <iostream> + +using namespace std; + +static const char *httpstr="http://"; + + + +static char *strndup(char *src,int num) { + char *dst; + + if(!(dst=(char *)malloc(num+1)))return NULL; + dst[num]='\0'; + + return strncpy(dst, src, num); +} + +static char *url2hostport(char *url,char **hname, + unsigned long *hip,unsigned int *port) { + char *cptr; + struct hostent *myhostent; + struct in_addr myaddr; + int isip=1; + + if(!(strncmp(url,httpstr,7)))url+=7; + cptr=url; + while(*cptr && *cptr!=':' && *cptr!='/') { + if((*cptr<'0' || *cptr>'9') && *cptr!='.')isip=0; + cptr++; + } + if(!(*hname=strndup(url,cptr-url))) { + *hname=NULL; + return NULL; + } + if(!isip) + { + if (!(myhostent=gethostbyname(*hname)))return NULL; + memcpy(&myaddr,myhostent->h_addr,sizeof(myaddr)); + *hip=myaddr.s_addr; + } + else if((*hip=inet_addr(*hname))==INADDR_NONE)return NULL; + if(!*cptr || *cptr=='/') { + *port=80; + return cptr; + } + *port=atoi(++cptr); + while(*cptr && *cptr!='/')cptr++; + return cptr; +} + + + + + + + + + + + + + +HttpInputStream::HttpInputStream() { + + proxyurl=NULL; + proxyip=0; + lopen=false; + byteCnt=0; +} + + +HttpInputStream::~HttpInputStream() { + close(); +} + + +int HttpInputStream::open(const char* filename) { + close(); + if (filename == NULL) { + return false; + } + /* + int matchPos=InputStream::getPath(filename,"http"); + if (matchPos=0) { + return false; + } + */ + + char* filename2=strdup(filename); + if((fp=http_open(filename2))==NULL) { + cout << "seterrorcode(SOUND_ERROR_FILEOPENFAIL)"<<endl; + delete filename2; + return false; + } + delete filename2; + lopen=true; + setUrl(filename); + return lopen; +} + + +void HttpInputStream::close() { + if (isOpen()) { + ::fclose(fp); + } + lopen=false; + setUrl(NULL); +} + + +int HttpInputStream::isOpen() { + return lopen; +} + + +int HttpInputStream::eof() { + if (isOpen()==false){ + return true; + } + return feof(fp); +} + + +int HttpInputStream::read(char* ptr,int size) { + int bytesRead=0; + if (isOpen()) { + bytesRead=fread(ptr, 1,size, fp); + if (ferror(fp) != 0){ + cout <<"http fread error"<<endl; + } else { + byteCnt+=bytesRead; + } + } + return bytesRead; +} + +int HttpInputStream::seek(long posInBytes) { + cout << "HttpInputStream::setBytePos not implemented:"<<posInBytes<<endl; + return false; +} + + + +long HttpInputStream::getByteLength() { + cout << "HttpInputStream::getByteLength not implemented"<<endl; + return 0; +} + + + +void HttpInputStream::print() { + printf("pos in file:%8x\n",(int)ftell(fp)); +} + + +int HttpInputStream::writestring(int fd, char *string) { + int result,bytes=strlen(string); + + while (bytes) { + if((result=SOCKETWRITEFUNC(fd,string,bytes))<0 && errno!=EINTR) { + cout << "writestring fail -1"<<endl; + return false; + } + else if(result==0) { + cout << "writestring fail -2"<<endl; + return false; + } + string += result; + bytes -= result; + } + return true; +} + + + +FILE* HttpInputStream::http_open(char *url) { + char *purl=NULL,*host,*request,*sptr; + char agent[50]; + int linelength; + unsigned long myip; + unsigned int myport; + int sock; + int relocate=0,numrelocs=0; + struct sockaddr_in server; + FILE *myfile; + if (url == NULL) { + cout << "cannot open NULL http_open"<<endl; + return NULL; + } + if (strlen(url)==0) { + cout << "zero length http_open"<<endl; + return NULL; + } + + if(!proxyip) + { + if(!proxyurl) + if(!(proxyurl=getenv("MP3_HTTP_PROXY"))) + if(!(proxyurl=getenv("http_proxy"))) + proxyurl = getenv("HTTP_PROXY"); + if (proxyurl && proxyurl[0] && strcmp(proxyurl, "none")) + { + if (!(url2hostport(proxyurl, &host, &proxyip, &proxyport))) + { + cout << "seterrorcode(SOUND_ERROR_UNKNOWNPROXY)"<<endl;; + return NULL; + } + if(host)free(host); + } + else + proxyip = INADDR_NONE; + } + + if((linelength=strlen(url)+100)<1024) + linelength=1024; + if(!(request=(char *)malloc(linelength)) || !(purl=(char *)malloc(1024))) + { + cout << "seterrorcode(SOUND_ERROR_MEMORYNOTENOUGH)"<<endl; + return NULL; + } + strncpy(purl,url,1023); + purl[1023]='\0'; + do{ + strcpy(request,"GET "); + if(proxyip!=INADDR_NONE) + { + if(strncmp(url,httpstr,7)) + strcat(request,httpstr); + strcat(request,purl); + myport=proxyport; + myip=proxyip; + } + else + { + if(!(sptr=url2hostport(purl,&host,&myip,&myport))) + { + cout << "seterrorcode(SOUND_ERROR_UNKNOWNHOST)"<<endl;; + return NULL; + } + if (host) + free (host); + strcat (request, sptr); + } + sprintf (agent, " HTTP/1.0\r\nUser-Agent: %s/%s\r\n\r\n", + "Splay","0.6"); + strcat (request, agent); + server.sin_family = AF_INET; + server.sin_port = htons(myport); + server.sin_addr.s_addr = myip; + if((sock=socket(PF_INET,SOCK_STREAM,6))<0) { + cout <<"seterrorcode(SOUND_ERROR_SOCKET)"<<endl; + return NULL; + } + if(connect(sock,(struct sockaddr *)&server,sizeof(server))) { + cout <<"seterrorcode(SOUND_ERROR_CONNECT)"<<endl; + return NULL; + } + if(!writestring(sock,request))return NULL; + if(!(myfile=::fdopen(sock, "rb"))) { + cout << "seterrorcode(SOUND_ERROR_FDOPEN)"<<endl; + return NULL; + }; + relocate=false; + purl[0]='\0'; + if(!readstring(request,linelength-1,myfile))return NULL; + if((sptr=strchr(request,' '))) { + switch(sptr[1]) { + case '3':relocate=true; + case '2':break; + default: + cout <<"seterrorcode(SOUND_ERROR_HTTPFAIL)"<<endl; + return NULL; + } + } + do { + if(!readstring(request,linelength-1,myfile))return NULL; + if(!strncmp(request,"Location:",9)) + strncpy (purl,request+10,1023); + } while (request[0]!='\r' && request[0]!='n'); + } while(relocate && purl[0] && numrelocs++<5); + if(relocate) { + cout << "seterrorcode(SOUND_ERROR_TOOMANYRELOC)"<<endl; + return NULL; + } + free(purl); + free(request); + return myfile; +} + +long HttpInputStream::getBytePosition() { + return 0; +} + +int HttpInputStream::readstring(char *string,int maxlen,FILE *f) { + char *result; + + do{ + result=fgets(string,maxlen,f); + }while(!result && errno==EINTR); + if(!result) + { + cout << "seterrorcode(SOUND_ERROR_FILEREADFAIL)"<<endl; + return false; + } + + return true; +} diff --git a/mpeglib/lib/input/httpInputStream.h b/mpeglib/lib/input/httpInputStream.h new file mode 100644 index 00000000..78ec10f0 --- /dev/null +++ b/mpeglib/lib/input/httpInputStream.h @@ -0,0 +1,84 @@ +/* + reads input data + 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 __HTTPINPUTSTREAM_H +#define __HTTPINPUTSTREAM_H + + +#include "inputStream.h" + +#ifndef __STRICT_ANSI__ +#define __STRICT_ANSI__ +#endif + +#include <stdlib.h> +#include <string.h> + + + +#if defined WIN32 +#include <io.h> +#define SOCKETWRITEFUNC _write +#else + +extern "C" { +#include <netdb.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + } +#define SOCKETWRITEFUNC write +#endif + +#include <sys/types.h> +#include <errno.h> + +class HttpInputStream : public InputStream{ + + long byteCnt; + + public: + HttpInputStream(); + ~HttpInputStream(); + + int open(const char* dest); + void close(); + int isOpen(); + + int eof(); + int read(char* ptr,int size); + int seek(long bytePos); + + long getByteLength(); + long getBytePosition(); + + void print(); + + private: + + FILE* fp; + int size; + + int writestring(int fd,char *string); + int readstring(char *string,int maxlen,FILE *f); + FILE* http_open(char *url); + + char* proxyurl; + unsigned long proxyip; + unsigned int proxyport; + + int lopen; + +}; +#endif diff --git a/mpeglib/lib/input/inputDetector.cpp b/mpeglib/lib/input/inputDetector.cpp new file mode 100644 index 00000000..28bcad5c --- /dev/null +++ b/mpeglib/lib/input/inputDetector.cpp @@ -0,0 +1,192 @@ +/* + returns inputtype for a given string + 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 "inputDetector.h" + +#include <iostream> + +using namespace std; + +static const char *filestrglobal1="/"; +static const char *filestrglobal2="./"; + +typedef struct prot2type_s { + const char* name; + int type; +} prot2type; + +static prot2type protocols[]= { {"http:" , __INPUT_HTTP }, + {"cdi:" , __INPUT_CDI }, + {"vcd:" , __INPUT_CDI }, + {"file:" , __INPUT_FILE }, + {"cdda:" , __INPUT_CDDA }, + {"audiocd:", __INPUT_CDDA }, + {NULL , __INPUT_UNKNOWN} }; + + +InputDetector::InputDetector() { +} + + +InputDetector::~InputDetector() { +} + +int InputDetector::getProtocolPos(int type,const char* url) { + prot2type* current=protocols; + int i=0; + while(current->name != NULL) { + if (current->type == type) { + int len=strlen(current->name); + if (strncmp(url,current->name,len)==0) { + return i; + } + } + i++; + current++; + } + return -1; +} + +int InputDetector::getProtocolType(const char* url) { + prot2type* current=protocols; + int n=strlen(url); + if (n > 0) { + while(current->name != NULL) { + int k=strlen(current->name); + if (n >= k) { + if (strncmp(url,current->name,k)==0) { + return current->type; + } + } + current++; + } + } + return __INPUT_UNKNOWN; +} + +int InputDetector::getInputType(const char* url) { + int back=__INPUT_FILE; + + if (url == NULL) { + return back; + } + + back=InputDetector::getProtocolType(url); + if (back == __INPUT_UNKNOWN) { + back = __INPUT_FILE; + } + + return back; + +} + +char* InputDetector::removeProtocol(const char* url) { + int type=InputDetector::getProtocolType(url); + int n=strlen(url); + if (n == 0) { + return NULL; + } + if (type == __INPUT_UNKNOWN) { + return strdup(url); + } + int pos=InputDetector::getProtocolPos(type,url); + if (pos == -1) { + return NULL; + } + const char* name=protocols[pos].name; + int k=strlen(name); + if (n >= k) { + return strdup(url+k); + } + return NULL; + +} + +char* InputDetector::getExtension(const char* url) { + if (url == NULL) { + cout << "get url NULL"<<endl; + return NULL; + } + char* back=NULL; + char* extStart=strrchr(url,'.'); + if (extStart != NULL) { + cout << "extStart:"<<extStart<<endl; + back=strdup(extStart); + } + return back; +} + +char* InputDetector::removeExtension(const char* url,char* extension) { + if (url == NULL) { + cout << "removeExtension url NULL"<<endl; + return NULL; + } + if (extension == NULL) { + cout << "removeExtension extension NULL"<<endl; + return strdup(url); + } + char* back=NULL; + int nExt=strlen(extension); + int nUrl=strlen(url); + cout << "extension:"<<extension<<" url:"<<url<<endl; + if (nUrl >= nExt) { + if(strncmp(url+nUrl-nExt,extension,nExt)==0) { + back=new char[nUrl-nExt+1]; + back[nUrl-nExt]=0; + strncpy(back,url,nUrl-nExt); + } + } + cout << "removeExt:"<<back<<endl; + return back; + +} + +char* InputDetector::getWithoutExtension(const char* url) { + char* extension=NULL; + char* back=NULL; + if (url == NULL) { + return NULL; + } + extension=InputDetector::getExtension(url); + if (extension == NULL) { + back=strdup(url); + } else { + back=InputDetector::removeExtension(url,extension); + delete extension; + } + return back; +} + +char* InputDetector::getFilename(const char* url) { + if (url == NULL) { + return NULL; + } + char* startSlash=strrchr(url,'/'); + if (startSlash == NULL) { + return NULL; + } + if (strlen(startSlash) == 1) { + return NULL; + } + startSlash++; + if (*startSlash == 0) { + return NULL; + } + return strdup(startSlash); +} + + +char* InputDetector::removeSlash(const char* url) { + return InputDetector::removeExtension(url,(char*)"/"); +} diff --git a/mpeglib/lib/input/inputDetector.h b/mpeglib/lib/input/inputDetector.h new file mode 100644 index 00000000..f4c3e47d --- /dev/null +++ b/mpeglib/lib/input/inputDetector.h @@ -0,0 +1,56 @@ +/* + returns inputtype for a given string + 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 __INPUTDETECTOR_H +#define __INPUTDETECTOR_H + + + +#define __INPUT_UNKNOWN 0 +#define __INPUT_FILE 1 +#define __INPUT_HTTP 2 +#define __INPUT_CDI 3 +#define __INPUT_BUFFER 4 +#define __INPUT_CDDA 5 + +extern "C" { +#include <string.h> +} + + +class InputDetector { + + + public: + InputDetector(); + ~InputDetector(); + + static int getInputType(const char* url); + + static int getProtocolType(const char* url); + // returns new allocated string without protocol specifier + static char* removeProtocol(const char* url); + static char* getWithoutExtension(const char* url); + static char* getExtension(const char* url); + static char* removeExtension(const char* url,char* extension); + static char* removeSlash(const char* url); + static char* getFilename(const char* url); + + private: + static int getProtocolPos(int type,const char* url); + +}; + +#endif + diff --git a/mpeglib/lib/input/inputPlugin.cpp b/mpeglib/lib/input/inputPlugin.cpp new file mode 100644 index 00000000..f3a33002 --- /dev/null +++ b/mpeglib/lib/input/inputPlugin.cpp @@ -0,0 +1,92 @@ +/* + C interface creator for input_plugins + 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 "inputPlugin.h" + +#include <iostream> + +using namespace std; + + +InputPlugin::InputPlugin() { +} + + +InputPlugin::~InputPlugin() { +} + + + +int InputPlugin::getInputType(const char* dest) { + return InputDetector::getInputType(dest); +} + + +InputStream* InputPlugin::createInputStream(int inputType) { + // make checks which input routine to use + InputStream* inputStream; + int method; + + inputStream=NULL; + method=inputType; + + switch(method) { + case __INPUT_FILE: { + inputStream=new FileInputStream(); + break; + } + case __INPUT_CDDA: { + inputStream=new CDDAInputStream(); + break; + } + + case __INPUT_HTTP: { + inputStream=new HttpInputStream(); + break; + } + case __INPUT_CDI: { + inputStream=new CDRomInputStream(); + break; + } + default: + cout << "error cannot create default input stream"<<endl; + exit(0); + } + + return inputStream; +} + +InputStream* InputPlugin::createInputStream(int inputType,int lThreadSafe) { + InputStream* input=InputPlugin::createInputStream(inputType); + if (lThreadSafe == false) { + return input; + } + InputStream* tsInput=new ThreadSafeInputStream(input); + return tsInput; +} + + +InputStream* InputPlugin::createInputStream(const char* dest) { + int method; + + method=InputPlugin::getInputType(dest); + return (InputPlugin::createInputStream(method)); +} + + +InputStream* InputPlugin::createInputStream(const char* dest,int lThreadSafe) { + int method; + + method=InputPlugin::getInputType(dest); + return (InputPlugin::createInputStream(method,lThreadSafe)); +} diff --git a/mpeglib/lib/input/inputPlugin.h b/mpeglib/lib/input/inputPlugin.h new file mode 100644 index 00000000..5ac68307 --- /dev/null +++ b/mpeglib/lib/input/inputPlugin.h @@ -0,0 +1,45 @@ +/* + C interface creator for input_plugins + 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 __INPUTPLUGIN_H +#define __INPUTPLUGIN_H + +#include "httpInputStream.h" +#include "fileInputStream.h" +#include "cdromInputStream.h" +#include "bufferInputStream.h" +#include "threadSafeInputStream.h" +#include "cddaInputStream.h" +#include <string.h> + +#include "inputDetector.h" +#include <kdemacros.h> + +#define _INPUT_THREADSAFE 1 + +class KDE_EXPORT InputPlugin { + + public: + InputPlugin(); + ~InputPlugin(); + + static InputStream* createInputStream(int inputType); + static InputStream* createInputStream(int inputType,int lThreadSafe); + static InputStream* createInputStream(const char* dest); + static InputStream* createInputStream(const char* dest,int lThreadSafe); + static int getInputType(const char* dest); + +}; +#endif diff --git a/mpeglib/lib/input/inputStream.cpp b/mpeglib/lib/input/inputStream.cpp new file mode 100644 index 00000000..7eb9943b --- /dev/null +++ b/mpeglib/lib/input/inputStream.cpp @@ -0,0 +1,135 @@ +/* + generic input class + 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 "inputStream.h" +#include "../util/mmx/mmx.h" + +#include <iostream> + +using namespace std; + + +InputStream::InputStream() { + timeStampArray=new TimeStampArray((char*)"Input",3000); + urlBuffer=new DynBuffer(20); + // we call mm_support() here because it is the only position + // where we gurantee that not threads are + // running (the call is not thread safe) + // afer the call we never execute the asm part again + // and everything is fine + mm_support(); +} + + + +InputStream::~InputStream() { + delete timeStampArray; + delete urlBuffer; + +} + + +int InputStream::open(const char* dest) { + cout << "direct virtual call InputStream::open:"<<dest<<endl; + return false; +} + + +void InputStream::close() { + cout << "direct virtual call InputStream::close"<<endl; + exit(0); +} + + +int InputStream::isOpen() { + cout << "direct virtual call InputStream::isOpen"<<endl; + exit(0); + return false; +} + + +int InputStream::eof() { + cout << "direct virtual call InputStream::eof"<<endl; + exit(0); + return true; +} + + +int InputStream::read(char* ,int ) { + cout << "direct virtual call InputStream::read"<<endl; + exit(0); + return 0; +} + + +int InputStream::seek(long bytePos) { + cout << "direct virtual call InputStream::seek:"<<bytePos<<endl; + exit(0); + return false; +} + +void InputStream::clear() { + cout << "direct virtual call InputStream::clear:"<<endl; + exit(0); +} + + +long InputStream::getByteLength() { + cout << "direct virtual call InputStream::getByteLength"<<endl; + return 0; +} + + +long InputStream::getBytePosition() { + cout << "direct virtual call InputStream::getBytePosition"<<endl; + return 0; +} + + +void InputStream::insertTimeStamp(TimeStamp* src,long key,int len) { + timeStampArray->insertTimeStamp(src,key,len); +} + +TimeStamp* InputStream::getTimeStamp(long key) { + return timeStampArray->getTimeStamp(key); +} + + +int InputStream::bytesUntilNext(long key) { + return timeStampArray->bytesUntilNext(key); +} + +void InputStream::print() { + cout << "direct virtual call InputStream::print"<<endl; +} + + + + + +char* InputStream::getUrl() { + return urlBuffer->getData(); +} + + +void InputStream::setUrl(const char* url) { + urlBuffer->clear(); + if (url != NULL) { + urlBuffer->append(url); + } +} + + + + + diff --git a/mpeglib/lib/input/inputStream.h b/mpeglib/lib/input/inputStream.h new file mode 100644 index 00000000..e232e99b --- /dev/null +++ b/mpeglib/lib/input/inputStream.h @@ -0,0 +1,79 @@ +/* + generic input class + 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 __MPEGLIBINPUTSTREAM_H +#define __MPEGLIBINPUTSTREAM_H + + +extern "C" { +#include <string.h> +#include <stdio.h> +#include <sys/stat.h> +} + +#include "../util/timeStampArray.h" +#include "../util/dynBuffer.h" + + + + +/** + The abstraction for the input stream. In derived classes + we implement http,file and cdi access. +*/ + + +class InputStream { + + + + public: + InputStream(); + + + virtual ~InputStream(); + + virtual int open(const char* dest); + virtual void close(); + virtual int isOpen(); + + virtual int eof(); + virtual int read(char* ptr,int size); + virtual int seek(long bytePos); + // clears possible input buffers + // (called by the decoderPlugin after a resyncCommit) + virtual void clear(); + + virtual long getByteLength(); + virtual long getBytePosition(); + + virtual void insertTimeStamp(TimeStamp* src,long key,int len); + virtual TimeStamp* getTimeStamp(long key); + virtual int bytesUntilNext(long key); + virtual void print(); + char* getUrl(); + + + + protected: + DynBuffer* urlBuffer; + + + class TimeStampArray* timeStampArray; + void setUrl(const char* url); + + +}; +#endif diff --git a/mpeglib/lib/input/simpleRingBuffer.cpp b/mpeglib/lib/input/simpleRingBuffer.cpp new file mode 100644 index 00000000..71c92329 --- /dev/null +++ b/mpeglib/lib/input/simpleRingBuffer.cpp @@ -0,0 +1,420 @@ +/* + a thread safe ring buffer without dependencies + 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 "simpleRingBuffer.h" +#include <string.h> + +#include <iostream> + +using namespace std; + +static int instanceCnt=0; + +SimpleRingBuffer::SimpleRingBuffer(int size,int minLinSize) { + abs_thread_mutex_init(&mut); + abs_thread_cond_init(&dataCond); + abs_thread_cond_init(&spaceCond); + + instance=instanceCnt; + instanceCnt++; + this->size=size; + startPos=(char*)malloc(size); + readPos=startPos; + writePos=startPos; + lockPos=startPos; + + lockgrade=0; + fillgrade=0; + linAvail=size; + lastPos=(startPos+size-1); + eofPos=lastPos+1; + + canWrite=size; + canRead=0; + + minLinBuf=new char[minLinSize]; + this->minLinBufSize=minLinSize; + waitMinData=0; + waitMinSpace=0; + lWaitForData=false; + lWaitForSpace=false; + + readBytes=0; + writeBytes=0; + + lCanWaitForData=true; + lCanWaitForSpace=true; +} + + +SimpleRingBuffer::~SimpleRingBuffer() { + // The user of this class must take care that the threads + // have exited! + free(startPos); + delete [] minLinBuf; + abs_thread_mutex_destroy(&mut); + abs_thread_cond_destroy(&dataCond); + abs_thread_cond_destroy(&spaceCond); +} + + +int SimpleRingBuffer::getSize() { + return size; +} + + +int SimpleRingBuffer::getWriteArea(char* &ptr,int &size) { + + // When we are in this area the following + // can happen by the other thread + // fillgrade is decreased (because reader fowards) + // readPos is changed. + + ptr=writePos; + size=canWrite; + + return size; +} + + +void SimpleRingBuffer::updateCanWrite() { + if (lockPos < writePos) { + canWrite=eofPos-writePos; + //printf("1 c:%d l:%p w:%p",canWrite,lockPos,writePos); + } else if (lockPos > writePos) { + canWrite=lockPos-writePos; + //printf("2 c:%d l:%p w:%p",canWrite,lockPos,writePos); + } else { + if (fillgrade > 0) { + canWrite=0; + } else { + canWrite=eofPos-writePos; + } + //printf("2 c:%d ",canWrite); + + } + if (canWrite < 0) { + printf("error canWrite:%d fill:%d lock:%p start:%p eof:%p write:%p\n", + canWrite,fillgrade,lockPos,startPos,eofPos,writePos); + } + +} + + +void SimpleRingBuffer::updateCanRead() { + canRead=fillgrade-lockgrade; + int currentSpace=size-fillgrade; + if (currentSpace >= waitMinSpace) { + abs_thread_cond_signal(&spaceCond); + } + if (canRead < 0) { + printf("error canRead:%d fillgrade:%d lockgrade:%d \n", + canRead,fillgrade,lockgrade); + } + +} + + +void SimpleRingBuffer::forwardLockPtr(int nBytes) { + abs_thread_mutex_lock(&mut); + + if (fillgrade < lockgrade) { + printf("1:fillgrade:%d < lockgrade:%d\n",fillgrade,lockgrade); + } + fillgrade-=nBytes; + lockgrade-=nBytes; + if (fillgrade < lockgrade) { + printf("2:fillgrade:%d < lockgrade:%d nBytes:%d\n", + fillgrade,lockgrade,nBytes); + } + lockPos=lockPos+nBytes; + if (lockPos > lastPos) { // we expects that we had a linAvail part + // if user forwards more than buffer boundary + nBytes=lockPos-lastPos; + lockPos=startPos+nBytes-1; + } + updateCanWrite(); + updateCanRead(); + + abs_thread_mutex_unlock(&mut); + return; +} + + +void SimpleRingBuffer::forwardWritePtr(int nBytes) { + abs_thread_mutex_lock(&mut); + + fillgrade=fillgrade+nBytes; + if (fillgrade < lockgrade) { + printf("3:fillgrade:%d < lockgrade:%d nBytes:%d\n", + fillgrade,lockgrade,nBytes); + } + writeBytes+=nBytes; + writePos=writePos+nBytes; + if(writePos >= eofPos) { + if (writePos == eofPos) { + writePos=startPos; + } else { + cout << "writePos > eofPos ! forward error:"<<(eofPos-writePos) + <<" bytes"<<endl; + } + } + + updateCanWrite(); + updateCanRead(); + if (fillgrade >= waitMinData) { + abs_thread_cond_signal(&dataCond); + } + abs_thread_mutex_unlock(&mut); +} + + +int SimpleRingBuffer::waitForSpace(int bytes){ + abs_thread_mutex_lock(&mut); + int back=0; + waitMinSpace=bytes; + if (waitMinSpace > size) { + waitMinSpace=size; + } + if (waitMinSpace < 0) { + cout << "negative waitForSpace"<<endl; + waitMinSpace=0; + } + int currentSpace=size-fillgrade; + if (lCanWaitForSpace) { + if (currentSpace < waitMinSpace) { + lWaitForSpace=true; + // it is not possible to wait for data/space simultanously + if (lWaitForData == true) { + abs_thread_cond_signal(&dataCond); + } + abs_thread_cond_wait(&spaceCond,&mut); + lWaitForSpace=false; + } + } + if (size-fillgrade >= waitMinSpace) { + back=1; + } + abs_thread_mutex_unlock(&mut); + return back; +} + + +void SimpleRingBuffer::exitWaitForSpace(){ + abs_thread_mutex_lock(&mut); + abs_thread_cond_signal(&spaceCond); + abs_thread_mutex_unlock(&mut); +} + +void SimpleRingBuffer::setCanWaitForSpace(int lCanWaitForSpace) { + abs_thread_mutex_lock(&mut); + this->lCanWaitForSpace=lCanWaitForSpace; + abs_thread_cond_signal(&spaceCond); + abs_thread_mutex_unlock(&mut); + +} + + + +void SimpleRingBuffer::forwardReadPtr(int nBytes) { + abs_thread_mutex_lock(&mut); + readBytes+=nBytes; + readPos+=nBytes; + linAvail=linAvail-nBytes; + lockgrade+=nBytes; + if (readPos > lastPos) { // we expects that we had a linAvail part + // if user forwards more than buffer boundary + nBytes=readPos-lastPos; + readPos=startPos+nBytes-1; + linAvail=lastPos+1-readPos; + } + if (fillgrade < lockgrade) { + printf("5:fillgrade:%d < lockgrade:%d nBytes:%d\n", + fillgrade,lockgrade,nBytes); + } + updateCanRead(); + abs_thread_mutex_unlock(&mut); +} + + + +int SimpleRingBuffer::getReadArea(char* &ptr,int &readSize) { + int pSize=readSize; + ptr=readPos; + + if (canRead == 0) { + readSize=0; + return 0; + } + if (pSize < 0) { + cout << "Generic Memory Info invalid"<<endl; + pSize=size/2; + } + // + // Now the part the we deliver a minimum buffer if it is + // possible + // + + if ( (pSize > linAvail) && + (minLinBufSize >linAvail) && + (canRead > linAvail) ) { + int copySize; + copySize=canRead; // we cannot copy more than this + if (copySize > pSize) { // if it is too much reduche it + copySize=pSize; + } + if (copySize > minLinBufSize) { // if it does not fit in buffer->reduce + copySize=minLinBufSize; + } + memcpy(minLinBuf,readPos,linAvail); + memcpy(minLinBuf+linAvail,startPos,copySize-linAvail); + readSize=copySize; + ptr=minLinBuf; + return copySize; + } + + // linAvail part end + + int copyBytes=linAvail; + if (canRead < copyBytes) { + copyBytes=canRead; + } + if (copyBytes >= pSize) { + readSize=pSize; + } else { + readSize=copyBytes; + } + return readSize; +} + + + +void SimpleRingBuffer::exitWaitForData(){ + abs_thread_mutex_lock(&mut); + abs_thread_cond_signal(&dataCond); + abs_thread_mutex_unlock(&mut); +} + + + +int SimpleRingBuffer::waitForData(int bytes){ + abs_thread_mutex_lock(&mut); + int back=0; + waitMinData=bytes; + if (waitMinData > size) { + waitMinData=size; + } + if (waitMinData < 0) { + cout << "negative waitForData"<<endl; + waitMinData=0; + } + if (lCanWaitForData) { + if (fillgrade < waitMinData) { + lWaitForData=true; + // it is not possible to wait for data space simultanously + if (lWaitForSpace == true) { + abs_thread_cond_signal(&spaceCond); + } + abs_thread_cond_wait(&dataCond,&mut); + lWaitForData=false; + } + } + if (fillgrade >= waitMinData) { + back=1; + } + abs_thread_mutex_unlock(&mut); + return back; +} + +int SimpleRingBuffer::getCanWaitForData() { + return lCanWaitForData; +} + + +void SimpleRingBuffer::setCanWaitForData(int lCanWaitForData) { + abs_thread_mutex_lock(&mut); + this->lCanWaitForData=lCanWaitForData; + abs_thread_cond_signal(&dataCond); + abs_thread_mutex_unlock(&mut); + +} + +void SimpleRingBuffer::emptyBuffer() { + abs_thread_mutex_lock(&mut); + writePos=readPos; + if (fillgrade < lockgrade) { + printf("4:fillgrade:%d < lockgrade:%d\n",fillgrade,lockgrade); + } + linAvail=lastPos+1-writePos; + fillgrade=lockgrade; + updateCanRead(); + updateCanWrite(); + readBytes=0; + writeBytes=0; + if (size-fillgrade >= waitMinSpace) { + abs_thread_cond_signal(&spaceCond); + } + if (fillgrade >= waitMinData) { + abs_thread_cond_signal(&dataCond); + } + abs_thread_mutex_unlock(&mut); +} + + +int SimpleRingBuffer::getFillgrade() { + return fillgrade; +} + + +int SimpleRingBuffer::getReadBytes() { + return readBytes; +} + + +int SimpleRingBuffer::getWriteBytes() { + return writeBytes; +} + + +int SimpleRingBuffer::getFreeRead() { + return fillgrade; +} + +int SimpleRingBuffer::getFreeWrite() { + return size-fillgrade; +} + +void SimpleRingBuffer::resizeBuffer(int changeSize) { + abs_thread_mutex_lock(&mut); + int lPos=lockPos-startPos; + int wPos=writePos-startPos; + int rPos=readPos-startPos; + startPos=(char *)realloc(startPos,changeSize); + size=changeSize; + readPos=startPos+lPos; + writePos=startPos+wPos; + lockPos=startPos+rPos; + + lastPos=(startPos+size-1); + eofPos=lastPos+1; + + linAvail=lastPos+1-readPos; + + updateCanWrite(); + updateCanRead(); + abs_thread_mutex_unlock(&mut); + + +} diff --git a/mpeglib/lib/input/simpleRingBuffer.h b/mpeglib/lib/input/simpleRingBuffer.h new file mode 100644 index 00000000..101725bf --- /dev/null +++ b/mpeglib/lib/input/simpleRingBuffer.h @@ -0,0 +1,136 @@ +/* + a thread safe ring buffer without dependencies + 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 _SIMPLERINGBUFFER_H +#define _SIMPLERINGBUFFER_H + +#include "../util/abstract/abs_thread.h" + +extern "C" { + #include <stdio.h> +} + +/** + Note to parameter minLinBufSize in Constructor: + <p> + If the fillgrade is sufficient we can delivier at least + this amount of bytes with one "fill" + (If the fillgrade is not suffficient we can only deliever fillgrade) + This values adresses the problem that a ring buffer cannot + deliever linear memory the whole time(eg. if you read near the + upper end) + <p> + If the requested Buffersize by the device is smaller than + this number you can be sure that you get exactly + your preferred buffersize. not more not less.(but + only if the fillgrade allows this) +*/ + + + + +class SimpleRingBuffer { + + + public: + + SimpleRingBuffer(int ringBufferSize, int minLinBufferSize); + virtual ~SimpleRingBuffer(); + + // Writer thread can call these: + + int getWriteArea(char* &ptr,int &size); + void forwardWritePtr(int bytes); + int waitForSpace(int minSpace); + void exitWaitForSpace(); + void setCanWaitForSpace(int lCanWaitForSpace); + + + // Reader thread these: + + void forwardReadPtr(int bytes); + int getReadArea(char* &ptr,int &size); + int waitForData(int minData); + void exitWaitForData(); + void setCanWaitForData(int lCanWaitForData); + int getCanWaitForData(); + + + // and the lockPos + void forwardLockPtr(int bytes); + + + // both: + + int getFillgrade(); // return how much buffer between reader/writer + void emptyBuffer(); // frees the space between them + int getFreeRead(); + int getFreeWrite(); + + int getSize(); + int getReadBytes(); + int getWriteBytes(); + + // make sure that no one calls getReadArea/getWriteArea + void resizeBuffer(int changeSize); + private: + void updateCanWrite(); + void updateCanRead(); + + int size; + + int lockgrade; + int fillgrade; + + char* readPos; + char* writePos; + char* lockPos; + + char* startPos; + + char* lastPos; + char* eofPos; + int canWrite; + int canRead; + + int waitMinData; + int waitMinSpace; + + abs_thread_mutex_t mut; + abs_thread_cond_t dataCond; + abs_thread_cond_t spaceCond; + + int insertBlock; + int readBlock; + int linAvail; + + char* minLinBuf; + int minLinBufSize; + int lWaitForData; + int lWaitForSpace; + + // statistic purpose: + int readBytes; + int writeBytes; + + int lCanWaitForSpace; + int lCanWaitForData; + int instance; +}; + +#endif + + + diff --git a/mpeglib/lib/input/threadSafeInputStream.cpp b/mpeglib/lib/input/threadSafeInputStream.cpp new file mode 100644 index 00000000..8b18a4c5 --- /dev/null +++ b/mpeglib/lib/input/threadSafeInputStream.cpp @@ -0,0 +1,137 @@ +/* + thread safe wrapper for input Stream + 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 "threadSafeInputStream.h" + + +ThreadSafeInputStream::ThreadSafeInputStream(InputStream* input) { + threadQueue=new ThreadQueue(); + this->input=input; +} + + +ThreadSafeInputStream::~ThreadSafeInputStream() { + delete threadQueue; + delete input; +} + + + +int ThreadSafeInputStream::open(const char* dest) { + int back; + threadQueue->waitForExclusiveAccess(); + back=input->open(dest); + threadQueue->releaseExclusiveAccess(); + return back; +} + + +void ThreadSafeInputStream::close() { + threadQueue->waitForExclusiveAccess(); + input->close(); + threadQueue->releaseExclusiveAccess(); +} + + +int ThreadSafeInputStream::isOpen() { + int back; + threadQueue->waitForExclusiveAccess(); + back=input->isOpen(); + threadQueue->releaseExclusiveAccess(); + return back; +} + + +int ThreadSafeInputStream::eof() { + int back; + threadQueue->waitForExclusiveAccess(); + back=input->eof(); + threadQueue->releaseExclusiveAccess(); + return back; +} + + +int ThreadSafeInputStream::read(char* buf,int len) { + int back; + threadQueue->waitForExclusiveAccess(); + back=input->read(buf,len); + threadQueue->releaseExclusiveAccess(); + return back; +} + + +int ThreadSafeInputStream::seek(long bytePos) { + int back; + threadQueue->waitForExclusiveAccess(); + back=input->seek(bytePos); + threadQueue->releaseExclusiveAccess(); + return back; +} + +void ThreadSafeInputStream::clear() { + threadQueue->waitForExclusiveAccess(); + input->clear(); + threadQueue->releaseExclusiveAccess(); +} + + +long ThreadSafeInputStream::getByteLength() { + long back; + threadQueue->waitForExclusiveAccess(); + back=input->getByteLength(); + threadQueue->releaseExclusiveAccess(); + return back; +} + + +long ThreadSafeInputStream::getBytePosition() { + long back; + threadQueue->waitForExclusiveAccess(); + back=input->getBytePosition(); + threadQueue->releaseExclusiveAccess(); + return back; +} + + +void ThreadSafeInputStream::insertTimeStamp(TimeStamp* src,long key,int len) { + threadQueue->waitForExclusiveAccess(); + input->insertTimeStamp(src,key,len); + threadQueue->releaseExclusiveAccess(); +} + + +TimeStamp* ThreadSafeInputStream::getTimeStamp(long key) { + TimeStamp* back; + threadQueue->waitForExclusiveAccess(); + back=input->getTimeStamp(key); + threadQueue->releaseExclusiveAccess(); + return back; +} + + +int ThreadSafeInputStream::bytesUntilNext(long key) { + int back; + threadQueue->waitForExclusiveAccess(); + back=input->bytesUntilNext(key); + threadQueue->releaseExclusiveAccess(); + return back; +} + +void ThreadSafeInputStream::print() { + threadQueue->waitForExclusiveAccess(); + input->print(); + threadQueue->releaseExclusiveAccess(); +} + + + diff --git a/mpeglib/lib/input/threadSafeInputStream.h b/mpeglib/lib/input/threadSafeInputStream.h new file mode 100644 index 00000000..0a29637b --- /dev/null +++ b/mpeglib/lib/input/threadSafeInputStream.h @@ -0,0 +1,56 @@ +/* + thread safe wrapper for input Stream + 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 __THREADSAFEINPUTSTREAM_H +#define __THREADSAFEINPUTSTREAM_H + +// read INTRO in threadQueue.h +// This class makes the inputStream (given in constructor) +// threadsafe by wrapping each call with a threadqueue. +// +// Important NOTE: the input pointer is the owned by this class !!! +// which means: we call delete on it! + +#include "../util/abstract/threadQueue.h" +#include "inputStream.h" + + +class ThreadSafeInputStream : public InputStream { + + ThreadQueue* threadQueue; + InputStream* input; + + public: + ThreadSafeInputStream(InputStream* input); + ~ThreadSafeInputStream(); + + + int open(const char* dest); + void close(); + int isOpen(); + + int eof(); + int read(char* ptr,int size); + int seek(long bytePos); + void clear(); + + long getByteLength(); + long getBytePosition(); + + void insertTimeStamp(TimeStamp* src,long key,int len); + TimeStamp* getTimeStamp(long key); + int bytesUntilNext(long key); + void print(); + +}; +#endif diff --git a/mpeglib/lib/mpegplay/COPYRIGHT b/mpeglib/lib/mpegplay/COPYRIGHT new file mode 100644 index 00000000..39076276 --- /dev/null +++ b/mpeglib/lib/mpegplay/COPYRIGHT @@ -0,0 +1,145 @@ + +The copyright of this package is a bit interesting. + +I release my modification under GPL, although many +parts (which I only copy&paste) are still the BSD license. +Thus, if you use this software, you use GPL source with +all advantages off the GPL license :-) + +Martin Vogt <mvogt@rhrk.uni-kl.de> + + +Here is the "history" of this package: + + +The copyrights from mpeg_play: +=========================================== + +First the source comes from the Berkeley mpeg_play player. +and was programmed by: + + MPEG Video Software Decoder + (Version 2.3; March 1996) + + Lawrence A. Rowe<Rowe@CS.Berkeley.EDU>, Ketan Patel, Brian Smith, Steve Smoot, and Eugene Hung + Computer Science Division-EECS, Univ. of Calif. at Berkeley + +mpeg_play related emails: + mpeg-bugs@plateau.cs.berkeley.edu + +The JPEG code comes from : + + jrevdct.c comes from the IJG libjpeg release, +The "official" archive site for this software is ftp.uu.net (Internet +address 192.48.96.9). The most recent released version can always be +found there in directory graphics/jpeg. + + + +Many other peoples have contributed to the mpeg_play package: + +ACKNOWLEDGEMENTS: + We gratefully thank Hewlett-Packard, Fujitsu, the Semiconductor + Research Corporation for financial support. + + We also want to thank the following people for their help: + + Tom Lane of the Independent JPEG Group provided us with + the basic inverse DCT code used by our player. + (tom_lane@g.gp.cs.cmu.edu) + + Reid Judd of Sun Microsystems provided advice and assistance. + + Todd Brunhoff of NVR provided advice and assistance. + + Toshihiko Kawai of Sony provided advice and assistance. + + Portions of this software Copyright (c) 1995 Brown University. + All rights reserved.(Loring Holden lsh@cs.brown.edu) + + + +Here is my work: + +The mpeg_play source has become over the years more and more _ugly_. +When I started the work (I wanted to play my Titanic CD-I with Linux) +I saw that mpeg_play needed a complete reengineering. This package +is the result of this work: + +* a readable source code +* better structures (although not real OOP) +* a few frames/second slower (buy faster cpus!) +* and usefull input interfaces (for file,http,..) + +But my modification (which makes programmers life much easier) +are done under the GPL! +Ok, the main part is still under the BSD License (all these +strange and complicated algorithm, I don't understand) but if you +use this package (with my modifications) you use GPL source! + +And ere are all theses Licences: +/* + * Copyright (c) 1995 The Regents of the University of California. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement is + * hereby granted, provided that the above copyright notice and the following + * two paragraphs appear in all copies of this software. + * + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF + * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + + +/* + * Portions of this software Copyright (c) 1995 Brown University. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement + * is hereby granted, provided that the above copyright notice and the + * following two paragraphs appear in all copies of this software. + * + * IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF BROWN + * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * BROWN UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" + * BASIS, AND BROWN UNIVERSITY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, + * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + + +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; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + +For more information you can conntact me by electronic mail: + + mvogt@rhrk.uni-kl.de + + diff --git a/mpeglib/lib/mpegplay/Makefile.am b/mpeglib/lib/mpegplay/Makefile.am new file mode 100644 index 00000000..172d4a96 --- /dev/null +++ b/mpeglib/lib/mpegplay/Makefile.am @@ -0,0 +1,48 @@ +# libsplay - Makefile.am + +EXTRA_DIST = mainMpegPlay.cpp README COPYRIGHT \ + mmxidct_asm.S copyFunctions.cpp + +INCLUDES = $(all_includes) + +AM_ASFLAGS = $(DEFS) $(DEFAULT_INCLUDES) $(all_includes) $(INTELCPPFLAG) +AM_CCASFLAGS = $(AM_ASFLAGS) + + +noinst_LTLIBRARIES = libmpegplay.la + +noinst_HEADERS = mpegVideoHeader.h mpegVideoStream.h \ + decoderTables.h gop.h \ + proto.h \ + recon.h startCodes.h \ + jrevdct.h \ + motionVector.h slice.h \ + decoderClass.h \ + mmxidct.h \ + picture.h mpegExtension.h macroBlock.h \ + copyFunctions.h \ + mpegVideoBitWindow.h videoDecoder.h \ + copyFunctions_asm.h copyFunctions_mmx.h + +mpegutildir = $(includedir)/$(THIS_LIB_NAME)/mpegutil + +mpegutil_HEADERS = mpegSystemStream.h mpegVideoLength.h \ + mpegSystemHeader.h tsSystemStream.h \ + psSystemStream.h pesSystemStream.h + +libmpegplay_la_SOURCES = mpegVideoHeader.cpp mpegVideoStream.cpp \ + globals.cpp jrevdct.cpp \ + recon.cpp decoderClass.cpp \ + decoderTables.cpp motionVector.cpp \ + slice.cpp gop.cpp \ + mmxidct.cpp \ + mpegSystemHeader.cpp mpegSystemStream.cpp \ + picture.cpp mpegExtension.cpp \ + macroBlock.cpp \ + mpegVideoLength.cpp \ + mpegVideoBitWindow.cpp videoDecoder.cpp \ + copyFunctions_asm.cpp copyFunctions_mmx.cpp \ + mmxidct_asm.S copyFunctions.cpp \ + tsSystemStream.cpp psSystemStream.cpp \ + pesSystemStream.cpp + diff --git a/mpeglib/lib/mpegplay/README b/mpeglib/lib/mpegplay/README new file mode 100644 index 00000000..5bd23c08 --- /dev/null +++ b/mpeglib/lib/mpegplay/README @@ -0,0 +1,26 @@ + +This directory contains a highly modified version of +mpeg_play the Berkley mpeg video player. + +Please view the file COPYRIGHT for licence questions. + +mpeg_play is in its current state (2.4) old and ugly source. +It's an old software package, which has been ported to too +many architectures, without keeping the source clean. + +(No, #ifdef/#defines is not the way to write cross platform code!) + +This is a new approach of an mpeg1 video player. + +I think this library is much cleaner and is now really usable +for mpeg1 video/audio playing. + +It needed a lot of work to even come to this (not +optimal) source code. But if you knew the mpeg_play source, you +obviously understand :-) + + +For comments or bug reports you can write me an email: + +Martin Vogt <mvogt@rhrk.uni-kl.de> + diff --git a/mpeglib/lib/mpegplay/configure.in.in b/mpeglib/lib/mpegplay/configure.in.in new file mode 100644 index 00000000..b2830f33 --- /dev/null +++ b/mpeglib/lib/mpegplay/configure.in.in @@ -0,0 +1 @@ +AM_PROG_AS diff --git a/mpeglib/lib/mpegplay/copyFunctions.cpp b/mpeglib/lib/mpegplay/copyFunctions.cpp new file mode 100644 index 00000000..e290da50 --- /dev/null +++ b/mpeglib/lib/mpegplay/copyFunctions.cpp @@ -0,0 +1,330 @@ +/* + stores heavily used copy functions (makes mmx support easier) + 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 "copyFunctions.h" + + +/* + * We use a lookup table to make sure values stay in the 0..255 range. + * Since this is cropping (ie, x = (x < 0)?0:(x>255)?255:x; ), wee call this + * table the "crop table". + * MAX_NEG_CROP is the maximum neg/pos value we can handle. + */ +/* + * We use a lookup table to make sure values stay in the 0..255 range. + * Since this is cropping (ie, x = (x < 0)?0:(x>255)?255:x; ), wee call this + * table the "crop table". + * MAX_NEG_CROP is the maximum neg/pos value we can handle. + */ + +// Compiler cannot allocate too big arrays. + + + + +CopyFunctions::CopyFunctions() { + /* Initialize crop table. */ + cropTbl=new unsigned char[NUM_CROP_ENTRIES]; + + int i; + + for (i = (-MAX_NEG_CROP); i < NUM_CROP_ENTRIES - MAX_NEG_CROP; i++) { + if (i <= 0) { + cropTbl[i + MAX_NEG_CROP] = 0; + } else if (i >= 255) { + cropTbl[i + MAX_NEG_CROP] = 255; + } else { + cropTbl[i + MAX_NEG_CROP] = i; + } + } + cm=cropTbl + MAX_NEG_CROP; + + copyFunctions_asm = new CopyFunctions_MMX(); + lmmx=copyFunctions_asm->support(); + + + +} + + +CopyFunctions::~CopyFunctions() { + delete cropTbl; +} + +void CopyFunctions::startNOFloatSection() { + // nothing + copyFunctions_asm->startNOFloatSection(); +} + + +void CopyFunctions::endNOFloatSection() { + copyFunctions_asm->endNOFloatSection(); + +} + + +void CopyFunctions::copy8_byte(unsigned char* source1, + unsigned char* dest,int inc) { + if (lmmx == false) { + int rr; + + for (rr = 0; rr < 8; rr++) { + memcpy(dest,source1,sizeof(char)*8); + source1+=inc; + dest+=inc; + } + + } else { + copyFunctions_asm->copy8_byte(source1,dest,inc); + } + + +} + +void CopyFunctions::copy8_word(unsigned short* source1, + unsigned short* dest,int inc) { + int rr; + + // Optimisation is slower, leave it in C + for (rr = 0; rr < 8; rr++) { + memcpy(dest,source1,sizeof(short)*8); + source1+=inc; + dest+=inc; + } + +} + + + +void CopyFunctions::copy8_src1linear_crop(short* source1, + unsigned char* dest,int inc) { + + if (lmmx == false) { + int rr; + + for (rr = 0; rr < 8; rr++) { + + dest[0] = cm[source1[0]]; + dest[1] = cm[source1[1]]; + dest[2] = cm[source1[2]]; + dest[3] = cm[source1[3]]; + dest[4] = cm[source1[4]]; + dest[5] = cm[source1[5]]; + dest[6] = cm[source1[6]]; + dest[7] = cm[source1[7]]; + + + dest += inc; + source1 += 8; + + } + } else { + copyFunctions_asm->copy8_src1linear_crop(source1,dest,inc); + } + +} + +void CopyFunctions::copy8_div2_nocrop(unsigned char* source1, + unsigned char* source2, + unsigned char* dest,int inc) { + if (lmmx == false) { + int rr; + for (rr = 0; rr < 8; rr++) { + + dest[0] = (int) (source1[0] + source2[0]+1) >> 1; + dest[1] = (int) (source1[1] + source2[1]+1) >> 1; + dest[2] = (int) (source1[2] + source2[2]+1) >> 1; + dest[3] = (int) (source1[3] + source2[3]+1) >> 1; + dest[4] = (int) (source1[4] + source2[4]+1) >> 1; + dest[5] = (int) (source1[5] + source2[5]+1) >> 1; + dest[6] = (int) (source1[6] + source2[6]+1) >> 1; + dest[7] = (int) (source1[7] + source2[7]+1) >> 1; + dest += inc; + source1 += inc; + source2 += inc; + } + } else { + copyFunctions_asm->copy8_div2_nocrop(source1,source2, dest, inc); + } + +} + +void CopyFunctions::copy8_div2_destlinear_nocrop(unsigned char* source1, + unsigned char* source2, + unsigned char* dest,int inc) { + + if (lmmx == false) { + int rr; + for (rr = 0; rr < 8; rr++) { + dest[0] = (int) (source1[0] + source2[0]) >> 1; + dest[1] = (int) (source1[1] + source2[1]) >> 1; + dest[2] = (int) (source1[2] + source2[2]) >> 1; + dest[3] = (int) (source1[3] + source2[3]) >> 1; + dest[4] = (int) (source1[4] + source2[4]) >> 1; + dest[5] = (int) (source1[5] + source2[5]) >> 1; + dest[6] = (int) (source1[6] + source2[6]) >> 1; + dest[7] = (int) (source1[7] + source2[7]) >> 1; + dest += 8; + source1 += inc; + source2 += inc; + } + } else { + copyFunctions_asm->copy8_div2_destlinear_nocrop(source1,source2,dest,inc); + } +} + + +void CopyFunctions::copy16_div2_destlinear_nocrop(unsigned char* source1, + unsigned char* source2, + unsigned char* dest,int inc){ + + if (lmmx == false) { + int rr; + for (rr = 0; rr < 16; rr++) { + dest[0] = (int) (source1[0] + source2[0]) >> 1; + dest[1] = (int) (source1[1] + source2[1]) >> 1; + dest[2] = (int) (source1[2] + source2[2]) >> 1; + dest[3] = (int) (source1[3] + source2[3]) >> 1; + dest[4] = (int) (source1[4] + source2[4]) >> 1; + dest[5] = (int) (source1[5] + source2[5]) >> 1; + dest[6] = (int) (source1[6] + source2[6]) >> 1; + dest[7] = (int) (source1[7] + source2[7]) >> 1; + dest[8] = (int) (source1[8] + source2[8]) >> 1; + dest[9] = (int) (source1[9] + source2[9]) >> 1; + dest[10] = (int) (source1[10] + source2[10]) >> 1; + dest[11] = (int) (source1[11] + source2[11]) >> 1; + dest[12] = (int) (source1[12] + source2[12]) >> 1; + dest[13] = (int) (source1[13] + source2[13]) >> 1; + dest[14] = (int) (source1[14] + source2[14]) >> 1; + dest[15] = (int) (source1[15] + source2[15]) >> 1; + dest += 16; + source1 += inc; + source2 += inc; + } + } else { + copyFunctions_asm->copy16_div2_destlinear_nocrop(source1,source2,dest,inc); + } + +} + + + +void CopyFunctions::copy8_div4_nocrop(unsigned char* source1, + unsigned char* source2, + unsigned char* source3, + unsigned char* source4, + unsigned char* dest,int inc) { + int rr; + + for (rr = 0; rr < 8; rr++) { + dest[0]=(int) (source1[0]+source2[0]+source3[0]+source4[0] + 2) >> 2; + dest[1]=(int) (source1[1]+source2[1]+source3[1]+source4[1] + 2) >> 2; + dest[2]=(int) (source1[2]+source2[2]+source3[2]+source4[2] + 2) >> 2; + dest[3]=(int) (source1[3]+source2[3]+source3[3]+source4[3] + 2) >> 2; + dest[4]=(int) (source1[4]+source2[4]+source3[4]+source4[4] + 2) >> 2; + dest[5]=(int) (source1[5]+source2[5]+source3[5]+source4[5] + 2) >> 2; + dest[6]=(int) (source1[6]+source2[6]+source3[6]+source4[6] + 2) >> 2; + dest[7]=(int) (source1[7]+source2[7]+source3[7]+source4[7] + 2) >> 2; + dest += inc; + source1 += inc; + source2 += inc; + source3 += inc; + source4 += inc; + } +} + +// Optimize me! +// should be mmx perfomance analysis shows: 8 % overall time + +void CopyFunctions::copy8_src2linear_crop(unsigned char* source1, + short int* source2, + unsigned char* dest,int inc) { + int rr; + if (lmmx == false) { + for (rr = 0; rr < 8; rr++) { + dest[0] = cm[(int) source1[0] + (int) source2[0]]; + dest[1] = cm[(int) source1[1] + (int) source2[1]]; + dest[2] = cm[(int) source1[2] + (int) source2[2]]; + dest[3] = cm[(int) source1[3] + (int) source2[3]]; + dest[4] = cm[(int) source1[4] + (int) source2[4]]; + dest[5] = cm[(int) source1[5] + (int) source2[5]]; + dest[6] = cm[(int) source1[6] + (int) source2[6]]; + dest[7] = cm[(int) source1[7] + (int) source2[7]]; + dest += inc; + source1 += inc; + source2 += 8; + } + } else { + copyFunctions_asm->copy8_src2linear_crop(source1,source2,dest,inc); + } + +} + +// Optimize me! +// should be mmx perfomance analysis shows: 13 % overall time +void CopyFunctions::copy8_div2_src3linear_crop(unsigned char* source1, + unsigned char* source2, + short int* source3, + unsigned char* dest,int inc) { + int rr; + if (lmmx==false) { + for (rr = 0; rr < 8; rr++) { + dest[0] = cm[((int) (source1[0] + source2[0]+1) >> 1) + source3[0]]; + dest[1] = cm[((int) (source1[1] + source2[1]+1) >> 1) + source3[1]]; + dest[2] = cm[((int) (source1[2] + source2[2]+1) >> 1) + source3[2]]; + dest[3] = cm[((int) (source1[3] + source2[3]+1) >> 1) + source3[3]]; + dest[4] = cm[((int) (source1[4] + source2[4]+1) >> 1) + source3[4]]; + dest[5] = cm[((int) (source1[5] + source2[5]+1) >> 1) + source3[5]]; + dest[6] = cm[((int) (source1[6] + source2[6]+1) >> 1) + source3[6]]; + dest[7] = cm[((int) (source1[7] + source2[7]+1) >> 1) + source3[7]]; + dest += inc; + source1 += inc; + source2 += inc; + source3 += 8; + + } + } else { + copyFunctions_asm->copy8_div2_src3linear_crop(source1,source2,source3, + dest,inc); + } + + +} + + +void CopyFunctions::copy8_div4_src5linear_crop(unsigned char* source1, + unsigned char* source2, + unsigned char* source3, + unsigned char* source4, + short int* source5, + unsigned char* dest,int inc) { + + int rr; + + for (rr = 0; rr < 8; rr++) { + dest[0]=cm[((int) (source1[0]+source2[0]+source3[0]+source4[0]+2) >> 2) + source5[0]]; + dest[1]=cm[((int) (source1[1]+source2[1]+source3[1]+source4[1]+2) >> 2) + source5[1]]; + dest[2]=cm[((int) (source1[2]+source2[2]+source3[2]+source4[2]+2) >> 2) + source5[2]]; + dest[3]=cm[((int) (source1[3]+source2[3]+source3[3]+source4[3]+2) >> 2) + source5[3]]; + dest[4]=cm[((int) (source1[4]+source2[4]+source3[4]+source4[4]+2) >> 2) + source5[4]]; + dest[5]=cm[((int) (source1[5]+source2[5]+source3[5]+source4[5]+2) >> 2) + source5[5]]; + dest[6]=cm[((int) (source1[6]+source2[6]+source3[6]+source4[6]+2) >> 2) + source5[6]]; + dest[7]=cm[((int) (source1[7]+source2[7]+source3[7]+source4[7]+2) >> 2) + source5[7]]; + dest +=inc; + source1 += inc; + source2 += inc; + source3 += inc; + source4 += inc; + source5 += 8; + } +} diff --git a/mpeglib/lib/mpegplay/copyFunctions.h b/mpeglib/lib/mpegplay/copyFunctions.h new file mode 100644 index 00000000..a1436739 --- /dev/null +++ b/mpeglib/lib/mpegplay/copyFunctions.h @@ -0,0 +1,95 @@ +/* + stores heavily used copy functions (makes mmx support easier) + 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 __COPYFUNCTIONS_H +#define __COPYFUNCTIONS_H + +#define MAX_NEG_CROP 32768 +#define NUM_CROP_ENTRIES (2048+2*MAX_NEG_CROP) + +#include <iostream> +#include "../util/mmx/mmx.h" + +extern "C" { +#include <string.h> +} + +#include "copyFunctions_mmx.h" + + +class CopyFunctions { + + unsigned char *cm; + int lmmx; + unsigned char* cropTbl; + CopyFunctions_ASM* copyFunctions_asm; + + public: + CopyFunctions(); + ~CopyFunctions(); + + /** + We make sure, that during the whole construcion block + we never (!!!) do float operations, thus we move + the time consumin emms call really at the end of + the whole reconstrucion/motion compensation + */ + + void startNOFloatSection(); + void endNOFloatSection(); + + void copy8_byte(unsigned char* source1, + unsigned char* dest,int inc); + + void copy8_word(unsigned short* source1, + unsigned short* dest,int inc); + + + void copy8_div2_nocrop(unsigned char* source1, + unsigned char* source2, + unsigned char* dest,int inc); + + void copy8_div2_destlinear_nocrop(unsigned char* source1, + unsigned char* source2, + unsigned char* dest,int inc); + + void copy16_div2_destlinear_nocrop(unsigned char* source1, + unsigned char* source2, + unsigned char* dest,int inc); + + + void copy8_div4_nocrop(unsigned char* source1, + unsigned char* source2, + unsigned char* source3, + unsigned char* source4, + unsigned char* dest,int inc); + + void copy8_src1linear_crop(short* source1,unsigned char* dest,int inc); + + void copy8_src2linear_crop(unsigned char* source1, + short int* source2, + unsigned char* dest,int inc); + void copy8_div2_src3linear_crop(unsigned char* source1, + unsigned char* source2, + short int* source3, + unsigned char* dest,int inc); + + void copy8_div4_src5linear_crop(unsigned char* source1, + unsigned char* source2, + unsigned char* source3, + unsigned char* source4, + short int* source5, + unsigned char* dest,int inc); + +}; +#endif diff --git a/mpeglib/lib/mpegplay/copyFunctions_asm.cpp b/mpeglib/lib/mpegplay/copyFunctions_asm.cpp new file mode 100644 index 00000000..40d4580f --- /dev/null +++ b/mpeglib/lib/mpegplay/copyFunctions_asm.cpp @@ -0,0 +1,90 @@ +/* + copyfunctions base class + 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 "copyFunctions_asm.h" + +using namespace std; + +CopyFunctions_ASM::CopyFunctions_ASM() { +} + +CopyFunctions_ASM::~CopyFunctions_ASM() { +} + + +int CopyFunctions_ASM::support() { + return false; +} + + +void CopyFunctions_ASM::startNOFloatSection() { +} + + +void CopyFunctions_ASM::endNOFloatSection() { +} + +void CopyFunctions_ASM::copy8_byte(unsigned char* , + unsigned char* ,int ) { + cout << "CopyFunctions_ASM::copy8_byte not implemented"<<endl; +} + + +void CopyFunctions_ASM::copy8_src1linear_crop(short* , + unsigned char* ,int ) { + cout << "CopyFunctions_ASM:: not implemented"<<endl; +} + + + + +void CopyFunctions_ASM::copy8_div2_nocrop(unsigned char* , + unsigned char* , + unsigned char* ,int ) { + cout << "CopyFunctions_ASM:: copy8_div2_nocrop not implemented"<<endl; +} + + +void CopyFunctions_ASM::copy8_div2_destlinear_nocrop(unsigned char* , + unsigned char* , + unsigned char* , + int ) { + cout << "CopyFunctions_ASM:: copy8_div2_destlinear_nocrop not implemented" + <<endl; +} + + +void CopyFunctions_ASM::copy16_div2_destlinear_nocrop(unsigned char* , + unsigned char* , + unsigned char* , + int ) { + cout << "CopyFunctions_ASM:: copy16_div2_destlinear_nocrop not implemented" + <<endl; +} + + +void CopyFunctions_ASM::copy8_src2linear_crop(unsigned char* , + short int* , + unsigned char* ,int ) { + cout << "CopyFunctions_ASM:: copy8_src2linear_crop not implemented"<<endl; +} + + +void CopyFunctions_ASM::copy8_div2_src3linear_crop(unsigned char* , + unsigned char* , + short int* , + unsigned char* , + int ) { + cout << "CopyFunctions_ASM:: copy8_div2_src3linear_crop not implemented" + <<endl; +} diff --git a/mpeglib/lib/mpegplay/copyFunctions_asm.h b/mpeglib/lib/mpegplay/copyFunctions_asm.h new file mode 100644 index 00000000..1156345a --- /dev/null +++ b/mpeglib/lib/mpegplay/copyFunctions_asm.h @@ -0,0 +1,61 @@ +/* + copyfunctions base class + 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 __COPYFUNCTIONS_ASM_H +#define __COPYFUNCTIONS_ASM_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <iostream> + +class CopyFunctions_ASM { + + public: + CopyFunctions_ASM(); + virtual ~CopyFunctions_ASM(); + + virtual int support(); + + virtual void startNOFloatSection(); + virtual void endNOFloatSection(); + + virtual void copy8_byte(unsigned char* source1, + unsigned char* dest,int inc); + + virtual void copy8_src1linear_crop(short* source1, + unsigned char* dest,int inc); + + virtual void copy8_div2_nocrop(unsigned char* source1, + unsigned char* source2, + unsigned char* dest,int inc); + + virtual void copy8_div2_destlinear_nocrop(unsigned char* source1, + unsigned char* source2, + unsigned char* dest,int inc); + + virtual void copy16_div2_destlinear_nocrop(unsigned char* source1, + unsigned char* source2, + unsigned char* dest,int inc); + + virtual void copy8_src2linear_crop(unsigned char* source1, + short int* source2, + unsigned char* dest,int inc); + + virtual void copy8_div2_src3linear_crop(unsigned char* source1, + unsigned char* source2, + short int* source3, + unsigned char* dest,int inc); +}; +#endif diff --git a/mpeglib/lib/mpegplay/copyFunctions_mmx.cpp b/mpeglib/lib/mpegplay/copyFunctions_mmx.cpp new file mode 100644 index 00000000..3e295e76 --- /dev/null +++ b/mpeglib/lib/mpegplay/copyFunctions_mmx.cpp @@ -0,0 +1,313 @@ +/* + copyfunctions implementation in mmx + 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 "copyFunctions_mmx.h" + +using namespace std; + +// mmx goodies +static long ADD_1[] = {0x01010101, 0x01010101}; +static long ADDW_1[] = {0x00010001, 0x00010001}; +static long MASK_AND[] = {0x7f7f7f7f, 0x7f7f7f7f}; + +void dummyCopyFunctions() { + cout << "ADD_1:"<<ADD_1<<endl; + cout << "ADDW_1:"<<ADDW_1<<endl; + cout << "MASK_AND:"<<MASK_AND<<endl; +} + +CopyFunctions_MMX::CopyFunctions_MMX() { +#ifdef INTEL + lmmx=mm_support(); +#else + lmmx=false; + cout << "no INTEL arch- disable MMX in copyFunctions"<<endl; +#endif +} + + +CopyFunctions_MMX::~CopyFunctions_MMX() { +} + +int CopyFunctions_MMX::support() { + return lmmx; +} + + +#if defined (__GNUC__) && defined (INTEL) + +void CopyFunctions_MMX::startNOFloatSection() { +} + + +void CopyFunctions_MMX::endNOFloatSection() { + emms(); +} + + + +void CopyFunctions_MMX::copy8_byte(unsigned char* source1, + unsigned char* dest,int inc) { + int rr=4; + + asm ( + "1:\n" + "movq (%0) ,%%mm0\n" + "leal (%0,%2) ,%0\n" + "movq (%0) ,%%mm1\n" + "leal (%0,%2) ,%0\n" + + // Write + "movq %%mm0 ,(%1)\n" + "leal (%1,%2) ,%1\n" + "movq %%mm1 ,(%1)\n" + "leal (%1,%2) ,%1\n" + + "decl %3\n" + "jnz 1b\n" + : + : "r"(source1),"r"(dest),"r"(inc),"r"(rr) + ); +} + + + +void CopyFunctions_MMX::copy8_src1linear_crop(short* source1, + unsigned char* dest,int inc) { + + asm ( + "movq (%1),%%mm0\n" + "packuswb 8(%1),%%mm0\n" + "movq %%mm0,(%0)\n" + "addl %2,%0\n" + + "movq 16(%1),%%mm0\n" + "packuswb 24(%1),%%mm0\n" + "movq %%mm0,(%0)\n" + "addl %2,%0\n" + + "movq 32(%1),%%mm0\n" + "packuswb 40(%1),%%mm0\n" + "movq %%mm0,(%0)\n" + "addl %2,%0\n" + + "movq 48(%1),%%mm0\n" + "packuswb 56(%1),%%mm0\n" + "movq %%mm0,(%0)\n" + "addl %2,%0\n" + + "movq 64(%1),%%mm0\n" + "packuswb 72(%1),%%mm0\n" + "movq %%mm0,(%0)\n" + "addl %2,%0\n" + + "movq 80(%1),%%mm0\n" + "packuswb 88(%1),%%mm0\n" + "movq %%mm0,(%0)\n" + "addl %2,%0\n" + + "movq 96(%1),%%mm0\n" + "packuswb 104(%1),%%mm0\n" + "movq %%mm0,(%0)\n" + "addl %2,%0\n" + + "movq 112(%1),%%mm0\n" + "packuswb 120(%1),%%mm0\n" + "movq %%mm0,(%0)\n" + : + :"r" (dest), "r" (source1),"r" (inc) + ); + +} + + + +void CopyFunctions_MMX::copy8_div2_nocrop(unsigned char* source1, + unsigned char* source2, + unsigned char* dest,int inc) { + int h=8; + asm ( + "movq MASK_AND, %%mm5\n" + "movq ADD_1, %%mm6\n" + "1:\t" + "movq (%1), %%mm0\n" /* 8 s */ + "movq (%4), %%mm1\n" /* 8 s +lx */ + "psrlw $1,%%mm0\n" + "psrlw $1,%%mm1\n" + "pand %%mm5,%%mm0\n" + "pand %%mm5,%%mm1\n" + "paddusb %%mm1,%%mm0\n" + "addl %3,%1\n" + "paddusb %%mm6,%%mm0\n" + "addl %3,%4\n" + "movq %%mm0,(%2)\n" + "decl %0\n" + "leal (%2, %3), %2\n" + "jnz 1b\n" + : + : "c"(h), "r"(source1), "r"(dest), "r"(inc), "r"(source2) + ); +} + + +void CopyFunctions_MMX::copy8_div2_destlinear_nocrop(unsigned char* source1, + unsigned char* source2, + unsigned char* dest, + int inc) { + int h=8; + asm ( + "movq MASK_AND, %%mm5\n" + "1:\t" + "movq (%1), %%mm0\n" /* 8 s */ + "movq (%4), %%mm1\n" /* 8 s +lx */ + "psrlw $1,%%mm0\n" + "psrlw $1,%%mm1\n" + "pand %%mm5,%%mm0\n" + "pand %%mm5,%%mm1\n" + "paddusb %%mm1,%%mm0\n" + "addl %3,%1\n" + "addl %3,%4\n" + "movq %%mm0,(%2)\n" + "decl %0\n" + "leal 8(%2), %2\n" + "jnz 1b\n" + : + : "c"(h), "r"(source1), "r"(dest), "r"(inc), "r"(source2) + ); +} + + + +void CopyFunctions_MMX::copy16_div2_destlinear_nocrop(unsigned char* source1, + unsigned char* source2, + unsigned char* dest, + int inc) { + int h=16; + inc=inc-8; + asm ( + "movq MASK_AND, %%mm5\n" + "1:\t" + "movq (%1), %%mm0\n" /* 8 s */ + "movq (%4), %%mm1\n" /* 8 s +lx */ + "psrlw $1,%%mm0\n" + "psrlw $1,%%mm1\n" + "pand %%mm5,%%mm0\n" + "pand %%mm5,%%mm1\n" + "paddusb %%mm1,%%mm0\n" + "leal 8(%1),%1\n" + "leal 8(%4),%4\n" + "movq %%mm0,(%2)\n" + "leal 8(%2),%2\n" + + "movq (%1), %%mm0\n" /* 8 s */ + "movq (%4), %%mm1\n" /* 8 s +lx */ + "psrlw $1,%%mm0\n" + "psrlw $1,%%mm1\n" + "pand %%mm5,%%mm0\n" + "pand %%mm5,%%mm1\n" + "paddusb %%mm1,%%mm0\n" + "leal (%3,%1),%1\n" + "leal (%3,%4),%4\n" + "movq %%mm0,(%2)\n" + "leal 8(%2),%2\n" + + "decl %0\n" + "jnz 1b\n" + : + : "c"(h), "r"(source1), "r"(dest), "r"(inc), "r"(source2) + ); +} + + +void CopyFunctions_MMX::copy8_src2linear_crop(unsigned char* source1, + short int* source2, + unsigned char* dest,int inc) { + + int rr=8; + // buggy + + asm ( + ".align 32\n" + "pxor %%mm2 ,%%mm2\n" // 0 0 0 0 0 0 0 0 + "1:\n" + "movq (%0) ,%%mm0\n" // s1_7 s1_6 s1_5 s1_4 s1_3 s1_2 s1_1 s1_0 + "movq (%0) ,%%mm4\n" // s1_7 s1_6 s1_5 s1_4 s1_3 s1_2 s1_1 s1_0 + "punpckhbw %%mm2 ,%%mm0\n" // 0 s1_7 0 s1_6 0 s1_5 0 s1_4 + "punpcklbw %%mm2 ,%%mm4\n" // 0 s1_3 0 s1_2 0 s1_1 0 s1_0 + "movq (%1) ,%%mm1\n" // s23h s23l s22h s22l s21l s21h s20h s20l + "movq 8(%1) ,%%mm5\n" // s27h s27l s26h s26l s25l s25h s24h s24l + "paddw %%mm0 ,%%mm5\n" // mm4=mm4 + s3_0..3 + "paddw %%mm4 ,%%mm1\n" // mm0=mm0 + s3_4..7 + "packuswb %%mm5 ,%%mm1\n" // cm[...] + + "movq %%mm1 ,(%2)\n" // wrote out + + "leal (%0,%3), %0\n" // source1+=inc + "leal 16(%1) , %1\n" // source2+=inc + "leal (%2,%3), %2\n" // dest+=inc + "decl %4\n" + "jnz 1b\n" + //"emms\n" + : + : "r"(source1), "r"(source2), "r"(dest),"r"(inc),"r"(rr) + ); +} + + +void CopyFunctions_MMX::copy8_div2_src3linear_crop(unsigned char* source1, + unsigned char* source2, + short int* source3, + unsigned char* dest, + int inc){ + // buggy + int rr=8; + + asm ( + "pxor %%mm2 ,%%mm2\n" // 0 0 0 0 0 0 0 0 + "pxor %%mm3 ,%%mm3\n" // 0 0 0 0 0 0 0 0 + "movq ADDW_1,%%mm6\n" // 0 1 0 1 0 1 0 1 + "1:\n" + "movq (%0) ,%%mm0\n" // s1_7 s1_6 s1_5 s1_4 s1_3 s1_2 s1_1 s1_0 + "movq (%1) ,%%mm1\n" // s2_7 s2_6 s2_5 s2_4 s2_3 s2_2 s2_1 s2_0 + "movq %%mm0 ,%%mm4\n" // s1_7 s1_6 s1_5 s1_4 s1_3 s1_2 s1_1 s1_0 + "movq %%mm1 ,%%mm5\n" // s2_7 s2_6 s2_5 s2_4 s2_3 s2_2 s2_1 s2_0 + "punpckhbw %%mm2 ,%%mm0\n" // 0 s1_7 0 s1_6 0 s1_5 0 s1_4 + "punpckhbw %%mm3 ,%%mm1\n" // 0 s2_7 0 s2_6 0 s2_5 0 s2_4 + "punpcklbw %%mm2 ,%%mm4\n" // 0 s1_3 0 s1_2 0 s1_1 0 s1_0 + "punpcklbw %%mm3 ,%%mm5\n" // 0 s2_3 0 s2_2 0 s2_1 0 s2_0 + "paddusw %%mm4 ,%%mm5\n" // mm5=s1_0..3 + s2_0..3 + "paddusw %%mm0 ,%%mm1\n" // mm1=s1_4..7 + s2_4..7 + "paddusw %%mm6 ,%%mm5\n" // mm5=mm5 + 1 + "paddusw %%mm6 ,%%mm1\n" // mm1=mm1 + 1 + "psraw $1 ,%%mm1\n" // mm1=mm1/2 + "psraw $1 ,%%mm5\n" // mm5=mm5/2 + "movq (%2) ,%%mm0\n" // s33h s33l s32h s32l s31l s31h s30h s30l + "movq 8(%2) ,%%mm4\n" // s37h s37l s36h s36l s35l s35h s34h s34l + "paddw %%mm0 ,%%mm5\n" // mm5=mm5 + s3_0..3 + "paddw %%mm4 ,%%mm1\n" // mm1=mm1 + s3_4..7 + "packuswb %%mm1 ,%%mm5\n" // cm[...] + "movq %%mm5 ,(%3)\n" // wrote out + "leal (%0,%4), %0\n" // source1+=inc + "leal (%1,%4), %1\n" // source2+=inc + "addl $16 ,%2 \n" // source3+8 + "leal (%3,%4), %3\n" // dest+=inc + "decl %5\n" + "jnz 1b\n" + : + : "r"(source1), "r"(source2), "r"(source3), + "r"(dest),"r"(inc),"m"(rr) + ); +} + + +#endif diff --git a/mpeglib/lib/mpegplay/copyFunctions_mmx.h b/mpeglib/lib/mpegplay/copyFunctions_mmx.h new file mode 100644 index 00000000..36e157be --- /dev/null +++ b/mpeglib/lib/mpegplay/copyFunctions_mmx.h @@ -0,0 +1,68 @@ +/* + copyfunctions implementation in mmx + 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 __COPYFUNCTIONS_MMX_H +#define __COPYFUNCTIONS_MMX_H + +#include "copyFunctions_asm.h" +#include "../util/mmx/mmx.h" + + +class CopyFunctions_MMX : public CopyFunctions_ASM { + + int lmmx; + + public: + CopyFunctions_MMX(); + ~CopyFunctions_MMX(); + + int support(); + +#if defined (__GNUC__) && defined (INTEL) + + void startNOFloatSection(); + void endNOFloatSection(); + + + void copy8_byte(unsigned char* source1, + unsigned char* dest,int inc); + + void copy8_src1linear_crop(short* source1, + unsigned char* dest,int inc); + + void copy8_div2_nocrop(unsigned char* source1, + unsigned char* source2, + unsigned char* dest,int inc); + + void copy8_div2_destlinear_nocrop(unsigned char* source1, + unsigned char* source2, + unsigned char* dest,int inc); + + void copy16_div2_destlinear_nocrop(unsigned char* source1, + unsigned char* source2, + unsigned char* dest,int inc); + + void copy8_src2linear_crop(unsigned char* source1, + short int* source2, + unsigned char* dest,int inc); + + void copy8_div2_src3linear_crop(unsigned char* source1, + unsigned char* source2, + short int* source3, + unsigned char* dest,int inc); + +#endif + +}; +#endif + diff --git a/mpeglib/lib/mpegplay/decoderClass.cpp b/mpeglib/lib/mpegplay/decoderClass.cpp new file mode 100644 index 00000000..e259c8e6 --- /dev/null +++ b/mpeglib/lib/mpegplay/decoderClass.cpp @@ -0,0 +1,893 @@ +/* + class for decoders + 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 "decoderClass.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + + + +#ifndef NDEBUG +#define NDEBUG +#endif +#include <assert.h> + + +#define DEBUG_DECODERCLASS(x) +//#define DEBUG_DECODERCLASS(x) x + +/* Array mapping zigzag to array pointer offset. */ + + +static const int zigzag_direct_nommx[64] = { + 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, + 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, + 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63}; + + +static const int zigzag_direct_mmx[64] = { + + 0*8+0/* 0*/, 1*8+0/* 1*/, 0*8+1/* 8*/, 0*8+2/*16*/, 1*8+1/* 9*/, 2*8+0/* 2*/, 3*8+0/* 3*/, 2*8+1/*10*/, + 1*8+2/*17*/, 0*8+3/*24*/, 0*8+4/*32*/, 1*8+3/*25*/, 2*8+2/*18*/, 3*8+1/*11*/, 4*8+0/* 4*/, 5*8+0/* 5*/, + 4*8+1/*12*/, 5*8+2/*19*/, 2*8+3/*26*/, 1*8+4/*33*/, 0*8+5/*40*/, 0*8+6/*48*/, 1*8+5/*41*/, 2*8+4/*34*/, + 3*8+3/*27*/, 4*8+2/*20*/, 5*8+1/*13*/, 6*8+0/* 6*/, 7*8+0/* 7*/, 6*8+1/*14*/, 5*8+2/*21*/, 4*8+3/*28*/, + 3*8+4/*35*/, 2*8+5/*42*/, 1*8+6/*49*/, 0*8+7/*56*/, 1*8+7/*57*/, 2*8+6/*50*/, 3*8+5/*43*/, 4*8+4/*36*/, + 5*8+3/*29*/, 6*8+2/*22*/, 7*8+1/*15*/, 7*8+2/*23*/, 6*8+3/*30*/, 5*8+4/*37*/, 4*8+5/*44*/, 3*8+6/*51*/, + 2*8+7/*58*/, 3*8+7/*59*/, 4*8+6/*52*/, 5*8+5/*45*/, 6*8+4/*38*/, 7*8+3/*31*/, 7*8+4/*39*/, 6*8+5/*46*/, + 7*8+6/*53*/, 4*8+7/*60*/, 5*8+7/*61*/, 6*8+6/*54*/, 7*8+5/*47*/, 7*8+6/*55*/, 6*8+7/*62*/, 7*8+7/*63*/ +}; + + + + + +/* Bit masks used by bit i/o operations. */ + + + +static unsigned int bitMask[] = {0xffffffff,0x7fffffff,0x3fffffff,0x1fffffff, + 0x0fffffff, 0x07ffffff, 0x03ffffff, 0x01ffffff, + 0x00ffffff, 0x007fffff, 0x003fffff, 0x001fffff, + 0x000fffff, 0x0007ffff, 0x0003ffff, 0x0001ffff, + 0x0000ffff, 0x00007fff, 0x00003fff, 0x00001fff, + 0x00000fff, 0x000007ff, 0x000003ff, 0x000001ff, + 0x000000ff, 0x0000007f, 0x0000003f, 0x0000001f, + 0x0000000f, 0x00000007, 0x00000003, 0x00000001}; + +static unsigned int rBitMask[] = {0xffffffff,0xfffffffe,0xfffffffc,0xfffffff8, + 0xfffffff0, 0xffffffe0, 0xffffffc0, 0xffffff80, + 0xffffff00, 0xfffffe00, 0xfffffc00, 0xfffff800, + 0xfffff000, 0xffffe000, 0xffffc000, 0xffff8000, + 0xffff0000, 0xfffe0000, 0xfffc0000, 0xfff80000, + 0xfff00000, 0xffe00000, 0xffc00000, 0xff800000, + 0xff000000, 0xfe000000, 0xfc000000, 0xf8000000, + 0xf0000000, 0xe0000000, 0xc0000000, 0x80000000}; + +static unsigned int bitTest[] = { 0x80000000,0x40000000,0x20000000,0x10000000, + 0x08000000, 0x04000000, 0x02000000, 0x01000000, + 0x00800000, 0x00400000, 0x00200000, 0x00100000, + 0x00080000, 0x00040000, 0x00020000, 0x00010000, + 0x00008000, 0x00004000, 0x00002000, 0x00001000, + 0x00000800, 0x00000400, 0x00000200, 0x00000100, + 0x00000080, 0x00000040, 0x00000020, 0x00000010, + 0x00000008, 0x00000004, 0x00000002, 0x00000001}; + + + + + +DecoderClass::DecoderClass(VideoDecoder* vid_stream, + MpegVideoStream* mpegVideoStream) { + + this->vid_stream=vid_stream; + this->mpegVideoStream=mpegVideoStream; + + +#ifdef INTEL + lmmx=mm_support(); +#else + lmmx=false; + DEBUG_DECODERCLASS(cout << "no INTEL arch- disable MMX in decoderClass"<<endl;) + +#endif + + if (lmmx==true) { + lmmx=4; + } + + int i; + for(i=0;i<64;i++) { + zigzag_direct[i]=zigzag_direct_nommx[i]; + } + if (lmmx) { + for(i=0;i<64;i++) { + // they are different !!! + zigzag_direct[i]=zigzag_direct_mmx[i]; + } + } + for(i=64;i<256;i++) { + zigzag_direct[i]=0; + } + resetDCT(); + reconptr = dct_recon[0]; + +} + + +DecoderClass::~DecoderClass() { +} + + + +int DecoderClass::decodeDCTDCSizeLum() { + unsigned int macro_val; + unsigned int index; + index=mpegVideoStream->showBits(5); + if (index < 31) { + macro_val = dct_dc_size_luminance[index].value; + mpegVideoStream->flushBits(dct_dc_size_luminance[index].num_bits); + } else { + index=mpegVideoStream->showBits(9); + index -= 0x1f0; + macro_val = dct_dc_size_luminance1[index].value; + mpegVideoStream->flushBits(dct_dc_size_luminance1[index].num_bits); + } + return macro_val; +} + + +int DecoderClass::decodeDCTDCSizeChrom() { + unsigned int macro_val; + unsigned int index; + index=mpegVideoStream->showBits(5); + if (index < 31) { + macro_val = dct_dc_size_chrominance[index].value; + mpegVideoStream->flushBits(dct_dc_size_chrominance[index].num_bits); + }else { + index=mpegVideoStream->showBits(10); + index -= 0x3e0; + macro_val = dct_dc_size_chrominance1[index].value; + mpegVideoStream->flushBits(dct_dc_size_chrominance1[index].num_bits); + } + return macro_val; +} + +/* + *-------------------------------------------------------------- + * + * DecodeMBAddrInc -- + * + * Huffman DecoderClass for macro_block_address_increment; the location + * in which the result will be placed is being passed as argument. + * The decoded value is obtained by doing a table lookup on + * mb_addr_inc. + * + * Results: + * The decoded value for macro_block_address_increment or MPGDECODE_ERROR + * for unbound values will be placed in the location specified. + * + * Side effects: + * Bit stream is irreversibly parsed. + * + *-------------------------------------------------------------- + */ +int DecoderClass::decodeMBAddrInc() { + unsigned int index; + int val; + index=mpegVideoStream->showBits(11); + val = mb_addr_inc[index].value; + mpegVideoStream->flushBits(mb_addr_inc[index].num_bits); + if (mb_addr_inc[index].num_bits==0) { + DEBUG_DECODERCLASS(cout<<"num_bits==0"<<endl;) + val=1; + } + + if (val == -1) { + DEBUG_DECODERCLASS(cout <<"EROR: decodeMBAddrInc"<<endl;) + val=MB_STUFFING; + } + return val; + +} + + +/* + *-------------------------------------------------------------- + * + * DecodeMotionVectors -- + * + * Huffman DecoderClass for the various motion vectors, including + * motion_horizontal_forward_code, motion_vertical_forward_code, + * motion_horizontal_backward_code, motion_vertical_backward_code. + * Location where the decoded result will be placed is being passed + * as argument. The decoded values are obtained by doing a table + * lookup on motion_vectors. + * + * Results: + * The decoded value for the motion vector or MPGDECODE_ERROR for unbound + * values will be placed in the location specified. + * + * Side effects: + * Bit stream is irreversibly parsed. + * + *-------------------------------------------------------------- + */ +int DecoderClass::decodeMotionVectors() { + unsigned int index; + int value; + index=mpegVideoStream->showBits(11); + value = motion_vectors[index].code; + + mpegVideoStream->flushBits(motion_vectors[index].num_bits); + return value; +} + + +/* + *-------------------------------------------------------------- + * + * DecodeCBP -- + * + * Huffman DecoderClass for coded_block_pattern; location in which the + * decoded result will be placed is being passed as argument. The + * decoded values are obtained by doing a table lookup on + * coded_block_pattern. + * + * Results: + * The decoded value for coded_block_pattern or MPGDECODE_ERROR for unbound + * values will be placed in the location specified. + * + * Side effects: + * Bit stream is irreversibly parsed. + * + *-------------------------------------------------------------- + */ +int DecoderClass::decodeCBP() { + unsigned int index; + unsigned int coded_bp; + index=mpegVideoStream->showBits(9); + coded_bp = coded_block_pattern[index].cbp; + mpegVideoStream->flushBits(coded_block_pattern[index].num_bits); + return coded_bp; +} + + + + + + + +/* + *-------------------------------------------------------------- + * + * DecodeMBTypeB -- + * + * Huffman Decoder for macro_block_type in bidirectionally-coded + * pictures;locations in which the decoded results: macroblock_quant, + * macroblock_motion_forward, macro_block_motion_backward, + * macroblock_pattern, macro_block_intra, will be placed are + * being passed as argument. The decoded values are obtained by + * doing a table lookup on mb_type_B. + * + * Results: + * The various decoded values for macro_block_type in + * bidirectionally-coded pictures or MPGDECODE_ERROR for unbound values will + * be placed in the locations specified. + * + * Side effects: + * Bit stream is irreversibly parsed. + * + *-------------------------------------------------------------- + */ +void DecoderClass::decodeMBTypeB(int& quant,int& motion_fwd, + int& motion_bwd,int& pat,int& intra){ + unsigned int index; + + index=mpegVideoStream->showBits(6); + + quant = mb_type_B[index].mb_quant; + motion_fwd = mb_type_B[index].mb_motion_forward; + motion_bwd = mb_type_B[index].mb_motion_backward; + pat = mb_type_B[index].mb_pattern; + intra = mb_type_B[index].mb_intra; + if (index == 0) { + DEBUG_DECODERCLASS(cout << "error in decodeMBTypeB"<<endl;) + } + mpegVideoStream->flushBits(mb_type_B[index].num_bits); +} + + +/* + *-------------------------------------------------------------- + * + * DecodeMBTypeI -- + * + * Huffman Decoder for macro_block_type in intra-coded pictures; + * locations in which the decoded results: macroblock_quant, + * macroblock_motion_forward, macro_block_motion_backward, + * macroblock_pattern, macro_block_intra, will be placed are + * being passed as argument. + * + * Results: + * The various decoded values for macro_block_type in intra-coded + * pictures or MPGDECODE_ERROR for unbound values will be placed in the + * locations specified. + * + * Side effects: + * Bit stream is irreversibly parsed. + * + *-------------------------------------------------------------- + */ +void DecoderClass::decodeMBTypeI(int& quant,int& motion_fwd, + int& motion_bwd,int& pat,int& intra) { + + unsigned int index; + static int quantTbl[4] = {MPGDECODE_ERROR, 1, 0, 0}; + + index=mpegVideoStream->showBits(2); + + motion_fwd = 0; + motion_bwd = 0; + pat = 0; + intra = 1; + quant = quantTbl[index]; + if (quant == MPGDECODE_ERROR) { + DEBUG_DECODERCLASS(cout << "decodeMBTypeI Error"<<endl;) + } + if (index) { + mpegVideoStream->flushBits (1 + quant); + } + +} + + + +/* + *-------------------------------------------------------------- + * + * DecodeMBTypeP -- + * + * Huffman Decoder for macro_block_type in predictive-coded pictures; + * locations in which the decoded results: macroblock_quant, + * macroblock_motion_forward, macro_block_motion_backward, + * macroblock_pattern, macro_block_intra, will be placed are + * being passed as argument. The decoded values are obtained by + * doing a table lookup on mb_type_P. + * + * Results: + * The various decoded values for macro_block_type in + * predictive-coded pictures or MPGDECODE_ERROR for unbound values will be + * placed in the locations specified. + * + * Side effects: + * Bit stream is irreversibly parsed. + * + *-------------------------------------------------------------- + */ +void DecoderClass::decodeMBTypeP(int& quant,int& motion_fwd, + int& motion_bwd,int& pat,int& intra) { + + unsigned int index; + + index=mpegVideoStream->showBits(6); + + quant = mb_type_P[index].mb_quant; + motion_fwd = mb_type_P[index].mb_motion_forward; + motion_bwd = mb_type_P[index].mb_motion_backward; + pat = mb_type_P[index].mb_pattern; + intra = mb_type_P[index].mb_intra; + if (index == 0) { + DEBUG_DECODERCLASS(cout << "error in decodeMBTypeP"<<endl;) + } + mpegVideoStream->flushBits(mb_type_P[index].num_bits); +} + +/* + *-------------------------------------------------------------- + * + * decodeDCTCoeff -- + * + * Huffman Decoder for dct_coeff_first and dct_coeff_next; + * locations where the results of decoding: run and level, are to + * be placed and also the type of DCT coefficients, either + * dct_coeff_first or dct_coeff_next, are being passed as argument. + * + * The decoder first examines the next 8 bits in the input stream, + * and perform according to the following cases: + * + * '0000 0000' - examine 8 more bits (i.e. 16 bits total) and + * perform a table lookup on dct_coeff_tbl_0. + * One more bit is then examined to determine the sign + * of level. + * + * '0000 0001' - examine 4 more bits (i.e. 12 bits total) and + * perform a table lookup on dct_coeff_tbl_1. + * One more bit is then examined to determine the sign + * of level. + * + * '0000 0010' - examine 2 more bits (i.e. 10 bits total) and + * perform a table lookup on dct_coeff_tbl_2. + * One more bit is then examined to determine the sign + * of level. + * + * '0000 0011' - examine 2 more bits (i.e. 10 bits total) and + * perform a table lookup on dct_coeff_tbl_3. + * One more bit is then examined to determine the sign + * of level. + * + * otherwise - perform a table lookup on dct_coeff_tbl. If the + * value of run is not ESCAPE, extract one more bit + * to determine the sign of level; otherwise 6 more + * bits will be extracted to obtain the actual value + * of run , and then 8 or 16 bits to get the value of level. + * + * + * + * Results: + * The decoded values of run and level or MPGDECODE_ERROR + * for unbound values + * are placed in the locations specified. + * + * Side effects: + * Bit stream is irreversibly parsed. + * + *-------------------------------------------------------------- + */ + +void DecoderClass::decodeDCTCoeff(unsigned short int* dct_coeff_tbl, + unsigned RUNTYPE& run,int& level) { + + + unsigned int temp, index; + unsigned int value, next32bits, flushed; + + /* + * Grab the next 32 bits and use it to improve performance of + * getting the bits to parse. Thus, calls are translated as: + * + * show_bitsX <--> next32bits >> (32-X) + * get_bitsX <--> val = next32bits >> (32-flushed-X); + * flushed += X; + * next32bits &= bitMask[flushed]; + * flush_bitsX <--> flushed += X; + * next32bits &= bitMask[flushed]; + * + */ + next32bits=mpegVideoStream->showBits32(); + + flushed = 0; + + /* show_bits8(index); */ + index = next32bits >> 24; + + if (index > 3) { + value = dct_coeff_tbl[index]; + run = (value & RUN_MASK) >> RUN_SHIFT; + if (run == END_OF_BLOCK) { + level = END_OF_BLOCK; + } + else { + /* num_bits = (value & NUM_MASK) + 1; */ + /* flush_bits(num_bits); */ + flushed = (value & NUM_MASK) + 1; + next32bits &= bitMask[flushed]; + if (run != ESCAPE) { + level = (value & LEVEL_MASK) >> LEVEL_SHIFT; + /* get_bits1(value); */ + /* if (value) *level = -*level; */ + if (next32bits >> (31-flushed)) level = -level; + flushed++; + /* next32bits &= bitMask[flushed]; last op before update */ + } + else { /* *run == ESCAPE */ + /* get_bits14(temp); */ + temp = next32bits >> (18-flushed); + flushed += 14; + next32bits &= bitMask[flushed]; + run = temp >> 8; + temp &= 0xff; + if (temp == 0) { + /* get_bits8(*level); */ + level = next32bits >> (24-flushed); + flushed += 8; + /* next32bits &= bitMask[flushed]; last op before update */ + assert(level >= 128); + } else if (temp != 128) { + /* Grab sign bit */ + level = ((int) (temp << 24)) >> 24; + } else { + /* get_bits8(*level); */ + level = next32bits >> (24-flushed); + flushed += 8; + /* next32bits &= bitMask[flushed]; last op before update */ + level = level - 256; + assert(level <= -128 && level >= -255); + } + } + /* Update bitstream... */ + mpegVideoStream->flushBitsDirect(flushed); + } + } + else { + if (index == 2) { + /* show_bits10(index); */ + index = next32bits >> 22; + value = dct_coeff_tbl_2[index & 3]; + } + else if (index == 3) { + /* show_bits10(index); */ + index = next32bits >> 22; + value = dct_coeff_tbl_3[index & 3]; + } + else if (index) { /* index == 1 */ + /* show_bits12(index); */ + index = next32bits >> 20; + value = dct_coeff_tbl_1[index & 15]; + } + else { /* index == 0 */ + /* show_bits16(index); */ + index = next32bits >> 16; + value = dct_coeff_tbl_0[index & 255]; + } + run = (value & RUN_MASK) >> RUN_SHIFT; + level = (value & LEVEL_MASK) >> LEVEL_SHIFT; + + /* + * Fold these operations together to make it fast... + */ + /* num_bits = (value & NUM_MASK) + 1; */ + /* flush_bits(num_bits); */ + /* get_bits1(value); */ + /* if (value) *level = -*level; */ + + flushed = (value & NUM_MASK) + 2; + if ((next32bits >> (32-flushed)) & 0x1) level = -level; + + /* Update bitstream ... */ + mpegVideoStream->flushBitsDirect(flushed); + + } + +} + + +void DecoderClass::resetDCT() { + /* Reset past dct dc y, cr, and cb values. */ + + dct_dc_y_past = 1024 << 3; + dct_dc_cr_past = 1024 << 3; + dct_dc_cb_past = 1024 << 3; + +} + + + +/* + *-------------------------------------------------------------- + * + * ParseReconBlock -- + * + * Parse values for block structure from bitstream. + * n is an indication of the position of the block within + * the macroblock (i.e. 0-5) and indicates the type of + * block (i.e. luminance or chrominance). Reconstructs + * coefficients from values parsed and puts in + * block.dct_recon array in vid stream structure. + * sparseFlag is set when the block contains only one + * coeffictient and is used by the IDCT. + * + * Results: + * + * + * Side effects: + * Bit stream irreversibly parsed. + * + *-------------------------------------------------------------- + */ + + +void DecoderClass::ParseReconBlock(int& n,int& mb_intra, + unsigned int& qscale, + int& lflag, + unsigned int* iqmatrixptr, + unsigned int* niqmatrixptr) { + + + + + int coeffCount=0; + if (mpegVideoStream->hasBytes(512) == false) { + DEBUG_DECODERCLASS(cout << "cannot get 512 raw bytes"<<endl;) + return; + } + + { + /* + * Copy the VideoDecoder fields curBits, bitOffset, and bitBuffer + * into local variables with the same names, so the macros use the + * local variables instead. This allows register allocation and + * can provide 1-2 fps speedup. On machines with not so many registers, + * don't do this. + */ + int size, pos, coeff; + int level; + unsigned RUNTYPE run; + unsigned RUNTYPE i; + + + memset((char *) dct_recon, 0, 64*sizeof(short int)); + + if (mb_intra) { + + if (n < 4) { + + /* + * Get the luminance bits. This code has been hand optimized to + * get by the normal bit parsing routines. We get some speedup + * by grabbing the next 16 bits and parsing things locally. + * Thus, calls are translated as: + * + * show_bitsX <--> next16bits >> (16-X) + * get_bitsX <--> val = next16bits >> (16-flushed-X); + * flushed += X; + * next16bits &= bitMask[flushed]; + * flush_bitsX <--> flushed += X; + * next16bits &= bitMask[flushed]; + * + * I've streamlined the code a lot, so that we don't have to mask + * out the low order bits and a few of the extra adds are removed. + * bsmith + */ + unsigned int next16bits, index, flushed; + next16bits=mpegVideoStream->showBits16(); + + index = next16bits >> (16-5); + if (index < 31) { + size = dct_dc_size_luminance[index].value; + flushed = dct_dc_size_luminance[index].num_bits; + } else { + index = next16bits >> (16-9); + index -= 0x1f0; + size = dct_dc_size_luminance1[index].value; + flushed = dct_dc_size_luminance1[index].num_bits; + } + next16bits &= bitMask[(16+flushed)&0x1f]; + if (size != 0) { + flushed += size; + coeff = next16bits >> (16-flushed); + if (!(coeff & bitTest[32-size])) { + coeff++; + coeff|= rBitMask[size&0x1f]; + } + coeff <<= 3; + } else { + coeff = 0; + } + mpegVideoStream->flushBitsDirect(flushed); + + if ( (n == 0) && (lflag) ) { + coeff += 1024; + } else { + coeff += dct_dc_y_past; + } + dct_dc_y_past = coeff; + + } else { /* n = 4 or 5 */ + /* + * Get the chrominance bits. This code has been hand optimized to + * as described above + */ + + unsigned int next16bits, index, flushed; + next16bits=mpegVideoStream->showBits16(); + + index = next16bits >> (16-5); + if (index < 31) { + size = dct_dc_size_chrominance[index].value; + flushed = dct_dc_size_chrominance[index].num_bits; + } else { + index = next16bits >> (16-10); + index -= 0x3e0; + size = dct_dc_size_chrominance1[index].value; + flushed = dct_dc_size_chrominance1[index].num_bits; + } + next16bits &= bitMask[(16+flushed)&0x1f]; + + if (size != 0) { + flushed += size; + coeff = next16bits >> (16-flushed); + if (!(coeff & bitTest[32-size])) { + coeff++; + coeff|=rBitMask[size&0x1f]; + } + coeff <<= 3; + } else { + coeff = 0; + } + mpegVideoStream->flushBitsDirect(flushed); + + /* We test 5 first; a result of the mixup of Cr and Cb */ + + if (n == 5) { + if (lflag) { + coeff += 1024; + } else { + coeff += dct_dc_cr_past; + } + dct_dc_cr_past = coeff; + } else { + if (lflag) { + coeff += 1024; + } else { + coeff += dct_dc_cb_past; + } + dct_dc_cb_past = coeff; + } + } + + coeff <<= lmmx; + reconptr[0] = coeff; + + pos=0; + i = 0; + coeffCount = (coeff != 0); + + + // we never have d_types so there is no check + + + while(1) { + decodeDCTCoeff(dct_coeff_next,run,level); + + if (run >=END_OF_BLOCK) { + break; + } + i++; + i+=run; + pos = zigzag_direct[i&0x3f]; + + + coeff = (level * qscale * iqmatrixptr[pos]) >> 3 ; + + if (level < 0) { + coeff += (1 - (coeff & 1)); + } else { + coeff -= (1 - (coeff & 1)); + } + + coeff <<= lmmx; + + reconptr[pos] = coeff; + coeffCount++; + + } + mpegVideoStream->flushBitsDirect(2); + + goto end; + + } else { /* non-intra-coded macroblock */ + + decodeDCTCoeff(dct_coeff_first,run,level); + i = run; + + pos = zigzag_direct[i&0x3f]; + + /* quantizes and oddifies each coefficient */ + if (level < 0) { + coeff = ((level - 1) * qscale * niqmatrixptr[pos]) >>3; + if ((coeff & 1) == 0) {coeff++;} + } else { + coeff = ((level + 1) * qscale * niqmatrixptr[pos]) >>3; + coeff = (coeff-1) | 1; + } + + coeff <<= lmmx; + + reconptr[pos] = coeff; + coeffCount = (coeff!=0); + + // we never have d_type pictures here, we do not support them + + while(1) { + decodeDCTCoeff(dct_coeff_next,run,level); + + if (run >= END_OF_BLOCK) { + break; + } + i++; + i+=run; + pos = zigzag_direct[i&0x3f]; + + if (level < 0) { + coeff = ((level - 1) * qscale * niqmatrixptr[pos]) >>3; + if ((coeff & 1) == 0) {coeff++;} + } else { + coeff = ((level + 1) * qscale * niqmatrixptr[pos]) >> 3; + coeff = (coeff-1) | 1; + } + + coeff <<= lmmx; + + reconptr[pos] = coeff; + coeffCount++; + } /* end while */ + + mpegVideoStream->flushBitsDirect(2); + goto end; + } + + end: + if (coeffCount == 1) { + if (lmmx) { + emms(); + reconptr[pos]>>=lmmx; + j_rev_dct_sparse (reconptr, pos); + //IDCT_mmx(reconptr); + } else { + j_rev_dct_sparse (reconptr, pos); + } + + } else { + + if (lmmx) { + IDCT_mmx(reconptr); + } else { + j_rev_dct(reconptr); + } + + } + } + + // we call this at the edn of the "critical sections" + /* + if (lmmx) { + emms(); + } + */ + + return; + +} + + + + + +void DecoderClass::print() { + int i; + for(i=0;i<64;i++) { + printf(" %d ",zigzag_direct[i]); + } + printf("\n"); +} + + + + + + + + + + + + + + + + + + diff --git a/mpeglib/lib/mpegplay/decoderClass.h b/mpeglib/lib/mpegplay/decoderClass.h new file mode 100644 index 00000000..2e969edc --- /dev/null +++ b/mpeglib/lib/mpegplay/decoderClass.h @@ -0,0 +1,96 @@ +/* + class for decoders + 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 __DECODERCLASS_H +#define __DECODERCLASS_H + + + +#include "videoDecoder.h" +#include "mpegVideoStream.h" +#include "decoderTables.h" +#include "slice.h" +#include "proto.h" +#include "../util/mmx/mmx.h" +#include "mmxidct.h" +#include "picture.h" + +/* Special values for DCT Coefficients */ +#define END_OF_BLOCK 62 +#define ESCAPE 61 + + +/* DCT coeff tables. */ +#define RUN_MASK 0xfc00 +#define LEVEL_MASK 0x03f0 +#define NUM_MASK 0x000f +#define RUN_SHIFT 10 +#define LEVEL_SHIFT 4 +#define RUNTYPE char + +class DecoderClass { + + int lmmx; + int zigzag_direct[256]; + + /* Block structure. */ + + short int dct_recon[8][8]; /* Reconstructed dct coeff matrix. */ + int dct_dc_y_past; /* Past lum. dc dct coefficient. */ + int dct_dc_cr_past; /* Past cr dc dct coefficient. */ + int dct_dc_cb_past; /* Past cb dc dct coefficient. */ + short int *reconptr; /* reconptr = dct_recon[0]; */ + + class VideoDecoder* vid_stream; + class MpegVideoStream* mpegVideoStream; + public: + DecoderClass(class VideoDecoder* vid_stream, + class MpegVideoStream* mpegVideoStream); + ~DecoderClass(); + int decodeDCTDCSizeLum(); + int decodeDCTDCSizeChrom(); + int decodeMotionVectors(); + int decodeCBP(); + + inline short int* getDCT() { return ((short int*) &(dct_recon[0][0]));} + void resetDCT(); + + void decodeMBTypeB(int& quant,int& motion_fwd, + int& motion_bwd,int& pat,int& intra); + + void decodeMBTypeI(int& quant,int& motion_fwd, + int& motion_bwd,int& pat,int& intra); + + void decodeMBTypeP(int& quant,int& motion_fwd, + int& motion_bwd,int& pat,int& intra); + + void ParseReconBlock(int& n,int& mb_intra,unsigned int& quant_scale, + int& lflag, + unsigned int* iqmatrixptr, + unsigned int* niqmatrixptr); + int decodeMBAddrInc(); + + + void print(); + + private: + + + inline void decodeDCTCoeff(unsigned short int* dct_coeff_tbl, + unsigned RUNTYPE& run, + int& level); + + + +}; +#endif diff --git a/mpeglib/lib/mpegplay/decoderTables.cpp b/mpeglib/lib/mpegplay/decoderTables.cpp new file mode 100644 index 00000000..9ada4901 --- /dev/null +++ b/mpeglib/lib/mpegplay/decoderTables.cpp @@ -0,0 +1,594 @@ +/* + * decoders.c + * + * This file contains all the routines for Huffman decoding required in + * MPEG + * + */ + + +#include "decoderTables.h" + +using namespace std; + + +/* Decoding table for macroblock_address_increment */ +mb_addr_inc_entry mb_addr_inc[2048]; + +/* Decoding table for macroblock_type in predictive-coded pictures */ +mb_type_entry mb_type_P[64]; + +/* Decoding table for macroblock_type in bidirectionally-coded pictures */ +mb_type_entry mb_type_B[64]; + +/* Decoding table for motion vectors */ +motion_vectors_entry motion_vectors[2048]; + +/* Decoding table for coded_block_pattern */ + +coded_block_pattern_entry coded_block_pattern[512] = +{ {(unsigned int)MPGDECODE_ERROR, 0}, {(unsigned int)MPGDECODE_ERROR, 0}, {39, 9}, {27, 9}, {59, 9}, {55, 9}, {47, 9}, {31, 9}, + {58, 8}, {58, 8}, {54, 8}, {54, 8}, {46, 8}, {46, 8}, {30, 8}, {30, 8}, + {57, 8}, {57, 8}, {53, 8}, {53, 8}, {45, 8}, {45, 8}, {29, 8}, {29, 8}, + {38, 8}, {38, 8}, {26, 8}, {26, 8}, {37, 8}, {37, 8}, {25, 8}, {25, 8}, + {43, 8}, {43, 8}, {23, 8}, {23, 8}, {51, 8}, {51, 8}, {15, 8}, {15, 8}, + {42, 8}, {42, 8}, {22, 8}, {22, 8}, {50, 8}, {50, 8}, {14, 8}, {14, 8}, + {41, 8}, {41, 8}, {21, 8}, {21, 8}, {49, 8}, {49, 8}, {13, 8}, {13, 8}, + {35, 8}, {35, 8}, {19, 8}, {19, 8}, {11, 8}, {11, 8}, {7, 8}, {7, 8}, + {34, 7}, {34, 7}, {34, 7}, {34, 7}, {18, 7}, {18, 7}, {18, 7}, {18, 7}, + {10, 7}, {10, 7}, {10, 7}, {10, 7}, {6, 7}, {6, 7}, {6, 7}, {6, 7}, + {33, 7}, {33, 7}, {33, 7}, {33, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, + {9, 7}, {9, 7}, {9, 7}, {9, 7}, {5, 7}, {5, 7}, {5, 7}, {5, 7}, + {63, 6}, {63, 6}, {63, 6}, {63, 6}, {63, 6}, {63, 6}, {63, 6}, {63, 6}, + {3, 6}, {3, 6}, {3, 6}, {3, 6}, {3, 6}, {3, 6}, {3, 6}, {3, 6}, + {36, 6}, {36, 6}, {36, 6}, {36, 6}, {36, 6}, {36, 6}, {36, 6}, {36, 6}, + {24, 6}, {24, 6}, {24, 6}, {24, 6}, {24, 6}, {24, 6}, {24, 6}, {24, 6}, + {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, + {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, + {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, + {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, + {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, + {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, + {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, + {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, + {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, + {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, + {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, + {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, + {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, + {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, + {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, + {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, + {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, + {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, + {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, + {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, + {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, + {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, + {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, + {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, + {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, + {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, + {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, + {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, + {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, + {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, + {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, + {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, + {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, + {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, + {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, + {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, + {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, + {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, + {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, + {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, + {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, + {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, + {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, + {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, + {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, + {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, + {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, + {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3} +}; + +/* Decoding tables for dct_dc_size_luminance */ +dct_dc_size_entry dct_dc_size_luminance[32] = +{ {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, + {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, + {0, 3}, {0, 3}, {0, 3}, {0, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, + {4, 3}, {4, 3}, {4, 3}, {4, 3}, {5, 4}, {5, 4}, {6, 5}, {(unsigned int)MPGDECODE_ERROR, 0} +}; + +dct_dc_size_entry dct_dc_size_luminance1[16] = +{ {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, + {8, 7}, {8, 7}, {8, 7}, {8, 7}, {9, 8}, {9, 8}, {10, 9}, {11, 9} +}; + +/* Decoding table for dct_dc_size_chrominance */ +dct_dc_size_entry dct_dc_size_chrominance[32] = +{ {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, + {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, + {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, + {3, 3}, {3, 3}, {3, 3}, {3, 3}, {4, 4}, {4, 4}, {5, 5}, {(unsigned int)MPGDECODE_ERROR, 0} +}; + +dct_dc_size_entry dct_dc_size_chrominance1[32] = +{ {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, + {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, + {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, + {8, 8}, {8, 8}, {8, 8}, {8, 8}, {9, 9}, {9, 9}, {10, 10}, {11, 10} +}; + +/* DCT coeff tables. */ + +unsigned short int dct_coeff_tbl_0[256] = +{ +0xffff, 0xffff, 0xffff, 0xffff, +0xffff, 0xffff, 0xffff, 0xffff, +0xffff, 0xffff, 0xffff, 0xffff, +0xffff, 0xffff, 0xffff, 0xffff, +0x052f, 0x051f, 0x050f, 0x04ff, +0x183f, 0x402f, 0x3c2f, 0x382f, +0x342f, 0x302f, 0x2c2f, 0x7c1f, +0x781f, 0x741f, 0x701f, 0x6c1f, +0x028e, 0x028e, 0x027e, 0x027e, +0x026e, 0x026e, 0x025e, 0x025e, +0x024e, 0x024e, 0x023e, 0x023e, +0x022e, 0x022e, 0x021e, 0x021e, +0x020e, 0x020e, 0x04ee, 0x04ee, +0x04de, 0x04de, 0x04ce, 0x04ce, +0x04be, 0x04be, 0x04ae, 0x04ae, +0x049e, 0x049e, 0x048e, 0x048e, +0x01fd, 0x01fd, 0x01fd, 0x01fd, +0x01ed, 0x01ed, 0x01ed, 0x01ed, +0x01dd, 0x01dd, 0x01dd, 0x01dd, +0x01cd, 0x01cd, 0x01cd, 0x01cd, +0x01bd, 0x01bd, 0x01bd, 0x01bd, +0x01ad, 0x01ad, 0x01ad, 0x01ad, +0x019d, 0x019d, 0x019d, 0x019d, +0x018d, 0x018d, 0x018d, 0x018d, +0x017d, 0x017d, 0x017d, 0x017d, +0x016d, 0x016d, 0x016d, 0x016d, +0x015d, 0x015d, 0x015d, 0x015d, +0x014d, 0x014d, 0x014d, 0x014d, +0x013d, 0x013d, 0x013d, 0x013d, +0x012d, 0x012d, 0x012d, 0x012d, +0x011d, 0x011d, 0x011d, 0x011d, +0x010d, 0x010d, 0x010d, 0x010d, +0x282c, 0x282c, 0x282c, 0x282c, +0x282c, 0x282c, 0x282c, 0x282c, +0x242c, 0x242c, 0x242c, 0x242c, +0x242c, 0x242c, 0x242c, 0x242c, +0x143c, 0x143c, 0x143c, 0x143c, +0x143c, 0x143c, 0x143c, 0x143c, +0x0c4c, 0x0c4c, 0x0c4c, 0x0c4c, +0x0c4c, 0x0c4c, 0x0c4c, 0x0c4c, +0x085c, 0x085c, 0x085c, 0x085c, +0x085c, 0x085c, 0x085c, 0x085c, +0x047c, 0x047c, 0x047c, 0x047c, +0x047c, 0x047c, 0x047c, 0x047c, +0x046c, 0x046c, 0x046c, 0x046c, +0x046c, 0x046c, 0x046c, 0x046c, +0x00fc, 0x00fc, 0x00fc, 0x00fc, +0x00fc, 0x00fc, 0x00fc, 0x00fc, +0x00ec, 0x00ec, 0x00ec, 0x00ec, +0x00ec, 0x00ec, 0x00ec, 0x00ec, +0x00dc, 0x00dc, 0x00dc, 0x00dc, +0x00dc, 0x00dc, 0x00dc, 0x00dc, +0x00cc, 0x00cc, 0x00cc, 0x00cc, +0x00cc, 0x00cc, 0x00cc, 0x00cc, +0x681c, 0x681c, 0x681c, 0x681c, +0x681c, 0x681c, 0x681c, 0x681c, +0x641c, 0x641c, 0x641c, 0x641c, +0x641c, 0x641c, 0x641c, 0x641c, +0x601c, 0x601c, 0x601c, 0x601c, +0x601c, 0x601c, 0x601c, 0x601c, +0x5c1c, 0x5c1c, 0x5c1c, 0x5c1c, +0x5c1c, 0x5c1c, 0x5c1c, 0x5c1c, +0x581c, 0x581c, 0x581c, 0x581c, +0x581c, 0x581c, 0x581c, 0x581c, +}; + +unsigned short int dct_coeff_tbl_1[16] = +{ +0x00bb, 0x202b, 0x103b, 0x00ab, +0x084b, 0x1c2b, 0x541b, 0x501b, +0x009b, 0x4c1b, 0x481b, 0x045b, +0x0c3b, 0x008b, 0x182b, 0x441b, +}; + +unsigned short int dct_coeff_tbl_2[4] = +{ +0x4019, 0x1429, 0x0079, 0x0839, +}; + +unsigned short int dct_coeff_tbl_3[4] = +{ +0x0449, 0x3c19, 0x3819, 0x1029, +}; + +unsigned short int dct_coeff_next[256] = +{ +0xffff, 0xffff, 0xffff, 0xffff, +0xf7d5, 0xf7d5, 0xf7d5, 0xf7d5, +0x0826, 0x0826, 0x2416, 0x2416, +0x0046, 0x0046, 0x2016, 0x2016, +0x1c15, 0x1c15, 0x1c15, 0x1c15, +0x1815, 0x1815, 0x1815, 0x1815, +0x0425, 0x0425, 0x0425, 0x0425, +0x1415, 0x1415, 0x1415, 0x1415, +0x3417, 0x0067, 0x3017, 0x2c17, +0x0c27, 0x0437, 0x0057, 0x2817, +0x0034, 0x0034, 0x0034, 0x0034, +0x0034, 0x0034, 0x0034, 0x0034, +0x1014, 0x1014, 0x1014, 0x1014, +0x1014, 0x1014, 0x1014, 0x1014, +0x0c14, 0x0c14, 0x0c14, 0x0c14, +0x0c14, 0x0c14, 0x0c14, 0x0c14, +0x0023, 0x0023, 0x0023, 0x0023, +0x0023, 0x0023, 0x0023, 0x0023, +0x0023, 0x0023, 0x0023, 0x0023, +0x0023, 0x0023, 0x0023, 0x0023, +0x0813, 0x0813, 0x0813, 0x0813, +0x0813, 0x0813, 0x0813, 0x0813, +0x0813, 0x0813, 0x0813, 0x0813, +0x0813, 0x0813, 0x0813, 0x0813, +0x0412, 0x0412, 0x0412, 0x0412, +0x0412, 0x0412, 0x0412, 0x0412, +0x0412, 0x0412, 0x0412, 0x0412, +0x0412, 0x0412, 0x0412, 0x0412, +0x0412, 0x0412, 0x0412, 0x0412, +0x0412, 0x0412, 0x0412, 0x0412, +0x0412, 0x0412, 0x0412, 0x0412, +0x0412, 0x0412, 0x0412, 0x0412, +0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, +0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, +0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, +0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, +0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, +0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, +0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, +0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, +0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, +0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, +0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, +0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, +0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, +0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, +0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, +0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, +0x0011, 0x0011, 0x0011, 0x0011, +0x0011, 0x0011, 0x0011, 0x0011, +0x0011, 0x0011, 0x0011, 0x0011, +0x0011, 0x0011, 0x0011, 0x0011, +0x0011, 0x0011, 0x0011, 0x0011, +0x0011, 0x0011, 0x0011, 0x0011, +0x0011, 0x0011, 0x0011, 0x0011, +0x0011, 0x0011, 0x0011, 0x0011, +0x0011, 0x0011, 0x0011, 0x0011, +0x0011, 0x0011, 0x0011, 0x0011, +0x0011, 0x0011, 0x0011, 0x0011, +0x0011, 0x0011, 0x0011, 0x0011, +0x0011, 0x0011, 0x0011, 0x0011, +0x0011, 0x0011, 0x0011, 0x0011, +0x0011, 0x0011, 0x0011, 0x0011, +0x0011, 0x0011, 0x0011, 0x0011, +}; + +unsigned short int dct_coeff_first[256] = +{ +0xffff, 0xffff, 0xffff, 0xffff, +0xf7d5, 0xf7d5, 0xf7d5, 0xf7d5, +0x0826, 0x0826, 0x2416, 0x2416, +0x0046, 0x0046, 0x2016, 0x2016, +0x1c15, 0x1c15, 0x1c15, 0x1c15, +0x1815, 0x1815, 0x1815, 0x1815, +0x0425, 0x0425, 0x0425, 0x0425, +0x1415, 0x1415, 0x1415, 0x1415, +0x3417, 0x0067, 0x3017, 0x2c17, +0x0c27, 0x0437, 0x0057, 0x2817, +0x0034, 0x0034, 0x0034, 0x0034, +0x0034, 0x0034, 0x0034, 0x0034, +0x1014, 0x1014, 0x1014, 0x1014, +0x1014, 0x1014, 0x1014, 0x1014, +0x0c14, 0x0c14, 0x0c14, 0x0c14, +0x0c14, 0x0c14, 0x0c14, 0x0c14, +0x0023, 0x0023, 0x0023, 0x0023, +0x0023, 0x0023, 0x0023, 0x0023, +0x0023, 0x0023, 0x0023, 0x0023, +0x0023, 0x0023, 0x0023, 0x0023, +0x0813, 0x0813, 0x0813, 0x0813, +0x0813, 0x0813, 0x0813, 0x0813, +0x0813, 0x0813, 0x0813, 0x0813, +0x0813, 0x0813, 0x0813, 0x0813, +0x0412, 0x0412, 0x0412, 0x0412, +0x0412, 0x0412, 0x0412, 0x0412, +0x0412, 0x0412, 0x0412, 0x0412, +0x0412, 0x0412, 0x0412, 0x0412, +0x0412, 0x0412, 0x0412, 0x0412, +0x0412, 0x0412, 0x0412, 0x0412, +0x0412, 0x0412, 0x0412, 0x0412, +0x0412, 0x0412, 0x0412, 0x0412, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +0x0010, 0x0010, 0x0010, 0x0010, +}; + +/* Macro for filling up the decoding table for mb_addr_inc */ +#define ASSIGN1(start, end, step, val, num) \ + for (i = start; i < end; i+= step) { \ + for (j = 0; j < step; j++) { \ + mb_addr_inc[i+j].value = val; \ + mb_addr_inc[i+j].num_bits = num; \ + } \ + val--; \ + } + + + +/* + *-------------------------------------------------------------- + * + * init_mb_addr_inc -- + * + * Initialize the VLC decoding table for macro_block_address_increment + * + * Results: + * The decoding table for macro_block_address_increment will + * be filled; illegal values will be filled as MPGDECODE_ERROR. + * + * Side effects: + * The global array mb_addr_inc will be filled. + * + *-------------------------------------------------------------- + */ +static void init_mb_addr_inc() +{ + int i, j, val; + + for (i = 0; i < 8; i++) { + mb_addr_inc[i].value = MPGDECODE_ERROR; + mb_addr_inc[i].num_bits = 0; + } + + mb_addr_inc[8].value = MACRO_BLOCK_ESCAPE; + mb_addr_inc[8].num_bits = 11; + + for (i = 9; i < 15; i++) { + mb_addr_inc[i].value = MPGDECODE_ERROR; + mb_addr_inc[i].num_bits = 0; + } + + mb_addr_inc[15].value = MACRO_BLOCK_STUFFING; + mb_addr_inc[15].num_bits = 11; + + for (i = 16; i < 24; i++) { + mb_addr_inc[i].value = MPGDECODE_ERROR; + mb_addr_inc[i].num_bits = 0; + } + + val = 33; + + ASSIGN1(24, 36, 1, val, 11); + ASSIGN1(36, 48, 2, val, 10); + ASSIGN1(48, 96, 8, val, 8); + ASSIGN1(96, 128, 16, val, 7); + ASSIGN1(128, 256, 64, val, 5); + ASSIGN1(256, 512, 128, val, 4); + ASSIGN1(512, 1024, 256, val, 3); + ASSIGN1(1024, 2048, 1024, val, 1); +} + + +/* Macro for filling up the decoding table for mb_type */ +#define ASSIGN2(start, end, quant, motion_forward, motion_backward, pattern, intra, num, mb_type) \ + for (i = start; i < end; i ++) { \ + mb_type[i].mb_quant = quant; \ + mb_type[i].mb_motion_forward = motion_forward; \ + mb_type[i].mb_motion_backward = motion_backward; \ + mb_type[i].mb_pattern = pattern; \ + mb_type[i].mb_intra = intra; \ + mb_type[i].num_bits = num; \ + } + + + +/* + *-------------------------------------------------------------- + * + * init_mb_type_P -- + * + * Initialize the VLC decoding table for macro_block_type in + * predictive-coded pictures. + * + * Results: + * The decoding table for macro_block_type in predictive-coded + * pictures will be filled; illegal values will be filled as MPGDECODE_ERROR. + * + * Side effects: + * The global array mb_type_P will be filled. + * + *-------------------------------------------------------------- + */ +static void init_mb_type_P() { + int i; + + mb_type_P[0].mb_quant = mb_type_P[0].mb_motion_forward + = mb_type_P[0].mb_motion_backward = mb_type_P[0].mb_pattern + = mb_type_P[0].mb_intra = (unsigned int)MPGDECODE_ERROR; + mb_type_P[0].num_bits = 0; + + ASSIGN2(1, 2, 1, 0, 0, 0, 1, 6, mb_type_P) + ASSIGN2(2, 4, 1, 0, 0, 1, 0, 5, mb_type_P) + ASSIGN2(4, 6, 1, 1, 0, 1, 0, 5, mb_type_P); + ASSIGN2(6, 8, 0, 0, 0, 0, 1, 5, mb_type_P); + ASSIGN2(8, 16, 0, 1, 0, 0, 0, 3, mb_type_P); + ASSIGN2(16, 32, 0, 0, 0, 1, 0, 2, mb_type_P); + ASSIGN2(32, 64, 0, 1, 0, 1, 0, 1, mb_type_P); +} + + + + +/* + *-------------------------------------------------------------- + * + * init_mb_type_B -- + * + * Initialize the VLC decoding table for macro_block_type in + * bidirectionally-coded pictures. + * + * Results: + * The decoding table for macro_block_type in bidirectionally-coded + * pictures will be filled; illegal values will be filled as MPGDECODE_ERROR. + * + * Side effects: + * The global array mb_type_B will be filled. + * + *-------------------------------------------------------------- + */ +static void init_mb_type_B() { + int i; + + mb_type_B[0].mb_quant = mb_type_B[0].mb_motion_forward + = mb_type_B[0].mb_motion_backward = mb_type_B[0].mb_pattern + = mb_type_B[0].mb_intra = (unsigned int) MPGDECODE_ERROR; + mb_type_B[0].num_bits = 0; + + ASSIGN2(1, 2, 1, 0, 0, 0, 1, 6, mb_type_B); + ASSIGN2(2, 3, 1, 0, 1, 1, 0, 6, mb_type_B); + ASSIGN2(3, 4, 1, 1, 0, 1, 0, 6, mb_type_B); + ASSIGN2(4, 6, 1, 1, 1, 1, 0, 5, mb_type_B); + ASSIGN2(6, 8, 0, 0, 0, 0, 1, 5, mb_type_B); + ASSIGN2(8, 12, 0, 1, 0, 0, 0, 4, mb_type_B); + ASSIGN2(12, 16, 0, 1, 0, 1, 0, 4, mb_type_B); + ASSIGN2(16, 24, 0, 0, 1, 0, 0, 3, mb_type_B); + ASSIGN2(24, 32, 0, 0, 1, 1, 0, 3, mb_type_B); + ASSIGN2(32, 48, 0, 1, 1, 0, 0, 2, mb_type_B); + ASSIGN2(48, 64, 0, 1, 1, 1, 0, 2, mb_type_B); +} + + +/* Macro for filling up the decoding tables for motion_vectors */ +#define ASSIGN3(start, end, step, val, num) \ + for (i = start; i < end; i+= step) { \ + for (j = 0; j < step / 2; j++) { \ + motion_vectors[i+j].code = val; \ + motion_vectors[i+j].num_bits = num; \ + } \ + for (j = step / 2; j < step; j++) { \ + motion_vectors[i+j].code = -val; \ + motion_vectors[i+j].num_bits = num; \ + } \ + val--; \ + } + + + +/* + *-------------------------------------------------------------- + * + * init_motion_vectors -- + * + * Initialize the VLC decoding table for the various motion + * vectors, including motion_horizontal_forward_code, + * motion_vertical_forward_code, motion_horizontal_backward_code, + * and motion_vertical_backward_code. + * + * Results: + * The decoding table for the motion vectors will be filled; + * illegal values will be filled as MPGDECODE_ERROR. + * + * Side effects: + * The global array motion_vector will be filled. + * + *-------------------------------------------------------------- + */ +static void init_motion_vectors() +{ + int i, j, val = 16; + + for (i = 0; i < 24; i++) { + motion_vectors[i].code = MPGDECODE_ERROR; + motion_vectors[i].num_bits = 0; + } + + ASSIGN3(24, 36, 2, val, 11); + ASSIGN3(36, 48, 4, val, 10); + ASSIGN3(48, 96, 16, val, 8); + ASSIGN3(96, 128, 32, val, 7); + ASSIGN3(128, 256, 128, val, 5); + ASSIGN3(256, 512, 256, val, 4); + ASSIGN3(512, 1024, 512, val, 3); + ASSIGN3(1024, 2048, 1024, val, 1); +} + + + +extern void init_pre_idct(); + + +/* + *-------------------------------------------------------------- + * + * init_tables -- + * + * Initialize all the tables for VLC decoding; this must be + * called when the system is set up before any decoding can + * take place. + * + * Results: + * All the decoding tables will be filled accordingly. + * + * Side effects: + * The corresponding global array for each decoding table + * will be filled. + * + *-------------------------------------------------------------- + */ +void init_tables() { + + init_mb_addr_inc(); + init_mb_type_P(); + init_mb_type_B(); + init_motion_vectors(); + + if (qualityFlag) { + cout << "qualityFlag in init_tables float idct removed"<<endl; + } + init_pre_idct(); + +} + + diff --git a/mpeglib/lib/mpegplay/decoderTables.h b/mpeglib/lib/mpegplay/decoderTables.h new file mode 100644 index 00000000..00b9b4f2 --- /dev/null +++ b/mpeglib/lib/mpegplay/decoderTables.h @@ -0,0 +1,110 @@ +/* + declares various tables to make things faster + 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 __DECODERTABLES_H +#define __DECODERTABLES_H + +#include "videoDecoder.h" +#include "proto.h" + +/* Code for unbound values in decoding tables */ +#define MPGDECODE_ERROR (-1) + +#define MACRO_BLOCK_STUFFING 34 +#define MACRO_BLOCK_ESCAPE 35 + + +/* Structure for an entry in the decoding table of + * macroblock_address_increment */ +typedef struct { + int value; /* value for macroblock_address_increment */ + int num_bits; /* length of the Huffman code */ +} mb_addr_inc_entry; + + +/* Structure for an entry in the decoding table of macroblock_type */ +typedef struct { + unsigned int mb_quant; /* macroblock_quant */ + unsigned int mb_motion_forward; /* macroblock_motion_forward */ + unsigned int mb_motion_backward; /* macroblock_motion_backward */ + unsigned int mb_pattern; /* macroblock_pattern */ + unsigned int mb_intra; /* macroblock_intra */ + unsigned int num_bits; /* length of the Huffman code */ +} mb_type_entry; + + +/* Structures for an entry in the decoding table of coded_block_pattern */ +typedef struct { + unsigned int cbp; /* coded_block_pattern */ + int num_bits; /* length of the Huffman code */ +} coded_block_pattern_entry; + + +/* Structure for an entry in the decoding table of motion vectors */ +typedef struct { + int code; /* value for motion_horizontal_forward_code, + * motion_vertical_forward_code, + * motion_horizontal_backward_code, or + * motion_vertical_backward_code. + */ + int num_bits; /* length of the Huffman code */ +} motion_vectors_entry; + + +/* Structure for an entry in the decoding table of dct_dc_size */ +typedef struct { + unsigned int value; /* value of dct_dc_size (luminance or chrominance) */ + int num_bits; /* length of the Huffman code */ +} dct_dc_size_entry; + + + +/* External declaration of dct coeff tables. */ + +extern unsigned short int dct_coeff_tbl_0[256]; +extern unsigned short int dct_coeff_tbl_1[16]; +extern unsigned short int dct_coeff_tbl_2[4]; +extern unsigned short int dct_coeff_tbl_3[4]; +extern unsigned short int dct_coeff_next[256]; +extern unsigned short int dct_coeff_first[256]; + +/* External declaration of dct dc size lumiance table. */ + +extern dct_dc_size_entry dct_dc_size_luminance[32]; +extern dct_dc_size_entry dct_dc_size_luminance1[16]; + +/* External declaration of dct dc size chrom table. */ + +extern dct_dc_size_entry dct_dc_size_chrominance[32]; +extern dct_dc_size_entry dct_dc_size_chrominance1[32]; + +/* External declaration of coded block pattern table. */ + +extern coded_block_pattern_entry coded_block_pattern[512]; + +/* Decoding table for macroblock_type in predictive-coded pictures */ +extern mb_type_entry mb_type_P[64]; + +/* Decoding table for macroblock_type in bidirectionally-coded pictures */ +extern mb_type_entry mb_type_B[64]; + +/* Decoding table for macroblock_address_increment */ +extern mb_addr_inc_entry mb_addr_inc[2048]; + +/* Decoding table for motion vectors */ +extern motion_vectors_entry motion_vectors[2048]; + +extern void init_tables(); + +#endif diff --git a/mpeglib/lib/mpegplay/globals.cpp b/mpeglib/lib/mpegplay/globals.cpp new file mode 100644 index 00000000..b1e416be --- /dev/null +++ b/mpeglib/lib/mpegplay/globals.cpp @@ -0,0 +1,41 @@ +/* + global variable for mpegplay + 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 + + */ + + + + + + + + + +/* + if used definetely uses more cpu, but I don't see + if the image is better or not. +*/ +int qualityFlag = 0; + +int gXErrorFlag = 0; + + + + + + + + + + + + + + diff --git a/mpeglib/lib/mpegplay/gop.cpp b/mpeglib/lib/mpegplay/gop.cpp new file mode 100644 index 00000000..b2199070 --- /dev/null +++ b/mpeglib/lib/mpegplay/gop.cpp @@ -0,0 +1,170 @@ +/* + parse/stores GOP (group of picture) information from a mpegVideoStream + 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 "gop.h" + +#include <iostream> + +using namespace std; + +GOP::GOP() { + drop_flag=false; + tc_hours=0; + tc_minutes=0; + tc_seconds=0; + tc_pictures=0; + closed_gop=false; + broken_link=false; + + mpegExtension=new MpegExtension(); + +} + + +GOP::~GOP() { + delete mpegExtension; +} + + +/* + *-------------------------------------------------------------- + * + * ParseGOP -- + * + * Parses of group of pictures header from bit stream + * associated with vid_stream. + * + * Results: + * Values in gop header placed into video stream structure. + * + * Side effects: + * Bit stream irreversibly parsed. + * + *-------------------------------------------------------------- + */ +int GOP::processGOP(MpegVideoStream* mpegVideoStream) { + unsigned int data; + + /* Flush group of pictures start code. */ + + mpegVideoStream->flushBits(32); + + /* Parse off drop frame flag. */ + + data=mpegVideoStream->getBits(1); + + if (data) { + drop_flag = true; + } else + drop_flag = false; + + /* Parse off hour component of time code. */ + + tc_hours=mpegVideoStream->getBits(5); + + /* Parse off minute component of time code. */ + + tc_minutes=mpegVideoStream->getBits(6); + + + /* Flush marker bit. */ + + mpegVideoStream->flushBits(1); + + /* Parse off second component of time code. */ + + tc_seconds=mpegVideoStream->getBits(6); + + /* Parse off picture count component of time code. */ + + tc_pictures=mpegVideoStream->getBits(6); + + /* Parse off closed gop and broken link flags. */ + data=mpegVideoStream->getBits(2); + if (data > 1) { + closed_gop = true; + if (data > 2) { + broken_link = true; + } else + broken_link = false; + } else { + closed_gop = false; + if (data) { + broken_link = true; + } else + broken_link = false; + } + + + /* + * If next start code is extension/user start code, + * parse off extension data. + */ + + mpegExtension->processExtensionData(mpegVideoStream); + + return true; +} + + + +int GOP::substract(GOP* minus,GOP* dest) { + int hours; + int minutes; + int seconds; + hours=getHour()-minus->getHour(); + minutes=getMinutes()-minus->getMinutes(); + seconds=getSeconds()-minus->getSeconds(); + + if (seconds < 0) { + seconds+=60; + minutes--; + } + if (minutes < 0) { + minutes+=60; + hours--; + } + dest->tc_hours=hours; + dest->tc_minutes=minutes; + dest->tc_seconds=seconds; + if (hours < 0) { + return false; + } + return true; +} + + +void GOP::copyTo(GOP* dest) { + dest->tc_hours=getHour(); + dest->tc_minutes=getMinutes(); + dest->tc_seconds=getSeconds(); + dest->drop_flag=getDropFlag(); + dest->tc_pictures=getPictures(); + dest->closed_gop=getClosedGOP(); + dest->broken_link=getBrokenLink(); + + // currently do not copy ext/user data FIX ME +} + + +void GOP::print(const char* description) { + cout << "GOP [START]:"<<description<<endl; + cout << "tc_hours:"<<getHour()<<endl; + cout << "tc_minutes:"<<getMinutes()<<endl; + cout << "tc_seconds:"<<getSeconds()<<endl; + cout << "drop_flag:"<<getDropFlag()<<endl; + cout << "tc_pictures:"<<getPictures()<<endl; + cout << "closed_gop:"<<getClosedGOP()<<endl; + cout << "broken_link:"<<getBrokenLink()<<endl; + cout << "GOP [END]"<<endl; +} diff --git a/mpeglib/lib/mpegplay/gop.h b/mpeglib/lib/mpegplay/gop.h new file mode 100644 index 00000000..a36d2886 --- /dev/null +++ b/mpeglib/lib/mpegplay/gop.h @@ -0,0 +1,62 @@ +/* + parse/stores GOP (group of picture) information from a mpegVideoStream + 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 __GOP_H +#define __GOP_H + +#include "mpegVideoStream.h" +#include "mpegExtension.h" + +class GOP { + /* Group of pictures structure. */ + + int drop_flag; /* Flag indicating dropped frame. */ + int tc_hours; /* Hour component of time code. */ + unsigned int tc_minutes; /* Minute component of time code. */ + unsigned int tc_seconds; /* Second component of time code. */ + unsigned int tc_pictures; /* Picture counter of time code. */ + int closed_gop; /* Indicates no pred. vectors to + previous group of pictures. */ + int broken_link; /* B frame unable to be decoded. */ + MpegExtension* mpegExtension; + + + public: + GOP(); + ~GOP(); + + int processGOP(MpegVideoStream* mpegVideoStream); + void copyTo(GOP* dest); + + inline int getDropFlag() { return drop_flag; } + inline unsigned int getHour() { return tc_hours; } + inline unsigned int getMinutes() { return tc_minutes; } + inline unsigned int getSeconds() { return tc_seconds; } + inline unsigned int getPictures() { return tc_pictures; } + inline int getClosedGOP() { return closed_gop; } + inline int getBrokenLink() { return broken_link; } + + + inline void setHour(int hour) { this->tc_hours=hour; } + inline void setMinute(unsigned int minute) { this->tc_minutes=minute; } + inline void setSecond(unsigned int second) { this->tc_seconds=second; } + + + // returns diff in seconds + int substract(GOP* minus,GOP* dest); + void print(const char* description); +}; +#endif diff --git a/mpeglib/lib/mpegplay/jrevdct.cpp b/mpeglib/lib/mpegplay/jrevdct.cpp new file mode 100644 index 00000000..4ffe48ab --- /dev/null +++ b/mpeglib/lib/mpegplay/jrevdct.cpp @@ -0,0 +1,1690 @@ +/* + * jrevdct.c + * + * This file is part of the Independent JPEG Group's software. + * The IJG code is distributed under the terms reproduced here: + * + * LEGAL ISSUES + * ============ + * + * In plain English: + * + * 1. We don't promise that this software works. (But if you find any bugs, + * please let us know!) + * 2. You can use this software for whatever you want. You don't have to + * pay us. + * 3. You may not pretend that you wrote this software. If you use it in a + * program, you must acknowledge somewhere in your documentation that + * you've used the IJG code. + * + * In legalese: + * + * The authors make NO WARRANTY or representation, either express or implied, + * with respect to this software, its quality, accuracy, merchantability, or + * fitness for a particular purpose. This software is provided "AS IS", and + * you, its user, assume the entire risk as to its quality and accuracy. + * + * This software is copyright (C) 1991, 1992, Thomas G. Lane. + * All Rights Reserved except as specified below. + * + * Permission is hereby granted to use, copy, modify, and distribute this + * software (or portions thereof) for any purpose, without fee, subject to + * these conditions: + * (1) If any part of the source code for this software is distributed, then + * this copyright and no-warranty notice must be included unaltered; and any + * additions, deletions, or changes to the original files must be clearly + * indicated in accompanying documentation. + * (2) If only executable code is distributed, then the accompanying + * documentation must state that "this software is based in part on the + * work of the Independent JPEG Group". + * (3) Permission for use of this software is granted only if the user + * accepts full responsibility for any undesirable consequences; the authors + * accept NO LIABILITY for damages of any kind. + * + * These conditions apply to any software derived from or based on the IJG + * code, not just to the unmodified library. If you use our work, you ought + * to acknowledge us. + * + * Permission is NOT granted for the use of any IJG author's name or company + * name in advertising or publicity relating to this software or products + * derived from it. This software may be referred to only as + * "the Independent JPEG Group's software". + * + * We specifically permit and encourage the use of this software as the + * basis of commercial products, provided that all warranty or liability + * claims are assumed by the product vendor. + * + * + * ARCHIVE LOCATIONS + * ================= + * + * The "official" archive site for this software is ftp.uu.net (Internet + * address 192.48.96.9). The most recent released version can always be + * found there in directory graphics/jpeg. This particular version will + * be archived as graphics/jpeg/jpegsrc.v6a.tar.gz. If you are on the + * Internet, you can retrieve files from ftp.uu.net by standard anonymous + * FTP. If you don't have FTP access, UUNET's archives are also available + * via UUCP; contact help@uunet.uu.net for information on retrieving files + * that way. + * + * Numerous Internet sites maintain copies of the UUNET files. However, + * only ftp.uu.net is guaranteed to have the latest official version. + * + * You can also obtain this software in DOS-compatible "zip" archive + * format from the SimTel archives (ftp.coast.net:/SimTel/msdos/graphics/), + * or on CompuServe in the Graphics Support forum (GO CIS:GRAPHSUP), + * library 12 "JPEG Tools". Again, these versions may sometimes lag behind + * the ftp.uu.net release. + * + * The JPEG FAQ (Frequently Asked Questions) article is a useful source of + * general information about JPEG. It is updated constantly and therefore + * is not included in this distribution. The FAQ is posted every two weeks + * to Usenet newsgroups comp.graphics.misc, news.answers, and other groups. + * You can always obtain the latest version from the news.answers archive + * at rtfm.mit.edu. By FTP, fetch /pub/usenet/news.answers/jpeg-faq/part1 + * and .../part2. If you don't have FTP, send e-mail to + * mail-server@rtfm.mit.edu with body + * send usenet/news.answers/jpeg-faq/part1 + * send usenet/news.answers/jpeg-faq/part2 + * + * ============== + * + * + * This file contains the basic inverse-DCT transformation subroutine. + * + * This implementation is based on an algorithm described in + * C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT + * Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics, + * Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991. + * The primary algorithm described there uses 11 multiplies and 29 adds. + * We use their alternate method with 12 multiplies and 32 adds. + * The advantage of this method is that no data path contains more than one + * multiplication; this allows a very simple and accurate implementation in + * scaled fixed-point arithmetic, with a minimal number of shifts. + * + * + * CHANGES FOR BERKELEY MPEG + * ========================= + * + * This file has been altered to use the Berkeley MPEG header files, + * to add the capability to handle sparse DCT matrices efficiently, + * and to relabel the inverse DCT function as well as the file + * (formerly jidctint.c). + * + * I've made lots of modifications to attempt to take advantage of the + * sparse nature of the DCT matrices we're getting. Although the logic + * is cumbersome, it's straightforward and the resulting code is much + * faster. + * + * A better way to do this would be to pass in the DCT block as a sparse + * matrix, perhaps with the difference cases encoded. + */ + +#include "jrevdct.h" + + + + +/* We assume that right shift corresponds to signed division by 2 with + * rounding towards minus infinity. This is correct for typical "arithmetic + * shift" instructions that shift in copies of the sign bit. But some + * C compilers implement >> with an unsigned shift. For these machines you + * must define RIGHT_SHIFT_IS_UNSIGNED. + * RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity. + * It is only applied with constant shift counts. SHIFT_TEMPS must be + * included in the variables of any routine using RIGHT_SHIFT. + */ + +#ifdef RIGHT_SHIFT_IS_UNSIGNED +#define SHIFT_TEMPS INT32 shift_temp; +#define RIGHT_SHIFT(x,shft) \ + ((shift_temp = (x)) < 0 ? \ + (shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \ + (shift_temp >> (shft))) +#else +#define SHIFT_TEMPS +#define RIGHT_SHIFT(x,shft) ((x) >> (shft)) +#endif + +/* + * This routine is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* + * A 2-D IDCT can be done by 1-D IDCT on each row followed by 1-D IDCT + * on each column. Direct algorithms are also available, but they are + * much more complex and seem not to be any faster when reduced to code. + * + * The poop on this scaling stuff is as follows: + * + * Each 1-D IDCT step produces outputs which are a factor of sqrt(N) + * larger than the true IDCT outputs. The final outputs are therefore + * a factor of N larger than desired; since N=8 this can be cured by + * a simple right shift at the end of the algorithm. The advantage of + * this arrangement is that we save two multiplications per 1-D IDCT, + * because the y0 and y4 inputs need not be divided by sqrt(N). + * + * We have to do addition and subtraction of the integer inputs, which + * is no problem, and multiplication by fractional constants, which is + * a problem to do in integer arithmetic. We multiply all the constants + * by CONST_SCALE and convert them to integer constants (thus retaining + * CONST_BITS bits of precision in the constants). After doing a + * multiplication we have to divide the product by CONST_SCALE, with proper + * rounding, to produce the correct output. This division can be done + * cheaply as a right shift of CONST_BITS bits. We postpone shifting + * as long as possible so that partial sums can be added together with + * full fractional precision. + * + * The outputs of the first pass are scaled up by PASS1_BITS bits so that + * they are represented to better-than-integral precision. These outputs + * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word + * with the recommended scaling. (To scale up 12-bit sample data further, an + * intermediate INT32 array would be needed.) + * + * To avoid overflow of the 32-bit intermediate results in pass 2, we must + * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26. Error analysis + * shows that the values given below are the most effective. + */ + +#ifdef EIGHT_BIT_SAMPLES +#define PASS1_BITS 2 +#else +#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ +#endif + +#define ONE ((INT32) 1) + +#define CONST_SCALE (ONE << CONST_BITS) + +/* Convert a positive real constant to an integer scaled by CONST_SCALE. + * IMPORTANT: if your compiler doesn't do this arithmetic at compile time, + * you will pay a significant penalty in run time. In that case, figure + * the correct integer constant values and insert them by hand. + */ + +#define FIX(x) ((INT32) ((x) * CONST_SCALE + 0.5)) + +/* When adding two opposite-signed fixes, the 0.5 cancels */ +#define FIX2(x) ((INT32) ((x) * CONST_SCALE)) + +/* Descale and correctly round an INT32 value that's scaled by N bits. + * We assume RIGHT_SHIFT rounds towards minus infinity, so adding + * the fudge factor is correct for either sign of X. + */ + +#define DESCALE(x,n) RIGHT_SHIFT((x) + (ONE << ((n)-1)), n) + +/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. + * For 8-bit samples with the recommended scaling, all the variable + * and constant values involved are no more than 16 bits wide, so a + * 16x16->32 bit multiply can be used instead of a full 32x32 multiply; + * this provides a useful speedup on many machines. + * There is no way to specify a 16x16->32 multiply in portable C, but + * some C compilers will do the right thing if you provide the correct + * combination of casts. + * NB: for 12-bit samples, a full 32-bit multiplication will be needed. + */ + +#ifdef EIGHT_BIT_SAMPLES +#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */ +#define MULTIPLY(var,const) (((INT16) (var)) * ((INT16) (const))) +#endif +#ifdef SHORTxLCONST_32 /* known to work with Microsoft C 6.0 */ +#define MULTIPLY(var,const) (((INT16) (var)) * ((INT32) (const))) +#endif +#endif + +#ifndef MULTIPLY /* default definition */ +#define MULTIPLY(var,const) ((var) * (const)) +#endif + +#ifndef NO_SPARSE_DCT +#define SPARSE_SCALE_FACTOR 8 +#endif + +/* Precomputed idct value arrays. */ + +static DCTELEM PreIDCT[64][64]; + + +/* + *-------------------------------------------------------------- + * + * init_pre_idct -- + * + * Pre-computes singleton coefficient IDCT values. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ +void init_pre_idct() { + int i; + + for (i=0; i<64; i++) { + memset((char *) PreIDCT[i], 0, 64*sizeof(DCTELEM)); + PreIDCT[i][i] = 1 << SPARSE_SCALE_FACTOR; + j_rev_dct(PreIDCT[i]); + } + + int pos; + int rr; + DCTELEM *ndataptr; + + for(pos=0;pos<64;pos++) { + ndataptr = PreIDCT[pos]; + + for(rr=0; rr<4; rr++) { + for(i=0;i<16;i++) { + ndataptr[i] = ndataptr[i]/256; + } + ndataptr += 16; + + } + } + + + + + + +} + +#ifndef NO_SPARSE_DCT + + +/* + *-------------------------------------------------------------- + * + * j_rev_dct_sparse -- + * + * Performs the inverse DCT on one block of coefficients. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +void j_rev_dct_sparse (DCTBLOCK data, int pos) { + short int val; + register int *dp; + register int v; + int quant; + + // cout << "j_rev_dct_sparse"<<endl; + + /* If DC Coefficient. */ + + if (pos == 0) { + dp = (int *)data; + v = *data; + quant = 8; + + /* Compute 32 bit value to assign. This speeds things up a bit */ + if (v < 0) { + val = -v; + val += (quant / 2); + val /= quant; + val = -val; + } + else { + val = (v + (quant / 2)) / quant; + } + + v = ((val & 0xffff) | (val << 16)); + + dp[0] = v; dp[1] = v; dp[2] = v; dp[3] = v; + dp[4] = v; dp[5] = v; dp[6] = v; dp[7] = v; + dp[8] = v; dp[9] = v; dp[10] = v; dp[11] = v; + dp[12] = v; dp[13] = v; dp[14] = v; dp[15] = v; + dp[16] = v; dp[17] = v; dp[18] = v; dp[19] = v; + dp[20] = v; dp[21] = v; dp[22] = v; dp[23] = v; + dp[24] = v; dp[25] = v; dp[26] = v; dp[27] = v; + dp[28] = v; dp[29] = v; dp[30] = v; dp[31] = v; + + return; + } + //printf("sparse is: %d val:%8x\n",pos,data[pos]); + + /* + j_rev_dct(data); + return; + */ + + /* Some other coefficient. */ + + DCTELEM *dataptr; + DCTELEM *ndataptr; + int coeff, rr; + + + + dataptr = (DCTELEM *)data; + coeff = dataptr[pos]; + ndataptr = PreIDCT[pos]; + + //printf ("COEFFICIENT = %3d, POSITION = %2d\n", coeff, pos); + coeff=coeff/256; + + for (rr=0; rr<4; rr++) { + + dataptr[0] = (ndataptr[0] * coeff); + dataptr[1] = (ndataptr[1] * coeff); + dataptr[2] = (ndataptr[2] * coeff); + dataptr[3] = (ndataptr[3] * coeff); + dataptr[4] = (ndataptr[4] * coeff); + dataptr[5] = (ndataptr[5] * coeff); + dataptr[6] = (ndataptr[6] * coeff); + dataptr[7] = (ndataptr[7] * coeff); + dataptr[8] = (ndataptr[8] * coeff); + dataptr[9] = (ndataptr[9] * coeff); + dataptr[10] = (ndataptr[10] * coeff); + dataptr[11] = (ndataptr[11] * coeff); + dataptr[12] = (ndataptr[12] * coeff); + dataptr[13] = (ndataptr[13] * coeff); + dataptr[14] = (ndataptr[14] * coeff); + dataptr[15] = (ndataptr[15] * coeff); + + + dataptr += 16; + ndataptr += 16; + } + + dataptr = (DCTELEM *) data; + + + + return; + +} + +#else + +/* + *-------------------------------------------------------------- + * + * j_rev_dct_sparse -- + * + * Performs the original inverse DCT on one block of + * coefficients. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ +void j_rev_dct_sparse (DCTBLOCK data,int pos) { + j_rev_dct(data); +} +#endif /* SPARSE_DCT */ + + +#ifndef FIVE_DCT + +#ifndef ORIG_DCT + + +/* + *-------------------------------------------------------------- + * + * j_rev_dct -- + * + * The inverse DCT function. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ +void j_rev_dct (DCTBLOCK data) { + + + INT32 tmp0, tmp1, tmp2, tmp3; + INT32 tmp10, tmp11, tmp12, tmp13; + INT32 z1, z2, z3, z4, z5; + INT32 d0, d1, d2, d3, d4, d5, d6, d7; + register DCTELEM *dataptr; + int rowctr; + SHIFT_TEMPS + + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true IDCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + + dataptr = data; + + for (rowctr = DCTSIZE-1; rowctr >= 0; rowctr--) { + /* Due to quantization, we will usually find that many of the input + * coefficients are zero, especially the AC terms. We can exploit this + * by short-circuiting the IDCT calculation for any row in which all + * the AC terms are zero. In that case each output is equal to the + * DC coefficient (with scale factor as needed). + * With typical images and quantization tables, half or more of the + * row DCT calculations can be simplified this way. + */ + + register int *idataptr = (int*)dataptr; + d0 = dataptr[0]; + d1 = dataptr[1]; + if ((d1 == 0) && (idataptr[1] + idataptr[2] + idataptr[3]) == 0) { + /* AC terms all zero */ + if (d0) { + /* Compute a 32 bit value to assign. */ + DCTELEM dcval = (DCTELEM) (d0 << PASS1_BITS); + register int v = (dcval & 0xffff) + (dcval << 16); + + idataptr[0] = v; + idataptr[1] = v; + idataptr[2] = v; + idataptr[3] = v; + } + + dataptr += DCTSIZE; /* advance pointer to next row */ + continue; + } + d2 = dataptr[2]; + d3 = dataptr[3]; + d4 = dataptr[4]; + d5 = dataptr[5]; + d6 = dataptr[6]; + d7 = dataptr[7]; + + /* Even part: reverse the even part of the forward DCT. */ + /* The rotator is sqrt(2)*c(-6). */ + if (d6) { + if (d4) { + if (d2) { + if (d0) { + /* d0 != 0, d2 != 0, d4 != 0, d6 != 0 */ + z1 = MULTIPLY(d2 + d6, FIX(0.541196100)); + tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065)); + tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865)); + + tmp0 = (d0 + d4) << CONST_BITS; + tmp1 = (d0 - d4) << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + } else { + /* d0 == 0, d2 != 0, d4 != 0, d6 != 0 */ + z1 = MULTIPLY(d2 + d6, FIX(0.541196100)); + tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065)); + tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865)); + + tmp0 = d4 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp2 - tmp0; + tmp12 = -(tmp0 + tmp2); + } + } else { + if (d0) { + /* d0 != 0, d2 == 0, d4 != 0, d6 != 0 */ + tmp2 = MULTIPLY(d6, - FIX2(1.306562965)); + tmp3 = MULTIPLY(d6, FIX(0.541196100)); + + tmp0 = (d0 + d4) << CONST_BITS; + tmp1 = (d0 - d4) << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + } else { + /* d0 == 0, d2 == 0, d4 != 0, d6 != 0 */ + tmp2 = MULTIPLY(d6, - FIX2(1.306562965)); + tmp3 = MULTIPLY(d6, FIX(0.541196100)); + + tmp0 = d4 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp2 - tmp0; + tmp12 = -(tmp0 + tmp2); + } + } + } else { + if (d2) { + if (d0) { + /* d0 != 0, d2 != 0, d4 == 0, d6 != 0 */ + z1 = MULTIPLY(d2 + d6, FIX(0.541196100)); + tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065)); + tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865)); + + tmp0 = d0 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + } else { + /* d0 == 0, d2 != 0, d4 == 0, d6 != 0 */ + z1 = MULTIPLY(d2 + d6, FIX(0.541196100)); + tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065)); + tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865)); + + tmp10 = tmp3; + tmp13 = -tmp3; + tmp11 = tmp2; + tmp12 = -tmp2; + } + } else { + if (d0) { + /* d0 != 0, d2 == 0, d4 == 0, d6 != 0 */ + tmp2 = MULTIPLY(d6, - FIX2(1.306562965)); + tmp3 = MULTIPLY(d6, FIX(0.541196100)); + + tmp0 = d0 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + } else { + /* d0 == 0, d2 == 0, d4 == 0, d6 != 0 */ + tmp2 = MULTIPLY(d6, - FIX2(1.306562965)); + tmp3 = MULTIPLY(d6, FIX(0.541196100)); + + tmp10 = tmp3; + tmp13 = -tmp3; + tmp11 = tmp2; + tmp12 = -tmp2; + } + } + } + } else { + if (d4) { + if (d2) { + if (d0) { + /* d0 != 0, d2 != 0, d4 != 0, d6 == 0 */ + tmp2 = MULTIPLY(d2, FIX(0.541196100)); + tmp3 = (INT32) (MULTIPLY(d2, (FIX(1.306562965) + .5))); + + tmp0 = (d0 + d4) << CONST_BITS; + tmp1 = (d0 - d4) << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + } else { + /* d0 == 0, d2 != 0, d4 != 0, d6 == 0 */ + tmp2 = MULTIPLY(d2, FIX(0.541196100)); + tmp3 = (INT32) (MULTIPLY(d2, (FIX(1.306562965) + .5))); + + tmp0 = d4 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp2 - tmp0; + tmp12 = -(tmp0 + tmp2); + } + } else { + if (d0) { + /* d0 != 0, d2 == 0, d4 != 0, d6 == 0 */ + tmp10 = tmp13 = (d0 + d4) << CONST_BITS; + tmp11 = tmp12 = (d0 - d4) << CONST_BITS; + } else { + /* d0 == 0, d2 == 0, d4 != 0, d6 == 0 */ + tmp10 = tmp13 = d4 << CONST_BITS; + tmp11 = tmp12 = -tmp10; + } + } + } else { + if (d2) { + if (d0) { + /* d0 != 0, d2 != 0, d4 == 0, d6 == 0 */ + tmp2 = MULTIPLY(d2, FIX(0.541196100)); + tmp3 = (INT32) (MULTIPLY(d2, (FIX(1.306562965) + .5))); + + tmp0 = d0 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + } else { + /* d0 == 0, d2 != 0, d4 == 0, d6 == 0 */ + tmp2 = MULTIPLY(d2, FIX(0.541196100)); + tmp3 = (INT32) (MULTIPLY(d2, (FIX(1.306562965) + .5))); + + tmp10 = tmp3; + tmp13 = -tmp3; + tmp11 = tmp2; + tmp12 = -tmp2; + } + } else { + if (d0) { + /* d0 != 0, d2 == 0, d4 == 0, d6 == 0 */ + tmp10 = tmp13 = tmp11 = tmp12 = d0 << CONST_BITS; + } else { + /* d0 == 0, d2 == 0, d4 == 0, d6 == 0 */ + tmp10 = tmp13 = tmp11 = tmp12 = 0; + } + } + } + } + + + /* Odd part per figure 8; the matrix is unitary and hence its + * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. + */ + + if (d7) { + if (d5) { + if (d3) { + if (d1) { + /* d1 != 0, d3 != 0, d5 != 0, d7 != 0 */ + z1 = d7 + d1; + z2 = d5 + d3; + z3 = d7 + d3; + z4 = d5 + d1; + z5 = MULTIPLY(z3 + z4, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, FIX(0.298631336)); + tmp1 = MULTIPLY(d5, FIX(2.053119869)); + tmp2 = MULTIPLY(d3, FIX(3.072711026)); + tmp3 = MULTIPLY(d1, FIX(1.501321110)); + z1 = MULTIPLY(z1, - FIX(0.899976223)); + z2 = MULTIPLY(z2, - FIX(2.562915447)); + z3 = MULTIPLY(z3, - FIX(1.961570560)); + z4 = MULTIPLY(z4, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 += z2 + z4; + tmp2 += z2 + z3; + tmp3 += z1 + z4; + } else { + /* d1 == 0, d3 != 0, d5 != 0, d7 != 0 */ + z2 = d5 + d3; + z3 = d7 + d3; + z5 = MULTIPLY(z3 + d5, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, FIX(0.298631336)); + tmp1 = MULTIPLY(d5, FIX(2.053119869)); + tmp2 = MULTIPLY(d3, FIX(3.072711026)); + z1 = MULTIPLY(d7, - FIX(0.899976223)); + z2 = MULTIPLY(z2, - FIX(2.562915447)); + z3 = MULTIPLY(z3, - FIX(1.961570560)); + z4 = MULTIPLY(d5, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 += z2 + z4; + tmp2 += z2 + z3; + tmp3 = z1 + z4; + } + } else { + if (d1) { + /* d1 != 0, d3 == 0, d5 != 0, d7 != 0 */ + z1 = d7 + d1; + z4 = d5 + d1; + z5 = MULTIPLY(d7 + z4, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, FIX(0.298631336)); + tmp1 = MULTIPLY(d5, FIX(2.053119869)); + tmp3 = MULTIPLY(d1, FIX(1.501321110)); + z1 = MULTIPLY(z1, - FIX(0.899976223)); + z2 = MULTIPLY(d5, - FIX(2.562915447)); + z3 = MULTIPLY(d7, - FIX(1.961570560)); + z4 = MULTIPLY(z4, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 += z2 + z4; + tmp2 = z2 + z3; + tmp3 += z1 + z4; + } else { + /* d1 == 0, d3 == 0, d5 != 0, d7 != 0 */ + z5 = MULTIPLY(d7 + d5, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, - FIX2(0.601344887)); + tmp1 = MULTIPLY(d5, - FIX2(0.509795578)); + z1 = MULTIPLY(d7, - FIX(0.899976223)); + z3 = MULTIPLY(d7, - FIX(1.961570560)); + z2 = MULTIPLY(d5, - FIX(2.562915447)); + z4 = MULTIPLY(d5, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 += z3; + tmp1 += z4; + tmp2 = z2 + z3; + tmp3 = z1 + z4; + } + } + } else { + if (d3) { + if (d1) { + /* d1 != 0, d3 != 0, d5 == 0, d7 != 0 */ + z1 = d7 + d1; + z3 = d7 + d3; + z5 = MULTIPLY(z3 + d1, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, FIX(0.298631336)); + tmp2 = MULTIPLY(d3, FIX(3.072711026)); + tmp3 = MULTIPLY(d1, FIX(1.501321110)); + z1 = MULTIPLY(z1, - FIX(0.899976223)); + z2 = MULTIPLY(d3, - FIX(2.562915447)); + z3 = MULTIPLY(z3, - FIX(1.961570560)); + z4 = MULTIPLY(d1, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 = z2 + z4; + tmp2 += z2 + z3; + tmp3 += z1 + z4; + } else { + /* d1 == 0, d3 != 0, d5 == 0, d7 != 0 */ + z3 = d7 + d3; + z5 = MULTIPLY(z3, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, - FIX2(0.601344887)); + tmp2 = MULTIPLY(d3, FIX(0.509795579)); + z1 = MULTIPLY(d7, - FIX(0.899976223)); + z2 = MULTIPLY(d3, - FIX(2.562915447)); + z3 = MULTIPLY(z3, - FIX2(0.785694958)); + + tmp0 += z3; + tmp1 = z2 + z5; + tmp2 += z3; + tmp3 = z1 + z5; + } + } else { + if (d1) { + /* d1 != 0, d3 == 0, d5 == 0, d7 != 0 */ + z1 = d7 + d1; + z5 = MULTIPLY(z1, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, - FIX2(1.662939224)); + tmp3 = MULTIPLY(d1, FIX2(1.111140466)); + z1 = MULTIPLY(z1, FIX2(0.275899379)); + z3 = MULTIPLY(d7, - FIX(1.961570560)); + z4 = MULTIPLY(d1, - FIX(0.390180644)); + + tmp0 += z1; + tmp1 = z4 + z5; + tmp2 = z3 + z5; + tmp3 += z1; + } else { + /* d1 == 0, d3 == 0, d5 == 0, d7 != 0 */ + tmp0 = MULTIPLY(d7, - FIX2(1.387039845)); + tmp1 = MULTIPLY(d7, FIX(1.175875602)); + tmp2 = MULTIPLY(d7, - FIX2(0.785694958)); + tmp3 = MULTIPLY(d7, FIX2(0.275899379)); + } + } + } + } else { + if (d5) { + if (d3) { + if (d1) { + /* d1 != 0, d3 != 0, d5 != 0, d7 == 0 */ + z2 = d5 + d3; + z4 = d5 + d1; + z5 = MULTIPLY(d3 + z4, FIX(1.175875602)); + + tmp1 = MULTIPLY(d5, FIX(2.053119869)); + tmp2 = MULTIPLY(d3, FIX(3.072711026)); + tmp3 = MULTIPLY(d1, FIX(1.501321110)); + z1 = MULTIPLY(d1, - FIX(0.899976223)); + z2 = MULTIPLY(z2, - FIX(2.562915447)); + z3 = MULTIPLY(d3, - FIX(1.961570560)); + z4 = MULTIPLY(z4, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 = z1 + z3; + tmp1 += z2 + z4; + tmp2 += z2 + z3; + tmp3 += z1 + z4; + } else { + /* d1 == 0, d3 != 0, d5 != 0, d7 == 0 */ + z2 = d5 + d3; + z5 = MULTIPLY(z2, FIX(1.175875602)); + + tmp1 = MULTIPLY(d5, FIX2(1.662939225)); + tmp2 = MULTIPLY(d3, FIX2(1.111140466)); + z2 = MULTIPLY(z2, - FIX2(1.387039845)); + z3 = MULTIPLY(d3, - FIX(1.961570560)); + z4 = MULTIPLY(d5, - FIX(0.390180644)); + + tmp0 = z3 + z5; + tmp1 += z2; + tmp2 += z2; + tmp3 = z4 + z5; + } + } else { + if (d1) { + /* d1 != 0, d3 == 0, d5 != 0, d7 == 0 */ + z4 = d5 + d1; + z5 = MULTIPLY(z4, FIX(1.175875602)); + + tmp1 = MULTIPLY(d5, - FIX2(0.509795578)); + tmp3 = MULTIPLY(d1, FIX2(0.601344887)); + z1 = MULTIPLY(d1, - FIX(0.899976223)); + z2 = MULTIPLY(d5, - FIX(2.562915447)); + z4 = MULTIPLY(z4, FIX2(0.785694958)); + + tmp0 = z1 + z5; + tmp2 = z2 + z5; + tmp1 += z4; + tmp3 += z4; + } else { + /* d1 == 0, d3 == 0, d5 != 0, d7 == 0 */ + tmp0 = MULTIPLY(d5, FIX(1.175875602)); + tmp1 = MULTIPLY(d5, FIX2(0.275899380)); + tmp2 = MULTIPLY(d5, - FIX2(1.387039845)); + tmp3 = MULTIPLY(d5, FIX2(0.785694958)); + } + } + } else { + if (d3) { + if (d1) { + /* d1 != 0, d3 != 0, d5 == 0, d7 == 0 */ + z5 = d3 + d1; + + tmp2 = MULTIPLY(d3, - FIX(1.451774981)); + tmp3 = MULTIPLY(d1, (FIX(0.211164243) - 1)); + z1 = MULTIPLY(d1, FIX(1.061594337)); + z2 = MULTIPLY(d3, - FIX(2.172734803)); + z4 = MULTIPLY(z5, FIX(0.785694958)); + z5 = MULTIPLY(z5, FIX(1.175875602)); + + tmp0 = z1 - z4; + tmp1 = z2 + z4; + tmp2 += z5; + tmp3 += z5; + } else { + /* d1 == 0, d3 != 0, d5 == 0, d7 == 0 */ + tmp0 = MULTIPLY(d3, - FIX2(0.785694958)); + tmp1 = MULTIPLY(d3, - FIX2(1.387039845)); + tmp2 = MULTIPLY(d3, - FIX2(0.275899379)); + tmp3 = MULTIPLY(d3, FIX(1.175875602)); + } + } else { + if (d1) { + /* d1 != 0, d3 == 0, d5 == 0, d7 == 0 */ + tmp0 = MULTIPLY(d1, FIX2(0.275899379)); + tmp1 = MULTIPLY(d1, FIX2(0.785694958)); + tmp2 = MULTIPLY(d1, FIX(1.175875602)); + tmp3 = MULTIPLY(d1, FIX2(1.387039845)); + } else { + /* d1 == 0, d3 == 0, d5 == 0, d7 == 0 */ + tmp0 = tmp1 = tmp2 = tmp3 = 0; + } + } + } + } + + /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ + + dataptr[0] = (DCTELEM) DESCALE(tmp10 + tmp3, CONST_BITS-PASS1_BITS); + dataptr[7] = (DCTELEM) DESCALE(tmp10 - tmp3, CONST_BITS-PASS1_BITS); + dataptr[1] = (DCTELEM) DESCALE(tmp11 + tmp2, CONST_BITS-PASS1_BITS); + dataptr[6] = (DCTELEM) DESCALE(tmp11 - tmp2, CONST_BITS-PASS1_BITS); + dataptr[2] = (DCTELEM) DESCALE(tmp12 + tmp1, CONST_BITS-PASS1_BITS); + dataptr[5] = (DCTELEM) DESCALE(tmp12 - tmp1, CONST_BITS-PASS1_BITS); + dataptr[3] = (DCTELEM) DESCALE(tmp13 + tmp0, CONST_BITS-PASS1_BITS); + dataptr[4] = (DCTELEM) DESCALE(tmp13 - tmp0, CONST_BITS-PASS1_BITS); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. */ + /* Note that we must descale the results by a factor of 8 == 2**3, */ + /* and also undo the PASS1_BITS scaling. */ + + dataptr = data; + for (rowctr = DCTSIZE-1; rowctr >= 0; rowctr--) { + /* Columns of zeroes can be exploited in the same way as we did with rows. + * However, the row calculation has created many nonzero AC terms, so the + * simplification applies less often (typically 5% to 10% of the time). + * On machines with very fast multiplication, it's possible that the + * test takes more time than it's worth. In that case this section + * may be commented out. + */ + + d0 = dataptr[DCTSIZE*0]; + d1 = dataptr[DCTSIZE*1]; + d2 = dataptr[DCTSIZE*2]; + d3 = dataptr[DCTSIZE*3]; + d4 = dataptr[DCTSIZE*4]; + d5 = dataptr[DCTSIZE*5]; + d6 = dataptr[DCTSIZE*6]; + d7 = dataptr[DCTSIZE*7]; + + /* Even part: reverse the even part of the forward DCT. */ + /* The rotator is sqrt(2)*c(-6). */ + if (d6) { + if (d4) { + if (d2) { + if (d0) { + /* d0 != 0, d2 != 0, d4 != 0, d6 != 0 */ + z1 = MULTIPLY(d2 + d6, FIX(0.541196100)); + tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065)); + tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865)); + + tmp0 = (d0 + d4) << CONST_BITS; + tmp1 = (d0 - d4) << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + } else { + /* d0 == 0, d2 != 0, d4 != 0, d6 != 0 */ + z1 = MULTIPLY(d2 + d6, FIX(0.541196100)); + tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065)); + tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865)); + + tmp0 = d4 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp2 - tmp0; + tmp12 = -(tmp0 + tmp2); + } + } else { + if (d0) { + /* d0 != 0, d2 == 0, d4 != 0, d6 != 0 */ + tmp2 = MULTIPLY(d6, - FIX2(1.306562965)); + tmp3 = MULTIPLY(d6, FIX(0.541196100)); + + tmp0 = (d0 + d4) << CONST_BITS; + tmp1 = (d0 - d4) << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + } else { + /* d0 == 0, d2 == 0, d4 != 0, d6 != 0 */ + tmp2 = MULTIPLY(d6, -FIX2(1.306562965)); + tmp3 = MULTIPLY(d6, FIX(0.541196100)); + + tmp0 = d4 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp2 - tmp0; + tmp12 = -(tmp0 + tmp2); + } + } + } else { + if (d2) { + if (d0) { + /* d0 != 0, d2 != 0, d4 == 0, d6 != 0 */ + z1 = MULTIPLY(d2 + d6, FIX(0.541196100)); + tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065)); + tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865)); + + tmp0 = d0 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + } else { + /* d0 == 0, d2 != 0, d4 == 0, d6 != 0 */ + z1 = MULTIPLY(d2 + d6, FIX(0.541196100)); + tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065)); + tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865)); + + tmp10 = tmp3; + tmp13 = -tmp3; + tmp11 = tmp2; + tmp12 = -tmp2; + } + } else { + if (d0) { + /* d0 != 0, d2 == 0, d4 == 0, d6 != 0 */ + tmp2 = MULTIPLY(d6, - FIX2(1.306562965)); + tmp3 = MULTIPLY(d6, FIX(0.541196100)); + + tmp0 = d0 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + } else { + /* d0 == 0, d2 == 0, d4 == 0, d6 != 0 */ + tmp2 = MULTIPLY(d6, - FIX2(1.306562965)); + tmp3 = MULTIPLY(d6, FIX(0.541196100)); + + tmp10 = tmp3; + tmp13 = -tmp3; + tmp11 = tmp2; + tmp12 = -tmp2; + } + } + } + } else { + if (d4) { + if (d2) { + if (d0) { + /* d0 != 0, d2 != 0, d4 != 0, d6 == 0 */ + tmp2 = MULTIPLY(d2, FIX(0.541196100)); + tmp3 = (INT32) (MULTIPLY(d2, (FIX(1.306562965) + .5))); + + tmp0 = (d0 + d4) << CONST_BITS; + tmp1 = (d0 - d4) << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + } else { + /* d0 == 0, d2 != 0, d4 != 0, d6 == 0 */ + tmp2 = MULTIPLY(d2, FIX(0.541196100)); + tmp3 = (INT32) (MULTIPLY(d2, (FIX(1.306562965) + .5))); + + tmp0 = d4 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp2 - tmp0; + tmp12 = -(tmp0 + tmp2); + } + } else { + if (d0) { + /* d0 != 0, d2 == 0, d4 != 0, d6 == 0 */ + tmp10 = tmp13 = (d0 + d4) << CONST_BITS; + tmp11 = tmp12 = (d0 - d4) << CONST_BITS; + } else { + /* d0 == 0, d2 == 0, d4 != 0, d6 == 0 */ + tmp10 = tmp13 = d4 << CONST_BITS; + tmp11 = tmp12 = -tmp10; + } + } + } else { + if (d2) { + if (d0) { + /* d0 != 0, d2 != 0, d4 == 0, d6 == 0 */ + tmp2 = MULTIPLY(d2, FIX(0.541196100)); + tmp3 = (INT32) (MULTIPLY(d2, (FIX(1.306562965) + .5))); + + tmp0 = d0 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + } else { + /* d0 == 0, d2 != 0, d4 == 0, d6 == 0 */ + tmp2 = MULTIPLY(d2, FIX(0.541196100)); + tmp3 = (INT32) (MULTIPLY(d2, (FIX(1.306562965) + .5))); + + tmp10 = tmp3; + tmp13 = -tmp3; + tmp11 = tmp2; + tmp12 = -tmp2; + } + } else { + if (d0) { + /* d0 != 0, d2 == 0, d4 == 0, d6 == 0 */ + tmp10 = tmp13 = tmp11 = tmp12 = d0 << CONST_BITS; + } else { + /* d0 == 0, d2 == 0, d4 == 0, d6 == 0 */ + tmp10 = tmp13 = tmp11 = tmp12 = 0; + } + } + } + } + + /* Odd part per figure 8; the matrix is unitary and hence its + * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. + */ + if (d7) { + if (d5) { + if (d3) { + if (d1) { + /* d1 != 0, d3 != 0, d5 != 0, d7 != 0 */ + z1 = d7 + d1; + z2 = d5 + d3; + z3 = d7 + d3; + z4 = d5 + d1; + z5 = MULTIPLY(z3 + z4, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, FIX(0.298631336)); + tmp1 = MULTIPLY(d5, FIX(2.053119869)); + tmp2 = MULTIPLY(d3, FIX(3.072711026)); + tmp3 = MULTIPLY(d1, FIX(1.501321110)); + z1 = MULTIPLY(z1, - FIX(0.899976223)); + z2 = MULTIPLY(z2, - FIX(2.562915447)); + z3 = MULTIPLY(z3, - FIX(1.961570560)); + z4 = MULTIPLY(z4, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 += z2 + z4; + tmp2 += z2 + z3; + tmp3 += z1 + z4; + } else { + /* d1 == 0, d3 != 0, d5 != 0, d7 != 0 */ + z2 = d5 + d3; + z3 = d7 + d3; + z5 = MULTIPLY(z3 + d5, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, FIX(0.298631336)); + tmp1 = MULTIPLY(d5, FIX(2.053119869)); + tmp2 = MULTIPLY(d3, FIX(3.072711026)); + z1 = MULTIPLY(d7, - FIX(0.899976223)); + z2 = MULTIPLY(z2, - FIX(2.562915447)); + z3 = MULTIPLY(z3, - FIX(1.961570560)); + z4 = MULTIPLY(d5, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 += z2 + z4; + tmp2 += z2 + z3; + tmp3 = z1 + z4; + } + } else { + if (d1) { + /* d1 != 0, d3 == 0, d5 != 0, d7 != 0 */ + z1 = d7 + d1; + z4 = d5 + d1; + z5 = MULTIPLY(d7 + z4, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, FIX(0.298631336)); + tmp1 = MULTIPLY(d5, FIX(2.053119869)); + tmp3 = MULTIPLY(d1, FIX(1.501321110)); + z1 = MULTIPLY(z1, - FIX(0.899976223)); + z2 = MULTIPLY(d5, - FIX(2.562915447)); + z3 = MULTIPLY(d7, - FIX(1.961570560)); + z4 = MULTIPLY(z4, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 += z2 + z4; + tmp2 = z2 + z3; + tmp3 += z1 + z4; + } else { + /* d1 == 0, d3 == 0, d5 != 0, d7 != 0 */ + z5 = MULTIPLY(d5 + d7, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, - FIX2(0.601344887)); + tmp1 = MULTIPLY(d5, - FIX2(0.509795578)); + z1 = MULTIPLY(d7, - FIX(0.899976223)); + z3 = MULTIPLY(d7, - FIX(1.961570560)); + z2 = MULTIPLY(d5, - FIX(2.562915447)); + z4 = MULTIPLY(d5, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 += z3; + tmp1 += z4; + tmp2 = z2 + z3; + tmp3 = z1 + z4; + } + } + } else { + if (d3) { + if (d1) { + /* d1 != 0, d3 != 0, d5 == 0, d7 != 0 */ + z1 = d7 + d1; + z3 = d7 + d3; + z5 = MULTIPLY(z3 + d1, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, FIX(0.298631336)); + tmp2 = MULTIPLY(d3, FIX(3.072711026)); + tmp3 = MULTIPLY(d1, FIX(1.501321110)); + z1 = MULTIPLY(z1, - FIX(0.899976223)); + z2 = MULTIPLY(d3, - FIX(2.562915447)); + z3 = MULTIPLY(z3, - FIX(1.961570560)); + z4 = MULTIPLY(d1, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 = z2 + z4; + tmp2 += z2 + z3; + tmp3 += z1 + z4; + } else { + /* d1 == 0, d3 != 0, d5 == 0, d7 != 0 */ + z3 = d7 + d3; + z5 = MULTIPLY(z3, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, - FIX2(0.601344887)); + z1 = MULTIPLY(d7, - FIX(0.899976223)); + tmp2 = MULTIPLY(d3, FIX(0.509795579)); + z2 = MULTIPLY(d3, - FIX(2.562915447)); + z3 = MULTIPLY(z3, - FIX2(0.785694958)); + + tmp0 += z3; + tmp1 = z2 + z5; + tmp2 += z3; + tmp3 = z1 + z5; + } + } else { + if (d1) { + /* d1 != 0, d3 == 0, d5 == 0, d7 != 0 */ + z1 = d7 + d1; + z5 = MULTIPLY(z1, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, - FIX2(1.662939224)); + tmp3 = MULTIPLY(d1, FIX2(1.111140466)); + z1 = MULTIPLY(z1, FIX2(0.275899379)); + z3 = MULTIPLY(d7, - FIX(1.961570560)); + z4 = MULTIPLY(d1, - FIX(0.390180644)); + + tmp0 += z1; + tmp1 = z4 + z5; + tmp2 = z3 + z5; + tmp3 += z1; + } else { + /* d1 == 0, d3 == 0, d5 == 0, d7 != 0 */ + tmp0 = MULTIPLY(d7, - FIX2(1.387039845)); + tmp1 = MULTIPLY(d7, FIX(1.175875602)); + tmp2 = MULTIPLY(d7, - FIX2(0.785694958)); + tmp3 = MULTIPLY(d7, FIX2(0.275899379)); + } + } + } + } else { + if (d5) { + if (d3) { + if (d1) { + /* d1 != 0, d3 != 0, d5 != 0, d7 == 0 */ + z2 = d5 + d3; + z4 = d5 + d1; + z5 = MULTIPLY(d3 + z4, FIX(1.175875602)); + + tmp1 = MULTIPLY(d5, FIX(2.053119869)); + tmp2 = MULTIPLY(d3, FIX(3.072711026)); + tmp3 = MULTIPLY(d1, FIX(1.501321110)); + z1 = MULTIPLY(d1, - FIX(0.899976223)); + z2 = MULTIPLY(z2, - FIX(2.562915447)); + z3 = MULTIPLY(d3, - FIX(1.961570560)); + z4 = MULTIPLY(z4, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 = z1 + z3; + tmp1 += z2 + z4; + tmp2 += z2 + z3; + tmp3 += z1 + z4; + } else { + /* d1 == 0, d3 != 0, d5 != 0, d7 == 0 */ + z2 = d5 + d3; + z5 = MULTIPLY(z2, FIX(1.175875602)); + + tmp1 = MULTIPLY(d5, FIX2(1.662939225)); + tmp2 = MULTIPLY(d3, FIX2(1.111140466)); + z2 = MULTIPLY(z2, - FIX2(1.387039845)); + z3 = MULTIPLY(d3, - FIX(1.961570560)); + z4 = MULTIPLY(d5, - FIX(0.390180644)); + + tmp0 = z3 + z5; + tmp1 += z2; + tmp2 += z2; + tmp3 = z4 + z5; + } + } else { + if (d1) { + /* d1 != 0, d3 == 0, d5 != 0, d7 == 0 */ + z4 = d5 + d1; + z5 = MULTIPLY(z4, FIX(1.175875602)); + + tmp1 = MULTIPLY(d5, - FIX2(0.509795578)); + tmp3 = MULTIPLY(d1, FIX2(0.601344887)); + z1 = MULTIPLY(d1, - FIX(0.899976223)); + z2 = MULTIPLY(d5, - FIX(2.562915447)); + z4 = MULTIPLY(z4, FIX2(0.785694958)); + + tmp0 = z1 + z5; + tmp1 += z4; + tmp2 = z2 + z5; + tmp3 += z4; + } else { + /* d1 == 0, d3 == 0, d5 != 0, d7 == 0 */ + tmp0 = MULTIPLY(d5, FIX(1.175875602)); + tmp1 = MULTIPLY(d5, FIX2(0.275899380)); + tmp2 = MULTIPLY(d5, - FIX2(1.387039845)); + tmp3 = MULTIPLY(d5, FIX2(0.785694958)); + } + } + } else { + if (d3) { + if (d1) { + /* d1 != 0, d3 != 0, d5 == 0, d7 == 0 */ + z5 = d3 + d1; + + tmp2 = MULTIPLY(d3, - FIX(1.451774981)); + tmp3 = MULTIPLY(d1, (FIX(0.211164243) - 1)); + z1 = MULTIPLY(d1, FIX(1.061594337)); + z2 = MULTIPLY(d3, - FIX(2.172734803)); + z4 = MULTIPLY(z5, FIX(0.785694958)); + z5 = MULTIPLY(z5, FIX(1.175875602)); + + tmp0 = z1 - z4; + tmp1 = z2 + z4; + tmp2 += z5; + tmp3 += z5; + } else { + /* d1 == 0, d3 != 0, d5 == 0, d7 == 0 */ + tmp0 = MULTIPLY(d3, - FIX2(0.785694958)); + tmp1 = MULTIPLY(d3, - FIX2(1.387039845)); + tmp2 = MULTIPLY(d3, - FIX2(0.275899379)); + tmp3 = MULTIPLY(d3, FIX(1.175875602)); + } + } else { + if (d1) { + /* d1 != 0, d3 == 0, d5 == 0, d7 == 0 */ + tmp0 = MULTIPLY(d1, FIX2(0.275899379)); + tmp1 = MULTIPLY(d1, FIX2(0.785694958)); + tmp2 = MULTIPLY(d1, FIX(1.175875602)); + tmp3 = MULTIPLY(d1, FIX2(1.387039845)); + } else { + /* d1 == 0, d3 == 0, d5 == 0, d7 == 0 */ + tmp0 = tmp1 = tmp2 = tmp3 = 0; + } + } + } + } + + /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ + + dataptr[DCTSIZE*0] = (DCTELEM) DESCALE(tmp10 + tmp3, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp10 - tmp3, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp11 + tmp2, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(tmp11 - tmp2, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(tmp12 + tmp1, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12 - tmp1, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp13 + tmp0, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp13 - tmp0, + CONST_BITS+PASS1_BITS+3); + + dataptr++; /* advance pointer to next column */ + } +} + +#else + + + +/* + *-------------------------------------------------------------- + * + * j_rev_dct -- + * + * The original inverse DCT function. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ +void j_rev_dct (DCTBLOCK data) +{ + INT32 tmp0, tmp1, tmp2, tmp3; + INT32 tmp10, tmp11, tmp12, tmp13; + INT32 z1, z2, z3, z4, z5; + register DCTELEM *dataptr; + int rowctr; + SHIFT_TEMPS + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true IDCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + + dataptr = data; + for (rowctr = DCTSIZE-1; rowctr >= 0; rowctr--) { + /* Due to quantization, we will usually find that many of the input + * coefficients are zero, especially the AC terms. We can exploit this + * by short-circuiting the IDCT calculation for any row in which all + * the AC terms are zero. In that case each output is equal to the + * DC coefficient (with scale factor as needed). + * With typical images and quantization tables, half or more of the + * row DCT calculations can be simplified this way. + */ + + if ((dataptr[1] | dataptr[2] | dataptr[3] | dataptr[4] | + dataptr[5] | dataptr[6] | dataptr[7]) == 0) { + /* AC terms all zero */ + DCTELEM dcval = (DCTELEM) (dataptr[0] << PASS1_BITS); + + dataptr[0] = dcval; + dataptr[1] = dcval; + dataptr[2] = dcval; + dataptr[3] = dcval; + dataptr[4] = dcval; + dataptr[5] = dcval; + dataptr[6] = dcval; + dataptr[7] = dcval; + + dataptr += DCTSIZE; /* advance pointer to next row */ + continue; + } + + /* Even part: reverse the even part of the forward DCT. */ + /* The rotator is sqrt(2)*c(-6). */ + + z2 = (INT32) dataptr[2]; + z3 = (INT32) dataptr[6]; + + z1 = MULTIPLY(z2 + z3, FIX(0.541196100)); + tmp2 = z1 + MULTIPLY(z3, - FIX(1.847759065)); + tmp3 = z1 + MULTIPLY(z2, FIX(0.765366865)); + + tmp0 = ((INT32) dataptr[0] + (INT32) dataptr[4]) << CONST_BITS; + tmp1 = ((INT32) dataptr[0] - (INT32) dataptr[4]) << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + /* Odd part per figure 8; the matrix is unitary and hence its + * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. + */ + + tmp0 = (INT32) dataptr[7]; + tmp1 = (INT32) dataptr[5]; + tmp2 = (INT32) dataptr[3]; + tmp3 = (INT32) dataptr[1]; + + z1 = tmp0 + tmp3; + z2 = tmp1 + tmp2; + z3 = tmp0 + tmp2; + z4 = tmp1 + tmp3; + z5 = MULTIPLY(z3 + z4, FIX(1.175875602)); /* sqrt(2) * c3 */ + + tmp0 = MULTIPLY(tmp0, FIX(0.298631336)); /* sqrt(2) * (-c1+c3+c5-c7) */ + tmp1 = MULTIPLY(tmp1, FIX(2.053119869)); /* sqrt(2) * ( c1+c3-c5+c7) */ + tmp2 = MULTIPLY(tmp2, FIX(3.072711026)); /* sqrt(2) * ( c1+c3+c5-c7) */ + tmp3 = MULTIPLY(tmp3, FIX(1.501321110)); /* sqrt(2) * ( c1+c3-c5-c7) */ + z1 = MULTIPLY(z1, - FIX(0.899976223)); /* sqrt(2) * (c7-c3) */ + z2 = MULTIPLY(z2, - FIX(2.562915447)); /* sqrt(2) * (-c1-c3) */ + z3 = MULTIPLY(z3, - FIX(1.961570560)); /* sqrt(2) * (-c3-c5) */ + z4 = MULTIPLY(z4, - FIX(0.390180644)); /* sqrt(2) * (c5-c3) */ + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 += z2 + z4; + tmp2 += z2 + z3; + tmp3 += z1 + z4; + + /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ + + dataptr[0] = (DCTELEM) DESCALE(tmp10 + tmp3, CONST_BITS-PASS1_BITS); + dataptr[7] = (DCTELEM) DESCALE(tmp10 - tmp3, CONST_BITS-PASS1_BITS); + dataptr[1] = (DCTELEM) DESCALE(tmp11 + tmp2, CONST_BITS-PASS1_BITS); + dataptr[6] = (DCTELEM) DESCALE(tmp11 - tmp2, CONST_BITS-PASS1_BITS); + dataptr[2] = (DCTELEM) DESCALE(tmp12 + tmp1, CONST_BITS-PASS1_BITS); + dataptr[5] = (DCTELEM) DESCALE(tmp12 - tmp1, CONST_BITS-PASS1_BITS); + dataptr[3] = (DCTELEM) DESCALE(tmp13 + tmp0, CONST_BITS-PASS1_BITS); + dataptr[4] = (DCTELEM) DESCALE(tmp13 - tmp0, CONST_BITS-PASS1_BITS); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. */ + /* Note that we must descale the results by a factor of 8 == 2**3, */ + /* and also undo the PASS1_BITS scaling. */ + + dataptr = data; + for (rowctr = DCTSIZE-1; rowctr >= 0; rowctr--) { + /* Columns of zeroes can be exploited in the same way as we did with rows. + * However, the row calculation has created many nonzero AC terms, so the + * simplification applies less often (typically 5% to 10% of the time). + * On machines with very fast multiplication, it's possible that the + * test takes more time than it's worth. In that case this section + * may be commented out. + */ + +#ifndef NO_ZERO_COLUMN_TEST + if ((dataptr[DCTSIZE*1] | dataptr[DCTSIZE*2] | dataptr[DCTSIZE*3] | + dataptr[DCTSIZE*4] | dataptr[DCTSIZE*5] | dataptr[DCTSIZE*6] | + dataptr[DCTSIZE*7]) == 0) { + /* AC terms all zero */ + DCTELEM dcval = (DCTELEM) DESCALE((INT32) dataptr[0], PASS1_BITS+3); + + dataptr[DCTSIZE*0] = dcval; + dataptr[DCTSIZE*1] = dcval; + dataptr[DCTSIZE*2] = dcval; + dataptr[DCTSIZE*3] = dcval; + dataptr[DCTSIZE*4] = dcval; + dataptr[DCTSIZE*5] = dcval; + dataptr[DCTSIZE*6] = dcval; + dataptr[DCTSIZE*7] = dcval; + + dataptr++; /* advance pointer to next column */ + continue; + } +#endif + + /* Even part: reverse the even part of the forward DCT. */ + /* The rotator is sqrt(2)*c(-6). */ + + z2 = (INT32) dataptr[DCTSIZE*2]; + z3 = (INT32) dataptr[DCTSIZE*6]; + + z1 = MULTIPLY(z2 + z3, FIX(0.541196100)); + tmp2 = z1 + MULTIPLY(z3, - FIX(1.847759065)); + tmp3 = z1 + MULTIPLY(z2, FIX(0.765366865)); + + tmp0 = ((INT32) dataptr[DCTSIZE*0] + (INT32) dataptr[DCTSIZE*4]) << CONST_BITS; + tmp1 = ((INT32) dataptr[DCTSIZE*0] - (INT32) dataptr[DCTSIZE*4]) << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + /* Odd part per figure 8; the matrix is unitary and hence its + * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. + */ + + tmp0 = (INT32) dataptr[DCTSIZE*7]; + tmp1 = (INT32) dataptr[DCTSIZE*5]; + tmp2 = (INT32) dataptr[DCTSIZE*3]; + tmp3 = (INT32) dataptr[DCTSIZE*1]; + + z1 = tmp0 + tmp3; + z2 = tmp1 + tmp2; + z3 = tmp0 + tmp2; + z4 = tmp1 + tmp3; + z5 = MULTIPLY(z3 + z4, FIX(1.175875602)); /* sqrt(2) * c3 */ + + tmp0 = MULTIPLY(tmp0, FIX(0.298631336)); /* sqrt(2) * (-c1+c3+c5-c7) */ + tmp1 = MULTIPLY(tmp1, FIX(2.053119869)); /* sqrt(2) * ( c1+c3-c5+c7) */ + tmp2 = MULTIPLY(tmp2, FIX(3.072711026)); /* sqrt(2) * ( c1+c3+c5-c7) */ + tmp3 = MULTIPLY(tmp3, FIX(1.501321110)); /* sqrt(2) * ( c1+c3-c5-c7) */ + z1 = MULTIPLY(z1, - FIX(0.899976223)); /* sqrt(2) * (c7-c3) */ + z2 = MULTIPLY(z2, - FIX(2.562915447)); /* sqrt(2) * (-c1-c3) */ + z3 = MULTIPLY(z3, - FIX(1.961570560)); /* sqrt(2) * (-c3-c5) */ + z4 = MULTIPLY(z4, - FIX(0.390180644)); /* sqrt(2) * (c5-c3) */ + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 += z2 + z4; + tmp2 += z2 + z3; + tmp3 += z1 + z4; + + /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ + + dataptr[DCTSIZE*0] = (DCTELEM) DESCALE(tmp10 + tmp3, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp10 - tmp3, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp11 + tmp2, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(tmp11 - tmp2, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(tmp12 + tmp1, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12 - tmp1, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp13 + tmp0, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp13 - tmp0, + CONST_BITS+PASS1_BITS+3); + + dataptr++; /* advance pointer to next column */ + } +} + + +#endif /* ORIG_DCT */ +#endif /* FIVE_DCT */ + diff --git a/mpeglib/lib/mpegplay/jrevdct.h b/mpeglib/lib/mpegplay/jrevdct.h new file mode 100644 index 00000000..d280c2ce --- /dev/null +++ b/mpeglib/lib/mpegplay/jrevdct.h @@ -0,0 +1,57 @@ +/* + definittion for reverse dct + 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 __JREVDCT_H +#define __JREVDCT_H + +extern "C" { +#include <string.h> +} + +#include "proto.h" + + +#ifndef XMD_H +typedef int INT32; +typedef short INT16; +typedef char INT8; +#endif +typedef unsigned int UINT32; +typedef unsigned short UINT16; +typedef unsigned char UINT8; + + + +/* Definition of Contant integer scale factor. */ + +#define CONST_BITS 13 + +/* Misc DCT definitions */ +#define DCTSIZE 8 /* The basic DCT block is 8x8 samples */ +#define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */ + +#define GLOBAL /* a function referenced thru EXTERNs */ + +typedef short DCTELEM; +typedef DCTELEM DCTBLOCK[DCTSIZE2]; + + +/* jrevdct.c */ +void init_pre_idct (void); +void j_rev_dct_sparse (DCTBLOCK data , int pos); +void j_rev_dct (DCTBLOCK data); +void j_rev_dct_sparse (DCTBLOCK data , int pos); +void j_rev_dct (DCTBLOCK data); + + +#endif diff --git a/mpeglib/lib/mpegplay/macroBlock.cpp b/mpeglib/lib/mpegplay/macroBlock.cpp new file mode 100644 index 00000000..2e35e551 --- /dev/null +++ b/mpeglib/lib/mpegplay/macroBlock.cpp @@ -0,0 +1,1152 @@ +/* + stores macroblock infos + 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 "macroBlock.h" + +#define DEBUG_MACROBLOCK(x) +//#define DEBUG_MACROBLOCK(x) x + + + +MacroBlock::MacroBlock(VideoDecoder* vid_stream) { + this->vid_stream=vid_stream; + copyFunctions=new CopyFunctions(); +} + + +MacroBlock::~MacroBlock() { + delete copyFunctions; +} + + +/* + *-------------------------------------------------------------- + * + * ParseMacroBlock -- + * + * Parseoff macroblock. Reconstructs DCT values. Applies + * inverse DCT, reconstructs motion vectors, calculates and + * set pixel values for macroblock in current pict image + * structure. + * + * Results: + * Here's where everything really happens. Welcome to the + * heart of darkness. + * + * Side effects: + * Bit stream irreversibly parsed off. + * + *-------------------------------------------------------------- + */ + +int MacroBlock::processMacroBlock(PictureArray* pictureArray) { + unsigned int data; + int recon_right_for, recon_down_for, recon_right_back, + recon_down_back; + int mb_quant = 0, mb_motion_forw = 0, mb_motion_back = 0, + mb_pattern = 0; + + int addr_incr; + MpegVideoStream* mpegVideoStream=vid_stream->mpegVideoStream; + DecoderClass* decoderClass=vid_stream->decoderClass; + + /* + * Parse off macroblock address increment and add to macroblock address. + */ + do { + addr_incr=decoderClass->decodeMBAddrInc(); + if (addr_incr==MB_ESCAPE) { + mb_address += 33; + addr_incr=MB_STUFFING; + } + + } while (addr_incr == MB_STUFFING); + mb_address+=addr_incr; + + + + if (mb_address > (vid_stream->mpegVideoHeader)->getMB_Size()) { + + DEBUG_MACROBLOCK(cout <<"ParseMacroBlock: SKIP_TO_START_CODE"<<endl;) + DEBUG_MACROBLOCK(cout <<"mb_address "<<mb_address<<endl;) + + int h=(vid_stream->mpegVideoHeader)->getMB_Height(); + int w=(vid_stream->mpegVideoHeader)->getMB_Width(); + + + DEBUG_MACROBLOCK(cout <<"mb_height*mb_width-1:"<<(h*w - 1)<<endl;) + return false; + } + + /* + * If macroblocks have been skipped, process skipped macroblocks. + */ + + int code_type=(vid_stream->picture)->getCodeType(); + + if (mb_address - past_mb_addr > 1) { + + processSkippedPictures(pictureArray,code_type, + (vid_stream->mpegVideoHeader)->getMB_Width()); + + } + + + /* Set past macroblock address to current macroblock address. */ + past_mb_addr = mb_address; + /* Based on picture type decode macroblock type. */ + + + switch (code_type) { + case I_TYPE: + decoderClass->decodeMBTypeI(mb_quant, mb_motion_forw, + mb_motion_back, mb_pattern, + mb_intra); + break; + + case P_TYPE: + decoderClass->decodeMBTypeP(mb_quant, mb_motion_forw, + mb_motion_back, mb_pattern, + mb_intra); + break; + + case B_TYPE: + decoderClass->decodeMBTypeB(mb_quant, mb_motion_forw, + mb_motion_back, mb_pattern, + mb_intra); + break; + case D_TYPE: + DEBUG_MACROBLOCK(cout <<"ERROR: MPEG-1 Streams with D-frames are not supported"<<endl;) + return false; + + } + /* If quantization flag set, parse off new quantization scale. */ + if (mb_quant == true) { + data=mpegVideoStream->getBits(5); + (vid_stream->slice)->setQuantScale(data); + } + /* If forward motion vectors exist... */ + + if (mb_motion_forw == true) { + // Parse off and decode horizontal forward motion vector. + motion_h_forw_code=decoderClass->decodeMotionVectors(); + + // If horiz. forward r data exists, parse off. + + if ((vid_stream->picture->getForw_f() != 1) && + (motion_h_forw_code != 0)) { + data=vid_stream->picture->geth_forw_r(mpegVideoStream); + motion_h_forw_r = data; + } + // Parse off and decode vertical forward motion vector. + + motion_v_forw_code=decoderClass->decodeMotionVectors(); + + // If vert. forw. r data exists, parse off. + + if ((vid_stream->picture->getForw_f() != 1) && + (motion_v_forw_code != 0)) { + + data=vid_stream->picture->getv_forw_r(mpegVideoStream); + motion_v_forw_r = data; + } + } + + /* If back motion vectors exist... */ + + if (mb_motion_back == true) { + // Parse off and decode horiz. back motion vector. + motion_h_back_code=decoderClass->decodeMotionVectors(); + + // If horiz. back r data exists, parse off. + + if ((vid_stream->picture->getBack_f() != 1) && + (motion_h_back_code != 0)) { + data=vid_stream->picture->geth_back_r(mpegVideoStream); + motion_h_back_r = data; + } + // Parse off and decode vert. back motion vector. + motion_v_back_code=decoderClass->decodeMotionVectors(); + + // If vert. back r data exists, parse off. + + if ((vid_stream->picture->getBack_f() != 1) && + (motion_v_back_code != 0)) { + data=vid_stream->picture->getv_back_r(mpegVideoStream); + motion_v_back_r = data; + } + } + + /* If mblock pattern flag set, parse and decode CBP (code block pattern). */ + if (mb_pattern == true) { + cbp=decoderClass->decodeCBP(); + } + /* Otherwise, set CBP to zero. */ + else + cbp = 0; + + + + /* Reconstruct motion vectors depending on picture type. */ + if (code_type == P_TYPE) { + + /* + * If no forw motion vectors, reset previous and current vectors to 0. + */ + if (!mb_motion_forw) { + recon_right_for = 0; + recon_down_for = 0; + recon_right_for_prev = 0; + recon_down_for_prev = 0; + } + /* + * Otherwise, compute new forw motion vectors. Reset previous vectors to + * current vectors. + */ + + else { + computeForwVector(&recon_right_for, &recon_down_for); + + } + } + if (code_type == B_TYPE) { + + /* Reset prev. and current vectors to zero if mblock is intracoded. */ + if (mb_intra) { + recon_right_for_prev = 0; + recon_down_for_prev = 0; + recon_right_back_prev = 0; + recon_down_back_prev = 0; + } else { + + /* If no forw vectors, current vectors equal prev. vectors. */ + + if (!mb_motion_forw) { + recon_right_for = recon_right_for_prev; + recon_down_for = recon_down_for_prev; + } + /* + * Otherwise compute forw. vectors. Reset prev vectors to new values. + */ + + else { + computeForwVector(&recon_right_for, &recon_down_for); + + } + + /* If no back vectors, set back vectors to prev back vectors. */ + + if (!mb_motion_back) { + recon_right_back = recon_right_back_prev; + recon_down_back = recon_down_back_prev; + } + /* Otherwise compute new vectors and reset prev. back vectors. */ + + else { + computeBackVector(&recon_right_back,&recon_down_back); + + } + + /* + * Store vector existence flags in structure for possible skipped + * macroblocks to follow. + */ + + bpict_past_forw = mb_motion_forw; + bpict_past_back = mb_motion_back; + } + } + int back; + back=reconstruct(recon_right_for, + recon_down_for, + recon_right_back, + recon_down_back, + mb_motion_forw, + mb_motion_back, + pictureArray); + + + /* If D Type picture, flush marker bit. */ + if (code_type == D_TYPE) { + mpegVideoStream->flushBits(1); + } + + /* If macroblock was intracoded, set macroblock past intra address. */ + if (mb_intra) { + past_intra_addr=mb_address; + } + if (back == false) { + return false; + } + return true; +} + + +int MacroBlock::resetMacroBlock() { + /* Reset past intrablock address. */ + past_intra_addr = -2; + + /* Reset previous recon motion vectors. */ + + + recon_right_for_prev = 0; + recon_down_for_prev = 0; + recon_right_back_prev = 0; + recon_down_back_prev = 0; + + /* Reset macroblock address. */ + mb_address = (((vid_stream->slice)->getVertPos()-1) * + (vid_stream->mpegVideoHeader)->getMB_Width()) - 1; + return true; + +} + + +int MacroBlock::resetPastMacroBlock() { + /* Reset past macroblock address field. */ + + past_mb_addr = -1; + return true; +} + + + + +int MacroBlock::reconstruct(int& recon_right_for, + int& recon_down_for, + int& recon_right_back, + int& recon_down_back, + int& mb_motion_forw, + int& mb_motion_back, + PictureArray* pictureArray) { + int mask, i; + int zero_block_flag; + int mb_row; + int mb_col; + int mb_width=(vid_stream->mpegVideoHeader)->getMB_Width(); + int row_size=pictureArray->getWidth(); + short int* dct_start=(vid_stream->decoderClass)->getDCT(); + unsigned int qscale=(vid_stream->slice)->getQuantScale(); + int codeType=(vid_stream->picture)->getCodeType(); + DecoderClass* decoderClass=vid_stream->decoderClass; + int lflag=false; + Recon* recon=vid_stream->recon; + unsigned int* iqmatrixptr= + (vid_stream->mpegVideoHeader)->getIntra_quant_matrix(); + unsigned int* niqmatrixptr= + (vid_stream->mpegVideoHeader)->getNon_intra_quant_matrix(); + + + + + + if (mb_address-past_intra_addr > 1) { + lflag=true; + } + + if (mb_width <= 0) { + DEBUG_MACROBLOCK(cout << "mb_width <= 0"<<endl;) + return false; + } + /* Calculate macroblock row and column from address. */ + mb_row=mb_address / mb_width; + mb_col=mb_address % mb_width; + + copyFunctions->startNOFloatSection(); + + for (mask = 32, i = 0; i < 6; mask >>= 1, i++) { + + + /* If block exists... */ + if ((mb_intra) || (cbp & mask)) { + zero_block_flag = 0; + //copyFunctions->endNOFloatSection(); + decoderClass->ParseReconBlock(i,mb_intra, + qscale,lflag,iqmatrixptr,niqmatrixptr); + //copyFunctions->endNOFloatSection(); + } else { + zero_block_flag = 1; + } + + + // If macroblock is intra coded... + + + if (mb_intra) { + recon->ReconIMBlock(i,mb_row,mb_col,row_size, + dct_start,pictureArray); + //copyFunctions->endNOFloatSection(); + } else if (mb_motion_forw && mb_motion_back) { + recon->ReconBiMBlock(i,recon_right_for, + recon_down_for,recon_right_back, + recon_down_back,zero_block_flag, + mb_row,mb_col,row_size,dct_start, + pictureArray); + //copyFunctions->endNOFloatSection(); + } else if (mb_motion_forw || (codeType ==P_TYPE)){ + recon->ReconPMBlock(i,recon_right_for, + recon_down_for,zero_block_flag, + mb_row,mb_col,row_size,dct_start, + pictureArray, codeType); + //copyFunctions->endNOFloatSection(); + } else if (mb_motion_back) { + recon->ReconBMBlock(i,recon_right_back, + recon_down_back,zero_block_flag, + mb_row,mb_col,row_size,dct_start, + pictureArray); + //copyFunctions->endNOFloatSection(); + + } else { + //DEBUG_MACROBLOCK(cout << "nothing"<<endl;) + } + + } + copyFunctions->endNOFloatSection(); + return true; +} + +/* + *-------------------------------------------------------------- + * + * ComputeForwVector -- + * + * Computes forward motion vector by calling ComputeVector + * with appropriate parameters. + * + * Results: + * Reconstructed motion vector placed in recon_right_for_ptr and + * recon_down_for_ptr. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +void MacroBlock::computeForwVector(int* recon_right_for_ptr, + int* recon_down_for_ptr) { + + Picture *picture; + + + picture = vid_stream->picture; + + + unsigned int forw_f=picture->getForw_f(); + unsigned int full_pel_forw_vector=picture->getFull_pel_forw_vector(); + vid_stream->motionVector->computeVector(recon_right_for_ptr, + recon_down_for_ptr, + recon_right_for_prev, + recon_down_for_prev, + forw_f, + full_pel_forw_vector, + motion_h_forw_code, + motion_v_forw_code, + motion_h_forw_r, + motion_v_forw_r); + picture->setForw_f(forw_f); + picture->setFull_pel_forw_vector(full_pel_forw_vector); +} + + +/* + *-------------------------------------------------------------- + * + * ComputeBackVector -- + * + * Computes backward motion vector by calling ComputeVector + * with appropriate parameters. + * + * Results: + * Reconstructed motion vector placed in recon_right_back_ptr and + * recon_down_back_ptr. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +void MacroBlock::computeBackVector(int* recon_right_back_ptr, + int* recon_down_back_ptr) { + + Picture *picture; + + + picture = vid_stream->picture; + + + unsigned int back_f=picture->getBack_f(); + unsigned int full_pel_back_vector=picture->getFull_pel_back_vector(); + + vid_stream->motionVector->computeVector(recon_right_back_ptr, + recon_down_back_ptr, + recon_right_back_prev, + recon_down_back_prev, + back_f, + full_pel_back_vector, + motion_h_back_code, + motion_v_back_code, + motion_h_back_r, + motion_v_back_r); + picture->setBack_f(back_f); + picture->setFull_pel_back_vector(full_pel_back_vector); +} + + + + + +int MacroBlock::processSkippedPictures(PictureArray* pictureArray, + int code_type, + int mb_width) { + copyFunctions->startNOFloatSection(); + + if (code_type == P_TYPE) { + + ProcessSkippedPFrameMBlocks(pictureArray->getCurrent(), + pictureArray->getFuture(), + mb_width); + + } else { + if (code_type == B_TYPE) { + ProcessSkippedBFrameMBlocks(vid_stream->picture, + pictureArray->getPast(), + pictureArray->getCurrent(), + pictureArray->getFuture(), + mb_width); + } + } + + copyFunctions->endNOFloatSection(); + + return true; +} + +/* + *-------------------------------------------------------------- + * + * ProcessSkippedPFrameMBlocks -- + * + * Processes skipped macroblocks in P frames. + * + * Results: + * Calculates pixel values for luminance, Cr, and Cb planes + * in current pict image for skipped macroblocks. + * + * Side effects: + * Pixel values in pict image changed. + * + *-------------------------------------------------------------- + */ +void MacroBlock::ProcessSkippedPFrameMBlocks(YUVPicture* current, + YUVPicture* future, + int mb_width) { + + int row_size, half_row, mb_row, mb_col, row, col, rr; + int addr, row_incr, half_row_incr, crow, ccol; + int *dest, *src, *dest1, *src1; + + /* For each row in macroblock luminance plane... */ + if (mb_width == 0) { + DEBUG_MACROBLOCK(cout << "mb_width in skipped is 0"<<endl;) + return; + } + + + /* Calculate row sizes for luminance and Cr/Cb macroblock areas. */ + + row_size = mb_width << 4; + half_row = (row_size >> 1); + row_incr = row_size >> 2; + half_row_incr = half_row >> 2; + + /* For each skipped macroblock, do... */ + int lumEnd=current->getLumLength(); + int colorEnd=current->getColorLength(); + + unsigned char *picDest; + unsigned char *picSrc; + + unsigned char *picDestStart; + unsigned char *picSrcStart; + + + + for (addr = past_mb_addr + 1; addr < mb_address; addr++) { + + /* Calculate macroblock row and col. */ + + mb_row = addr / mb_width; + mb_col = addr % mb_width; + + /* Calculate upper left pixel row,col for luminance plane. */ + + row = mb_row << 4; + col = mb_col << 4; + + picDest=current->getLuminancePtr(); + picSrc=future->getLuminancePtr(); + + picDestStart=(picDest+(row*row_size)+col); + picSrcStart=(picSrc+(row*row_size)+col); + + if ((picDestStart+7*row_size+7 >= picDest+lumEnd) || + (picDestStart < picDest)) { + DEBUG_MACROBLOCK(cout << "urg! last resort caught before sigsev skipped -1"<<endl;) + break; + } + if ((picSrcStart+7*row_size+7 >= picSrc+lumEnd) || + (picSrcStart < picSrc)) { + DEBUG_MACROBLOCK(cout << "urg! last resort caught before sigsev skipped -2"<<endl;) + break; + } + + dest=(int*)picDestStart; + src=(int*)picSrcStart; + + + + for (rr = 0; rr < 8; rr++) { + + /* Copy pixel values from last I or P picture. */ + memcpy(dest,src,sizeof(int)*4); + + dest += row_incr; + src += row_incr; + memcpy(dest,src,sizeof(int)*4); + + dest += row_incr; + src += row_incr; + } + + /* + * Divide row,col to get upper left pixel of macroblock in Cr and Cb + * planes. + */ + + crow = row >> 1; + ccol = col >> 1; + + /* For each row in Cr, and Cb planes... */ + picDest=current->getCrPtr(); + picDestStart=(picDest+(crow*half_row)+ccol); + if ((picDestStart+7*half_row_incr+7 >= picDest+colorEnd) || + (picDestStart < picDest)) { + DEBUG_MACROBLOCK(cout << "urg! last resort caught before sigsev skipped -3"<<endl;) + break; + } + + + dest=(int*)(current->getCrPtr()+(crow*half_row)+ccol); + src=(int*)(future->getCrPtr()+(crow*half_row)+ccol); + dest1=(int*)(current->getCbPtr()+(crow*half_row)+ccol); + src1=(int*)(future->getCbPtr()+(crow*half_row)+ccol); + + for (rr = 0; rr < 4; rr++) { + + /* Copy pixel values from last I or P picture. */ + memcpy(dest,src,sizeof(int)*2); + memcpy(dest1,src1,sizeof(int)*2); + + + dest += half_row_incr; + src += half_row_incr; + dest1 += half_row_incr; + src1 += half_row_incr; + + memcpy(dest,src,sizeof(int)*2); + memcpy(dest1,src1,sizeof(int)*2); + + dest += half_row_incr; + src += half_row_incr; + dest1 += half_row_incr; + src1 += half_row_incr; + } + + } + + recon_right_for_prev = 0; + recon_down_for_prev = 0; + +} + + + + + +/* + *-------------------------------------------------------------- + * + * ProcessSkippedBFrameMBlocks -- + * + * Processes skipped macroblocks in B frames. + * + * Results: + * Calculates pixel values for luminance, Cr, and Cb planes + * in current pict image for skipped macroblocks. + * + * Side effects: + * Pixel values in pict image changed. + * + *-------------------------------------------------------------- + */ + +void MacroBlock::ProcessSkippedBFrameMBlocks(Picture* picture, + YUVPicture* past, + YUVPicture* current, + YUVPicture* future, + int mb_width) { + int row_size, half_row, mb_row, mb_col, row, col, rr; + int right_half_for = 0, down_half_for = 0; + int c_right_half_for = 0, c_down_half_for = 0; + int right_half_back = 0, down_half_back = 0; + int c_right_half_back = 0, c_down_half_back = 0; + int addr, right_for = 0, down_for = 0; + int recon_right_for, recon_down_for; + int recon_right_back, recon_down_back; + int right_back = 0, down_back = 0; + int c_right_for = 0, c_down_for = 0; + int c_right_back = 0, c_down_back = 0; + unsigned char forw_lum[256]; + unsigned char forw_cr[64], forw_cb[64]; + unsigned char back_lum[256], back_cr[64], back_cb[64]; + int row_incr, half_row_incr; + int ccol, crow; + + + /* Calculate row sizes for luminance and Cr/Cb macroblock areas. */ + + if (mb_width == 0) { + DEBUG_MACROBLOCK(cout << "mb_width in skipped is 0 (2)"<<endl;) + return; + } + + row_size = mb_width << 4; + half_row = (row_size >> 1); + row_incr = row_size >> 2; + half_row_incr = half_row >> 2; + + /* Establish motion vector codes based on full pixel flag. */ + + if (picture->getFull_pel_forw_vector()) { + recon_right_for = recon_right_for_prev << 1; + recon_down_for = recon_down_for_prev << 1; + } else { + recon_right_for = recon_right_for_prev; + recon_down_for = recon_down_for_prev; + } + + if (picture->getFull_pel_back_vector()) { + recon_right_back = recon_right_back_prev << 1; + recon_down_back = recon_down_back_prev << 1; + } else { + recon_right_back = recon_right_back_prev; + recon_down_back = recon_down_back_prev; + } + + + /* If only one motion vector, do display copy, else do full + calculation. + */ + + /* Calculate motion vectors. */ + + if (bpict_past_forw) { + right_for = recon_right_for >> 1; + down_for = recon_down_for >> 1; + right_half_for = recon_right_for & 0x1; + down_half_for = recon_down_for & 0x1; + + recon_right_for /= 2; + recon_down_for /= 2; + c_right_for = recon_right_for >> 1; + c_down_for = recon_down_for >> 1; + c_right_half_for = recon_right_for & 0x1; + c_down_half_for = recon_down_for & 0x1; + + } + if (bpict_past_back) { + right_back = recon_right_back >> 1; + down_back = recon_down_back >> 1; + right_half_back = recon_right_back & 0x1; + down_half_back = recon_down_back & 0x1; + + recon_right_back /= 2; + recon_down_back /= 2; + c_right_back = recon_right_back >> 1; + c_down_back = recon_down_back >> 1; + c_right_half_back = recon_right_back & 0x1; + c_down_half_back = recon_down_back & 0x1; + + } + /* For each skipped macroblock, do... */ + + for (addr = past_mb_addr + 1; + addr < mb_address; addr++) { + + /* Calculate macroblock row and col. */ + + mb_row = addr / mb_width; + mb_col = addr % mb_width; + + /* Calculate upper left pixel row,col for luminance plane. */ + + row = mb_row << 4; + col = mb_col << 4; + crow = row / 2; + ccol = col / 2; + + /* If forward predicted, calculate prediction values. */ + if (bpict_past_forw) { + int lumEnd=current->getLumLength(); + int colorEnd=current->getColorLength(); + ReconSkippedBlock(past->getLuminancePtr(), + forw_lum,row,col,row_size, + right_for,down_for, + right_half_for, + down_half_for,16,lumEnd); + ReconSkippedBlock(past->getCrPtr(), + forw_cr,crow,ccol, half_row, + c_right_for,c_down_for, + c_right_half_for, + c_down_half_for,8,colorEnd); + ReconSkippedBlock(past->getCbPtr(), + forw_cb,crow,ccol,half_row, + c_right_for,c_down_for, + c_right_half_for, + c_down_half_for,8,colorEnd); + } + /* If back predicted, calculate prediction values. */ + + if (bpict_past_back) { + int lumEnd=current->getLumLength(); + int colorEnd=current->getColorLength(); + ReconSkippedBlock(future->getLuminancePtr(), + back_lum,row,col,row_size, + right_back,down_back, + right_half_back,down_half_back, + 16,lumEnd); + ReconSkippedBlock(future->getCrPtr(), + back_cr,crow,ccol, + half_row,c_right_back, + c_down_back,c_right_half_back, + c_down_half_back,8,colorEnd); + ReconSkippedBlock(future->getCbPtr(), + back_cb,crow,ccol,half_row, + c_right_back,c_down_back, + c_right_half_back, + c_down_half_back,8,colorEnd); + } + unsigned char* picDest=current->getLuminancePtr(); + int lumEnd=current->getLumLength(); + int colorEnd=current->getColorLength(); + + unsigned char* picDestStart=(picDest+(row*row_size)+col); + + + if ((picDestStart+7*row_size+7 >= picDest+lumEnd) || + (picDestStart < picDest)) { + DEBUG_MACROBLOCK(cout << "urg! last resort caught before sigsev skipped -4"<<endl;) + return; + } + + picDest=current->getCrPtr(); + picDestStart=(picDest+(crow*half_row)+ccol); + if ((picDestStart+7*half_row_incr+7 >= picDest+colorEnd) || + (picDestStart < picDest)) { + DEBUG_MACROBLOCK(cout << "urg! last resort caught before sigsev skipped -5"<<endl;) + exit(0); + } + + + if (bpict_past_forw && !bpict_past_back) { + + int *dest, *dest1; + int *src, *src1; + dest=(int*)(current->getLuminancePtr()+(row*row_size)+col); + src=(int*)forw_lum; + + for (rr = 0; rr < 16; rr++) { + + /* memcpy(dest, forw_lum+(rr<<4), 16); */ + + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + dest[3] = src[3]; + dest += row_incr; + src += 4; + } + + dest = (int*)(current->getCrPtr()+(crow*half_row)+ccol); + dest1 = (int*)(current->getCbPtr()+(crow*half_row)+ccol); + src = (int*)forw_cr; + src1 = (int*)forw_cb; + + for (rr = 0; rr < 8; rr++) { + /* + * memcpy(dest, forw_cr+(rr<<3), 8); memcpy(dest1, forw_cb+(rr<<3), + * 8); + */ + + dest[0] = src[0]; + dest[1] = src[1]; + + dest1[0] = src1[0]; + dest1[1] = src1[1]; + + dest += half_row_incr; + dest1 += half_row_incr; + src += 2; + src1 += 2; + } + } else if (bpict_past_back && !bpict_past_forw) { + + int *src, *src1; + int *dest, *dest1; + dest=(int*)(current->getLuminancePtr()+(row*row_size)+col); + src = (int*)back_lum; + + for (rr = 0; rr < 16; rr++) { + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + dest[3] = src[3]; + dest += row_incr; + src += 4; + } + + + dest = (int *)(current->getCrPtr()+(crow*half_row)+ccol); + dest1 = (int *)(current->getCbPtr()+(crow*half_row)+ccol); + src = (int *)back_cr; + src1 = (int *)back_cb; + + for (rr = 0; rr < 8; rr++) { + /* + * memcpy(dest, back_cr+(rr<<3), 8); memcpy(dest1, back_cb+(rr<<3), + * 8); + */ + + dest[0] = src[0]; + dest[1] = src[1]; + + dest1[0] = src1[0]; + dest1[1] = src1[1]; + + dest += half_row_incr; + dest1 += half_row_incr; + src += 2; + src1 += 2; + } + } else { + + unsigned char *src1, *src2, *src1a, *src2a; + unsigned char *dest, *dest1; + dest = current->getLuminancePtr()+(row*row_size)+col; + src1 = forw_lum; + src2 = back_lum; + + for (rr = 0; rr < 16; rr++) { + dest[0] = (int) (src1[0] + src2[0]) >> 1; + dest[1] = (int) (src1[1] + src2[1]) >> 1; + dest[2] = (int) (src1[2] + src2[2]) >> 1; + dest[3] = (int) (src1[3] + src2[3]) >> 1; + dest[4] = (int) (src1[4] + src2[4]) >> 1; + dest[5] = (int) (src1[5] + src2[5]) >> 1; + dest[6] = (int) (src1[6] + src2[6]) >> 1; + dest[7] = (int) (src1[7] + src2[7]) >> 1; + dest[8] = (int) (src1[8] + src2[8]) >> 1; + dest[9] = (int) (src1[9] + src2[9]) >> 1; + dest[10] = (int) (src1[10] + src2[10]) >> 1; + dest[11] = (int) (src1[11] + src2[11]) >> 1; + dest[12] = (int) (src1[12] + src2[12]) >> 1; + dest[13] = (int) (src1[13] + src2[13]) >> 1; + dest[14] = (int) (src1[14] + src2[14]) >> 1; + dest[15] = (int) (src1[15] + src2[15]) >> 1; + dest += row_size; + src1 += 16; + src2 += 16; + } + + + dest = current->getCrPtr() + (crow * half_row) + ccol; + dest1 = current->getCbPtr() + (crow * half_row) + ccol; + src1 = forw_cr; + src2 = back_cr; + src1a = forw_cb; + src2a = back_cb; + + for (rr = 0; rr < 8; rr++) { + dest[0] = (int) (src1[0] + src2[0]) >> 1; + dest[1] = (int) (src1[1] + src2[1]) >> 1; + dest[2] = (int) (src1[2] + src2[2]) >> 1; + dest[3] = (int) (src1[3] + src2[3]) >> 1; + dest[4] = (int) (src1[4] + src2[4]) >> 1; + dest[5] = (int) (src1[5] + src2[5]) >> 1; + dest[6] = (int) (src1[6] + src2[6]) >> 1; + dest[7] = (int) (src1[7] + src2[7]) >> 1; + dest += half_row; + src1 += 8; + src2 += 8; + + dest1[0] = (int) (src1a[0] + src2a[0]) >> 1; + dest1[1] = (int) (src1a[1] + src2a[1]) >> 1; + dest1[2] = (int) (src1a[2] + src2a[2]) >> 1; + dest1[3] = (int) (src1a[3] + src2a[3]) >> 1; + dest1[4] = (int) (src1a[4] + src2a[4]) >> 1; + dest1[5] = (int) (src1a[5] + src2a[5]) >> 1; + dest1[6] = (int) (src1a[6] + src2a[6]) >> 1; + dest1[7] = (int) (src1a[7] + src2a[7]) >> 1; + dest1 += half_row; + src1a += 8; + src2a += 8; + } + } + + } +} + + + + + + + +/* + *-------------------------------------------------------------- + * + * ReconSkippedBlock -- + * + * Reconstructs predictive block for skipped macroblocks + * in B Frames. + * + * Results: + * No return values. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ +void MacroBlock::ReconSkippedBlock(unsigned char* source, + unsigned char* dest, + int row, + int col, + int row_size, + int right, + int down, + int right_half, + int down_half, + int width,int maxLen) { + int rr; + unsigned char *source2; + unsigned char *tmp; + + tmp = source+((row + down) * row_size) + col + right; + + + if ((tmp+7*row_size+7 >= source+maxLen) || + (tmp < source)) { + DEBUG_MACROBLOCK(cout << "urg! last resort caught before sigsev skipped -6"<<endl;) + return; + } + + source=tmp; + if (width == 16) { + if ((!right_half) && (!down_half)) { + if (right & 0x1) { + /* No alignment, use bye copy */ + for (rr = 0; rr < 16; rr++) { + + memcpy(dest,source,sizeof(char)*16); + + dest += 16; + source += row_size; + } + } else if (right & 0x2) { + /* Half-word bit aligned, use 16 bit copy */ + short *src = (short *)source; + short *d = (short *)dest; + row_size >>= 1; + for (rr = 0; rr < 16; rr++) { + + memcpy(d,src,sizeof(short)*8); + + d += 8; + src += row_size; + } + } else { + /* Word aligned, use 32 bit copy */ + int *src = (int *)source; + int *d = (int *)dest; + row_size >>= 2; + for (rr = 0; rr < 16; rr++) { + d[0] = src[0]; + d[1] = src[1]; + d[2] = src[2]; + d[3] = src[3]; + d += 4; + src += row_size; + } + } + } else { + source2 = source + right_half + (row_size * down_half); + copyFunctions->copy16_div2_destlinear_nocrop(source,source2,dest, + row_size); + + + } + } else { /* (width == 8) */ + assert(width == 8); + if ((!right_half) && (!down_half)) { + if (right & 0x1) { + for (rr = 0; rr < width; rr++) { + + memcpy(dest,source,sizeof(char)*8); + + dest += 8; + source += row_size; + } + } else if (right & 0x02) { + short *d = (short *)dest; + short *src = (short *)source; + row_size >>= 1; + for (rr = 0; rr < width; rr++) { + d[0] = src[0]; + d[1] = src[1]; + d[2] = src[2]; + d[3] = src[3]; + d += 4; + src += row_size; + } + } else { + int *d = (int *)dest; + int *src = (int *)source; + row_size >>= 2; + for (rr = 0; rr < width; rr++) { + d[0] = src[0]; + d[1] = src[1]; + d += 2; + src += row_size; + } + } + } else { + source2 = source + right_half + (row_size * down_half); + copyFunctions->copy8_div2_destlinear_nocrop(source,source2, + dest,row_size); + } + } +} + diff --git a/mpeglib/lib/mpegplay/macroBlock.h b/mpeglib/lib/mpegplay/macroBlock.h new file mode 100644 index 00000000..db56e7be --- /dev/null +++ b/mpeglib/lib/mpegplay/macroBlock.h @@ -0,0 +1,97 @@ +/* + stores macroblock infos + 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 __MACROBLOCK_H +#define __MACROBLOCK_H + +#include "videoDecoder.h" +#include "decoderClass.h" +#include "motionVector.h" +#include "recon.h" +#include "copyFunctions.h" + +class MacroBlock { + + /* Macroblock structure. */ + + int mb_address; /* Macroblock address. */ + int past_mb_addr; /* Previous mblock address. */ + int motion_h_forw_code; /* Forw. horiz. motion vector code. */ + unsigned int motion_h_forw_r; /* Used in decoding vectors. */ + int motion_v_forw_code; /* Forw. vert. motion vector code. */ + unsigned int motion_v_forw_r; /* Used in decdoinge vectors. */ + int motion_h_back_code; /* Back horiz. motion vector code. */ + unsigned int motion_h_back_r; /* Used in decoding vectors. */ + int motion_v_back_code; /* Back vert. motion vector code. */ + unsigned int motion_v_back_r; /* Used in decoding vectors. */ + unsigned int cbp; /* Coded block pattern. */ + int mb_intra; /* Intracoded mblock flag. */ + int bpict_past_forw; /* Past B frame forw. vector flag. */ + int bpict_past_back; /* Past B frame back vector flag. */ + int past_intra_addr; /* Addr of last intracoded mblock. */ + int recon_right_for_prev; /* Past right forw. vector. */ + int recon_down_for_prev; /* Past down forw. vector. */ + int recon_right_back_prev; /* Past right back vector. */ + int recon_down_back_prev; /* Past down back vector. */ + + class VideoDecoder* vid_stream; + CopyFunctions* copyFunctions; + + public: + MacroBlock(class VideoDecoder* vid_stream); + ~MacroBlock(); + int processMacroBlock(PictureArray* pictureArray); + int resetMacroBlock(); + int resetPastMacroBlock(); + + private: + int reconstruct(int& recon_right_for, + int& recon_down_for, + int& recon_right_back, + int& recon_down_back, + int& mb_motion_forw, + int& mb_motion_back, + PictureArray* pictureArray); + + void computeForwVector(int* recon_right_for_ptr, + int* recon_down_for_ptr); + + void computeBackVector(int* recon_right_back_ptr, + int* recon_down_back_ptr); + + int processSkippedPictures(PictureArray* pictureArray, + int code_type, + int mb_width); + + void ProcessSkippedPFrameMBlocks(YUVPicture* current, + YUVPicture* future, + int mb_width); + + + void ProcessSkippedBFrameMBlocks(Picture* picture, + YUVPicture* past, + YUVPicture* current, + YUVPicture* future, + int mb_width); + + + void ReconSkippedBlock(unsigned char* source,unsigned char* dest, + int row, int col,int row_size, + int right,int down, + int right_half,int down_half,int width, + int maxLen); + + +}; +#endif diff --git a/mpeglib/lib/mpegplay/mainMpegPlay.cpp b/mpeglib/lib/mpegplay/mainMpegPlay.cpp new file mode 100644 index 00000000..1c3d9659 --- /dev/null +++ b/mpeglib/lib/mpegplay/mainMpegPlay.cpp @@ -0,0 +1,179 @@ +/* + * main.c -- + * + * Example program for mpegplay library. + * Build with : + BUILD with:(if you have intel mmx) + + + g++ -DINTEL -I/usr/X11R6/include -I.. \ + -o mpegplay mainMpegPlay.cpp -L/usr/X11R6/lib \ + ../.libs/libmpeg.a -lX11 -lXext -lXv -lXxf86dga \ + -lXxf86dga -lpthread + + */ + + +#include "mpegPlugin.h" +#include "../output/outPlugin.h" +#include "mpegVideoLength.h" + +// Includes for non plugin version +#define _NO_PLUGIN_VERSION +//#define _PLUGIN_VERSION + + +#ifdef _NO_PLUGIN_VERSION + +int main(int argc, char** argv) { + + + + if (argc <= 1) { + printf("Usage:\n\n"); + printf("%s filename\n\n",argv[0]); + exit(0); + } + cout << "open -s 1"<<endl; + + InputStream* input=InputPlugin::createInputStream(argv[1]); + OutputStream* output=OutPlugin::createOutputStream(_OUTPUT_LOCAL); + + output->config("performance","true",NULL); + cout << "open -s"<<endl; + input->open(argv[1]); + //loader->seek(1024*1024*364+1024*600); + //loader->seek(1024*1024*333); + + MpegVideoLength* mpegVideoLength=new MpegVideoLength(input); + + + cout << "START length calc"<<endl; + while (mpegVideoLength->firstInitialize()==false) { + if (input->eof()) { + break; + } + continue; + } + int len=mpegVideoLength->getLength(); + cout << "END length calc"<<endl; + + + MpegVideoStream* mpegVideoStream=new MpegVideoStream(input); + MpegVideoHeader* mpegVideoHeader=new MpegVideoHeader(); + cout << "start init"<<endl; + while (mpegVideoStream->firstInitialize(mpegVideoHeader)==false) { + + if (input->eof()) { + break; + } + } + + VideoDecoder* video; + mpegVideoHeader->print("start"); + cout << "**************"<<endl; + + PictureArray* pictureArray; + YUVPicture* pic; + + // now create pictureArray from the sequence + int width=mpegVideoHeader->getMB_Width()*16; + int height=mpegVideoHeader->getMB_Height()*16; + cout << "width:"<<width<<" height:"<<height<<endl; + + output->openWindow(width,height,(char*)"kmpg"); + + video= new VideoDecoder(mpegVideoStream,mpegVideoHeader); + + + // init is true + int cnt=0; + while (input->eof()==false){ + pictureArray=output->lockPictureArray(); + video->mpegVidRsrc(pictureArray); + pic=pictureArray->getYUVPictureCallback(); + if (pic == NULL) { + // nothin to display + continue; + } + + output->unlockPictureArray(pictureArray); + pictureArray->setYUVPictureCallback(NULL); + + } + cout << "DestroyVideoDecoder"<<endl; + delete video; + + + delete mpegVideoHeader; + delete mpegVideoStream; + cout << "end"<<endl; + +} + +#endif + + +/* + + threaded Plugin version + + ( not useful for gprof ) +*/ + +#ifdef _PLUGIN_VERSION + +int main(int argc, char** argv) { + + + + if (argc <= 1) { + printf("Usage:\n\n"); + printf("%s filename\n\n",argv[0]); + exit(0); + } + + // + // The order is important !!!! + // 1. construct + // 2. set Output + // 3. open input + // 4. set input + // + // you cannot set the input _before_ the output + // in fact you can, but this gives you a segfault! + + MpegPlugin* plugin=new MpegPlugin(); + OutputStream* out=OutPlugin::createOutputStream(_OUTPUT_LOCAL); + InputStream* in=InputPlugin::createInputStream(argv[1]); + + cout << "open -s 1"<<endl; + + // The plugin does not do "open" + in->open(argv[1]); + cout << "open -s 2"<<endl; + + // watch the order! + plugin->setOutputPlugin(out); + cout << "open -s 3"<<endl; + plugin->setInputPlugin(in); + cout << "open -s 4"<<endl; + + plugin->play(); + int cnt=0; + while(plugin->getStreamState() != _STREAM_STATE_EOF) { + sleep(1); + PluginInfo* pluginInfo=plugin->getPluginInfo(); + pluginInfo->print(); + } + cout << "plugin eof"<<endl; + plugin->close(); + + delete plugin; + delete in; + delete out; + +} + +#endif + diff --git a/mpeglib/lib/mpegplay/mmxidct.cpp b/mpeglib/lib/mpegplay/mmxidct.cpp new file mode 100644 index 00000000..f6e12409 --- /dev/null +++ b/mpeglib/lib/mpegplay/mmxidct.cpp @@ -0,0 +1,27 @@ +/* + wapper for other architectures than mmx + 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 "mmxidct.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + + +#ifndef INTEL + void IDCT_mmx(short int* reconptr) { + printf("urgs mmxidct!\n"); + exit(0); + } + +#endif diff --git a/mpeglib/lib/mpegplay/mmxidct.h b/mpeglib/lib/mpegplay/mmxidct.h new file mode 100644 index 00000000..9cdfe18c --- /dev/null +++ b/mpeglib/lib/mpegplay/mmxidct.h @@ -0,0 +1,22 @@ +/* + wapper for other architectures than mmx + 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 __MMXIDCT_H +#define __MMXIDCT_H + +#include <stdio.h> +#include <stdlib.h> + +extern "C" void IDCT_mmx(short int* reconptr); + +#endif diff --git a/mpeglib/lib/mpegplay/mmxidct_asm.S b/mpeglib/lib/mpegplay/mmxidct_asm.S new file mode 100644 index 00000000..b618c561 --- /dev/null +++ b/mpeglib/lib/mpegplay/mmxidct_asm.S @@ -0,0 +1,738 @@ + +#ifndef INTEL + +/** + Some compilers cannot compile empty files. +*/ + +IDCT_mmx_dummy: + .section .note.GNU-stack,"",%progbits +#endif + + +#ifdef INTEL + + +/* + * the input data is tranposed and each 16 bit element in the 8x8 matrix + * is left aligned: + * for example in 11...1110000 format + * If the iDCT is of I macroblock then 0.5 needs to be added to the; + * DC Component + * (element[0][0] of the matrix) + */ + +/* extrn re_matrix */ + +.data + .align 16 + .type preSC,@object +preSC: .short 16384,22725,21407,19266,16384,12873,8867,4520 + .short 22725,31521,29692,26722,22725,17855,12299,6270 + .short 21407,29692,27969,25172,21407,16819,11585,5906 + .short 19266,26722,25172,22654,19266,15137,10426,5315 + .short 16384,22725,21407,19266,16384,12873,8867,4520 + .short 12873,17855,16819,15137,25746,20228,13933,7103 + .short 17734,24598,23170,20853,17734,13933,9597,4892 + .short 18081,25080,23624,21261,18081,14206,9785,4988 + .size preSC,128 + .align 8 + .type x0005000200010001,@object + .size x0005000200010001,8 +x0005000200010001: + .long 0x00010001,0x00050002 + .align 8 + .type x0040000000000000,@object + .size x0040000000000000,8 +x0040000000000000: + .long 0, 0x00400000 + .align 8 + .type x5a825a825a825a82,@object + .size x5a825a825a825a82,8 +x5a825a825a825a82: + .long 0x5a825a82, 0x5a825a82 + .align 8 + .type x539f539f539f539f,@object + .size x539f539f539f539f,8 +x539f539f539f539f: + .long 0x539f539f,0x539f539f + .align 8 + .type x4546454645464546,@object + .size x4546454645464546,8 +x4546454645464546: + .long 0x45464546,0x45464546 + .align 8 + .type x61f861f861f861f8,@object + .size x61f861f861f861f8,8 +x61f861f861f861f8: + .long 0x61f861f8,0x61f861f8 + .align 8 + .type scratch1,@object + .size scratch1,8 +scratch1: + .long 0,0 + .align 8 + .type scratch3,@object + .size scratch3,8 +scratch3: + .long 0,0 + .align 8 + .type scratch5,@object + .size scratch5,8 +scratch5: + .long 0,0 + .align 8 + .type scratch7,@object + .size scratch7,8 +scratch7: + .long 0,0 + .type x0,@object + .size x0,8 +x0: + .long 0,0 + .align 8 +.text + .align 4 +.globl IDCT_mmx + .type IDCT_mmx,@function +IDCT_mmx: + pushl %ebp + movl %esp,%ebp + pushl %ebx + pushl %ecx + pushl %edx + pushl %esi + pushl %edi + movl 8(%ebp),%esi /* source matrix */ +#if 0 + movq (%esi), %mm0 + movq 8(%esi), %mm1 + psllw $4, %mm0 + movq 16(%esi), %mm2 + psllw $4, %mm1 + movq 24(%esi), %mm3 + psllw $4, %mm2 + movq 32(%esi), %mm4 + psllw $4, %mm3 + movq 40(%esi), %mm5 + psllw $4, %mm4 + movq 48(%esi), %mm6 + psllw $4, %mm5 + movq 56(%esi), %mm7 + psllw $4, %mm6 + psllw $4, %mm7 + movq %mm0, (%esi) + movq %mm1, 8(%esi) + movq %mm2,16(%esi) + movq %mm3,24(%esi) + movq %mm4,32(%esi) + movq %mm5,40(%esi) + movq %mm6,48(%esi) + movq %mm7,56(%esi) + movq 64(%esi), %mm0 + movq 72(%esi), %mm1 + psllw $4, %mm0 + movq 80(%esi), %mm2 + psllw $4, %mm1 + movq 88(%esi), %mm3 + psllw $4, %mm2 + movq 96(%esi), %mm4 + psllw $4, %mm3 + movq 104(%esi), %mm5 + psllw $4, %mm4 + movq 112(%esi), %mm6 + psllw $4, %mm5 + movq 120(%esi), %mm7 + psllw $4, %mm6 + psllw $4, %mm7 + movq %mm0,64(%esi) + movq %mm1,72(%esi) + movq %mm2,80(%esi) + movq %mm3,88(%esi) + movq %mm4,96(%esi) + movq %mm5,104(%esi) + movq %mm6,112(%esi) + movq %mm7,120(%esi) +#endif + leal preSC, %ecx +/* column 0: even part + * use V4, V12, V0, V8 to produce V22..V25 + */ + movq 8*12(%ecx), %mm0 /* maybe the first mul can be done together */ + /* with the dequantization in iHuff module */ + pmulhw 8*12(%esi), %mm0 /* V12 */ + movq 8*4(%ecx), %mm1 + pmulhw 8*4(%esi), %mm1 /* V4 */ + movq (%ecx), %mm3 + psraw $1, %mm0 /* t64=t66 */ + pmulhw (%esi), %mm3 /* V0 */ + movq 8*8(%ecx), %mm5 /* duplicate V4 */ + movq %mm1, %mm2 /* added 11/1/96 */ + pmulhw 8*8(%esi),%mm5 /* V8 */ + psubsw %mm0, %mm1 /* V16 */ + pmulhw x5a825a825a825a82, %mm1 /* 23170 ->V18 */ + paddsw %mm0, %mm2 /* V17 */ + movq %mm2, %mm0 /* duplicate V17 */ + psraw $1, %mm2 /* t75=t82 */ + psraw $2, %mm0 /* t72 */ + movq %mm3, %mm4 /* duplicate V0 */ + paddsw %mm5, %mm3 /* V19 */ + psubsw %mm5, %mm4 /* V20 ;mm5 free */ +/* moved from the block below */ + movq 8*10(%ecx), %mm7 + psraw $1, %mm3 /* t74=t81 */ + movq %mm3, %mm6 /* duplicate t74=t81 */ + psraw $2, %mm4 /* t77=t79 */ + psubsw %mm0, %mm1 /* V21 ; mm0 free */ + paddsw %mm2, %mm3 /* V22 */ + movq %mm1, %mm5 /* duplicate V21 */ + paddsw %mm4, %mm1 /* V23 */ + movq %mm3, 8*4(%esi) /* V22 */ + psubsw %mm5, %mm4 /* V24; mm5 free */ + movq %mm1, 8*12(%esi) /* V23 */ + psubsw %mm2, %mm6 /* V25; mm2 free */ + movq %mm4, (%esi) /* V24 */ +/* keep mm6 alive all along the next block */ + /* movq %mm6, 8*8(%esi) V25 */ +/* column 0: odd part + * use V2, V6, V10, V14 to produce V31, V39, V40, V41 + */ +/* moved above: movq 8*10(%ecx), %mm7 */ + + pmulhw 8*10(%esi), %mm7 /* V10 */ + movq 8*6(%ecx), %mm0 + pmulhw 8*6(%esi), %mm0 /* V6 */ + movq 8*2(%ecx), %mm5 + movq %mm7, %mm3 /* duplicate V10 */ + pmulhw 8*2(%esi), %mm5 /* V2 */ + movq 8*14(%ecx), %mm4 + psubsw %mm0, %mm7 /* V26 */ + pmulhw 8*14(%esi), %mm4 /* V14 */ + paddsw %mm0, %mm3 /* V29 ; free mm0 */ + movq %mm7, %mm1 /* duplicate V26 */ + psraw $1, %mm3 /* t91=t94 */ + pmulhw x539f539f539f539f,%mm7 /* V33 */ + psraw $1, %mm1 /* t96 */ + movq %mm5, %mm0 /* duplicate V2 */ + psraw $2, %mm4 /* t85=t87 */ + paddsw %mm4,%mm5 /* V27 */ + psubsw %mm4, %mm0 /* V28 ; free mm4 */ + movq %mm0, %mm2 /* duplicate V28 */ + psraw $1, %mm5 /* t90=t93 */ + pmulhw x4546454645464546,%mm0 /* V35 */ + psraw $1, %mm2 /* t97 */ + movq %mm5, %mm4 /* duplicate t90=t93 */ + psubsw %mm2, %mm1 /* V32 ; free mm2 */ + pmulhw x61f861f861f861f8,%mm1 /* V36 */ + psllw $1, %mm7 /* t107 */ + paddsw %mm3, %mm5 /* V31 */ + psubsw %mm3, %mm4 /* V30 ; free mm3 */ + pmulhw x5a825a825a825a82,%mm4 /* V34 */ + nop + psubsw %mm1, %mm0 /* V38 */ + psubsw %mm7, %mm1 /* V37 ; free mm7 */ + psllw $1, %mm1 /* t114 */ +/* move from the next block */ + movq %mm6, %mm3 /* duplicate V25 */ +/* move from the next block */ + movq 8*4(%esi), %mm7 /* V22 */ + psllw $1, %mm0 /* t110 */ + psubsw %mm5, %mm0 /* V39 (mm5 needed for next block) */ + psllw $2, %mm4 /* t112 */ +/* moved from the next block */ + movq 8*12(%esi), %mm2 /* V23 */ + psubsw %mm0, %mm4 /* V40 */ + paddsw %mm4, %mm1 /* V41; free mm0 */ +/* moved from the next block */ + psllw $1, %mm2 /* t117=t125 */ +/* column 0: output butterfly */ +/* moved above: + * movq %mm6, %mm3 duplicate V25 + * movq 8*4(%esi), %mm7 V22 + * movq 8*12(%esi), %mm2 V23 + * psllw $1, %mm2 t117=t125 + */ + psubsw %mm1, %mm6 /* tm6 */ + paddsw %mm1, %mm3 /* tm8; free mm1 */ + movq %mm7, %mm1 /* duplicate V22 */ + paddsw %mm5, %mm7 /* tm0 */ + movq %mm3, 8*8(%esi) /* tm8; free mm3 */ + psubsw %mm5, %mm1 /* tm14; free mm5 */ + movq %mm6, 8*6(%esi) /* tm6; free mm6 */ + movq %mm2, %mm3 /* duplicate t117=t125 */ + movq (%esi), %mm6 /* V24 */ + paddsw %mm0, %mm2 /* tm2 */ + movq %mm7, (%esi) /* tm0; free mm7 */ + psubsw %mm0, %mm3 /* tm12; free mm0 */ + movq %mm1, 8*14(%esi) /* tm14; free mm1 */ + psllw $1, %mm6 /* t119=t123 */ + movq %mm2, 8*2(%esi) /* tm2; free mm2 */ + movq %mm6, %mm0 /* duplicate t119=t123 */ + movq %mm3, 8*12(%esi) /* tm12; free mm3 */ + paddsw %mm4, %mm6 /* tm4 */ +/* moved from next block */ + movq 8*5(%ecx), %mm1 + psubsw %mm4, %mm0 /* tm10; free mm4 */ +/* moved from next block */ + pmulhw 8*5(%esi), %mm1 /* V5 */ + movq %mm6, 8*4(%esi) /* tm4; free mm6 */ + movq %mm0, 8*10(%esi) /* tm10; free mm0 */ +/* column 1: even part + * use V5, V13, V1, V9 to produce V56..V59 + */ +/* moved to prev block: + * movq 8*5(%ecx), %mm1 + * pmulhw 8*5(%esi), %mm1 V5 + */ + movq 8*13(%ecx), %mm7 + psllw $1, %mm1 /* t128=t130 */ + pmulhw 8*13(%esi), %mm7 /* V13 */ + movq %mm1, %mm2 /* duplicate t128=t130 */ + movq 8(%ecx), %mm3 + pmulhw 8(%esi), %mm3 /* V1 */ + movq 8*9(%ecx), %mm5 + psubsw %mm7, %mm1 /* V50 */ + pmulhw 8*9(%esi), %mm5 /* V9 */ + paddsw %mm7, %mm2 /* V51 */ + pmulhw x5a825a825a825a82, %mm1 /* 23170 ->V52 */ + movq %mm2, %mm6 /* duplicate V51 */ + psraw $1, %mm2 /* t138=t144 */ + movq %mm3, %mm4 /* duplicate V1 */ + psraw $2, %mm6 /* t136 */ + paddsw %mm5, %mm3 /* V53 */ + psubsw %mm5, %mm4 /* V54 ;mm5 free */ + movq %mm3, %mm7 /* duplicate V53 */ +/* moved from next block */ + movq 8*11(%ecx), %mm0 + psraw $1, %mm4 /* t140=t142 */ + psubsw %mm6, %mm1 /* V55 ; mm6 free */ + paddsw %mm2, %mm3 /* V56 */ + movq %mm4, %mm5 /* duplicate t140=t142 */ + paddsw %mm1, %mm4 /* V57 */ + movq %mm3, 8*5(%esi) /* V56 */ + psubsw %mm1, %mm5 /* V58; mm1 free */ + movq %mm4, 8*13(%esi) /* V57 */ + psubsw %mm2, %mm7 /* V59; mm2 free */ + movq %mm5, 8*9(%esi) /* V58 */ +/* keep mm7 alive all along the next block + * movq %mm7, 8(%esi) V59 + * moved above + * movq 8*11(%ecx), %mm0 + */ + pmulhw 8*11(%esi), %mm0 /* V11 */ + movq 8*7(%ecx), %mm6 + pmulhw 8*7(%esi), %mm6 /* V7 */ + movq 8*15(%ecx), %mm4 + movq %mm0, %mm3 /* duplicate V11 */ + pmulhw 8*15(%esi), %mm4 /* V15 */ + movq 8*3(%ecx), %mm5 + psllw $1, %mm6 /* t146=t152 */ + pmulhw 8*3(%esi), %mm5 /* V3 */ + paddsw %mm6, %mm0 /* V63 */ +/* note that V15 computation has a correction step: + * this is a 'magic' constant that rebiases the results to be closer to the + * expected result. this magic constant can be refined to reduce the error + * even more by doing the correction step in a later stage when the number + * is actually multiplied by 16 + */ + paddw x0005000200010001, %mm4 + psubsw %mm6, %mm3 /* V60 ; free mm6 */ + psraw $1, %mm0 /* t154=t156 */ + movq %mm3, %mm1 /* duplicate V60 */ + pmulhw x539f539f539f539f, %mm1 /* V67 */ + movq %mm5, %mm6 /* duplicate V3 */ + psraw $2, %mm4 /* t148=t150 */ + paddsw %mm4, %mm5 /* V61 */ + psubsw %mm4, %mm6 /* V62 ; free mm4 */ + movq %mm5, %mm4 /* duplicate V61 */ + psllw $1, %mm1 /* t169 */ + paddsw %mm0, %mm5 /* V65 -> result */ + psubsw %mm0, %mm4 /* V64 ; free mm0 */ + pmulhw x5a825a825a825a82, %mm4 /* V68 */ + psraw $1, %mm3 /* t158 */ + psubsw %mm6, %mm3 /* V66 */ + movq %mm5, %mm2 /* duplicate V65 */ + pmulhw x61f861f861f861f8, %mm3 /* V70 */ + psllw $1, %mm6 /* t165 */ + pmulhw x4546454645464546, %mm6 /* V69 */ + psraw $1, %mm2 /* t172 */ +/* moved from next block */ + movq 8*5(%esi), %mm0 /* V56 */ + psllw $1, %mm4 /* t174 */ +/* moved from next block */ + psraw $1, %mm0 /* t177=t188 */ + nop + psubsw %mm3, %mm6 /* V72 */ + psubsw %mm1, %mm3 /* V71 ; free mm1 */ + psubsw %mm2, %mm6 /* V73 ; free mm2 */ +/* moved from next block */ + psraw $1, %mm5 /* t178=t189 */ + psubsw %mm6, %mm4 /* V74 */ +/* moved from next block */ + movq %mm0, %mm1 /* duplicate t177=t188 */ + paddsw %mm4, %mm3 /* V75 */ +/* moved from next block */ + paddsw %mm5, %mm0 /* tm1 */ +/* location + * 5 - V56 + * 13 - V57 + * 9 - V58 + * X - V59, mm7 + * X - V65, mm5 + * X - V73, mm6 + * X - V74, mm4 + * X - V75, mm3 + * free mm0, mm1 & mm2 + * moved above + * movq 8*5(%esi), %mm0 V56 + * psllw $1, %mm0 t177=t188 ! new !! + * psllw $1, %mm5 t178=t189 ! new !! + * movq %mm0, %mm1 duplicate t177=t188 + * paddsw %mm5, %mm0 tm1 + */ + movq 8*13(%esi), %mm2 /* V57 */ + psubsw %mm5, %mm1 /* tm15; free mm5 */ + movq %mm0, 8(%esi) /* tm1; free mm0 */ + psraw $1, %mm7 /* t182=t184 ! new !! */ +/* save the store as used directly in the transpose + * movq %mm1, 120(%esi) tm15; free mm1 + */ + movq %mm7, %mm5 /* duplicate t182=t184 */ + psubsw %mm3, %mm7 /* tm7 */ + paddsw %mm3, %mm5 /* tm9; free mm3 */ + movq 8*9(%esi), %mm0 /* V58 */ + movq %mm2, %mm3 /* duplicate V57 */ + movq %mm7, 8*7(%esi) /* tm7; free mm7 */ + psubsw %mm6, %mm3 /* tm13 */ + paddsw %mm6, %mm2 /* tm3 ; free mm6 */ +/* moved up from the transpose */ + movq %mm3, %mm7 +/* moved up from the transpose */ + punpcklwd %mm1, %mm3 + movq %mm0, %mm6 /* duplicate V58 */ + movq %mm2, 8*3(%esi) /* tm3; free mm2 */ + paddsw %mm4, %mm0 /* tm5 */ + psubsw %mm4, %mm6 /* tm11; free mm4 */ +/* moved up from the transpose */ + punpckhwd %mm1, %mm7 + movq %mm0, 8*5(%esi) /* tm5; free mm0 */ +/* moved up from the transpose */ + movq %mm5, %mm2 +/* transpose - M4 part + * --------- --------- + * | M1 | M2 | | M1'| M3'| + * --------- --> --------- + * | M3 | M4 | | M2'| M4'| + * --------- --------- + * Two alternatives: use full mmword approach so the following code can be + * scheduled before the transpose is done without stores, or use the faster + * half mmword stores (when possible) + */ + movd %mm3, 8*9+4(%esi) /* MS part of tmt9 */ + punpcklwd %mm6, %mm5 + movd %mm7, 8*13+4(%esi) /* MS part of tmt13 */ + punpckhwd %mm6, %mm2 + movd %mm5, 8*9(%esi) /* LS part of tmt9 */ + punpckhdq %mm3, %mm5 /* free mm3 */ + movd %mm2, 8*13(%esi) /* LS part of tmt13 */ + punpckhdq %mm7, %mm2 /* free mm7 */ +/* moved up from the M3 transpose */ + movq 8*8(%esi), %mm0 +/* moved up from the M3 transpose */ + movq 8*10(%esi), %mm1 +/* moved up from the M3 transpose */ + movq %mm0, %mm3 +/* shuffle the rest of the data, and write it with 2 mmword writes */ + movq %mm5, 8*11(%esi) /* tmt11 */ +/* moved up from the M3 transpose */ + punpcklwd %mm1, %mm0 + movq %mm2, 8*15(%esi) /* tmt15 */ +/* moved up from the M3 transpose */ + punpckhwd %mm1, %mm3 +/* transpose - M3 part + * moved up to previous code section + * movq 8*8(%esi), %mm0 + * movq 8*10(%esi), %mm1 + * movq %mm0, %mm3 + * punpcklwd %mm1, %mm0 + * punpckhwd %mm1, %mm3 + */ + movq 8*12(%esi), %mm6 + movq 8*14(%esi), %mm4 + movq %mm6, %mm2 +/* shuffle the data and write the lower parts of the transposed in 4 dwords */ + punpcklwd %mm4, %mm6 + movq %mm0, %mm1 + punpckhdq %mm6, %mm1 + movq %mm3, %mm7 + punpckhwd %mm4, %mm2 /* free mm4 */ + punpckldq %mm6, %mm0 /* free mm6 */ +/* moved from next block */ + movq 8*13(%esi), %mm4 /* tmt13 */ + punpckldq %mm2, %mm3 + punpckhdq %mm2, %mm7 /* free mm2 */ +/* moved from next block */ + movq %mm3, %mm5 /* duplicate tmt5 */ +/* column 1: even part (after transpose) +* moved above +* movq %mm3, %mm5 duplicate tmt5 +* movq 8*13(%esi), %mm4 tmt13 +*/ + psubsw %mm4, %mm3 /* V134 */ + pmulhw x5a825a825a825a82, %mm3 /* 23170 ->V136 */ + movq 8*9(%esi), %mm6 /* tmt9 */ + paddsw %mm4, %mm5 /* V135 ; mm4 free */ + movq %mm0, %mm4 /* duplicate tmt1 */ + paddsw %mm6, %mm0 /* V137 */ + psubsw %mm6, %mm4 /* V138 ; mm6 free */ + psllw $2, %mm3 /* t290 */ + psubsw %mm5, %mm3 /* V139 */ + movq %mm0, %mm6 /* duplicate V137 */ + paddsw %mm5, %mm0 /* V140 */ + movq %mm4, %mm2 /* duplicate V138 */ + paddsw %mm3, %mm2 /* V141 */ + psubsw %mm3, %mm4 /* V142 ; mm3 free */ + movq %mm0, 8*9(%esi) /* V140 */ + psubsw %mm5, %mm6 /* V143 ; mm5 free */ +/* moved from next block */ + movq 8*11(%esi), %mm0 /* tmt11 */ + movq %mm2, 8*13(%esi) /* V141 */ +/* moved from next block */ + movq %mm0, %mm2 /* duplicate tmt11 */ +/* column 1: odd part (after transpose) */ +/* moved up to the prev block + * movq 8*11(%esi), %mm0 tmt11 + * movq %mm0, %mm2 duplicate tmt11 + */ + movq 8*15(%esi), %mm5 /* tmt15 */ + psubsw %mm7, %mm0 /* V144 */ + movq %mm0, %mm3 /* duplicate V144 */ + paddsw %mm7, %mm2 /* V147 ; free mm7 */ + pmulhw x539f539f539f539f, %mm0 /* 21407-> V151 */ + movq %mm1, %mm7 /* duplicate tmt3 */ + paddsw %mm5, %mm7 /* V145 */ + psubsw %mm5, %mm1 /* V146 ; free mm5 */ + psubsw %mm1, %mm3 /* V150 */ + movq %mm7, %mm5 /* duplicate V145 */ + pmulhw x4546454645464546, %mm1 /* 17734-> V153 */ + psubsw %mm2, %mm5 /* V148 */ + pmulhw x61f861f861f861f8, %mm3 /* 25080-> V154 */ + psllw $2, %mm0 /* t311 */ + pmulhw x5a825a825a825a82, %mm5 /* 23170-> V152 */ + paddsw %mm2, %mm7 /* V149 ; free mm2 */ + psllw $1, %mm1 /* t313 */ + nop /* without the nop - freeze here for one clock */ + movq %mm3, %mm2 /* duplicate V154 */ + psubsw %mm0, %mm3 /* V155 ; free mm0 */ + psubsw %mm2, %mm1 /* V156 ; free mm2 */ +/* moved from the next block */ + movq %mm6, %mm2 /* duplicate V143 */ +/* moved from the next block */ + movq 8*13(%esi), %mm0 /* V141 */ + psllw $1, %mm1 /* t315 */ + psubsw %mm7, %mm1 /* V157 (keep V149) */ + psllw $2, %mm5 /* t317 */ + psubsw %mm1, %mm5 /* V158 */ + psllw $1, %mm3 /* t319 */ + paddsw %mm5, %mm3 /* V159 */ +/* column 1: output butterfly (after transform) + * moved to the prev block + * movq %mm6, %mm2 duplicate V143 + * movq 8*13(%esi), %mm0 V141 + */ + psubsw %mm3, %mm2 /* V163 */ + paddsw %mm3, %mm6 /* V164 ; free mm3 */ + movq %mm4, %mm3 /* duplicate V142 */ + psubsw %mm5, %mm4 /* V165 ; free mm5 */ + movq %mm2, scratch7 /* out7 */ + psraw $4, %mm6 + psraw $4, %mm4 + paddsw %mm5, %mm3 /* V162 */ + movq 8*9(%esi), %mm2 /* V140 */ + movq %mm0, %mm5 /* duplicate V141 */ +/* in order not to perculate this line up, + * we read 72(%esi) very near to this location + */ + movq %mm6, 8*9(%esi) /* out9 */ + paddsw %mm1, %mm0 /* V161 */ + movq %mm3, scratch5 /* out5 */ + psubsw %mm1, %mm5 /* V166 ; free mm1 */ + movq %mm4, 8*11(%esi) /* out11 */ + psraw $4, %mm5 + movq %mm0, scratch3 /* out3 */ + movq %mm2, %mm4 /* duplicate V140 */ + movq %mm5, 8*13(%esi) /* out13 */ + paddsw %mm7, %mm2 /* V160 */ +/* moved from the next block */ + movq 8(%esi), %mm0 + psubsw %mm7, %mm4 /* V167 ; free mm7 */ +/* moved from the next block */ + movq 8*3(%esi), %mm7 + psraw $4, %mm4 + movq %mm2, scratch1 /* out1 */ +/* moved from the next block */ + movq %mm0, %mm1 + movq %mm4, 8*15(%esi) /* out15 */ +/* moved from the next block */ + punpcklwd %mm7, %mm0 +/* transpose - M2 parts + * moved up to the prev block + * movq 8(%esi), %mm0 + * movq 8*3(%esi), %mm7 + * movq %mm0, %mm1 + * punpcklwd %mm7, %mm0 + */ + movq 8*5(%esi), %mm5 + punpckhwd %mm7, %mm1 + movq 8*7(%esi), %mm4 + movq %mm5, %mm3 +/* shuffle the data and write the lower parts of the trasposed in 4 dwords */ + movd %mm0, 8*8(%esi) /* LS part of tmt8 */ + punpcklwd %mm4, %mm5 + movd %mm1, 8*12(%esi) /* LS part of tmt12 */ + punpckhwd %mm4, %mm3 + movd %mm5, 8*8+4(%esi) /* MS part of tmt8 */ + punpckhdq %mm5, %mm0 /* tmt10 */ + movd %mm3, 8*12+4(%esi) /* MS part of tmt12 */ + punpckhdq %mm3, %mm1 /* tmt14 */ +/* transpose - M1 parts */ + movq (%esi), %mm7 + movq 8*2(%esi), %mm2 + movq %mm7, %mm6 + movq 8*4(%esi), %mm5 + punpcklwd %mm2, %mm7 + movq 8*6(%esi), %mm4 + punpckhwd %mm2, %mm6 /* free mm2 */ + movq %mm5, %mm3 + punpcklwd %mm4, %mm5 + punpckhwd %mm4, %mm3 /* free mm4 */ + movq %mm7, %mm2 + movq %mm6, %mm4 + punpckldq %mm5, %mm7 /* tmt0 */ + punpckhdq %mm5, %mm2 /* tmt2 ; free mm5 */ +/* shuffle the rest of the data, and write it with 2 mmword writes */ + punpckldq %mm3, %mm6 /* tmt4 */ +/* moved from next block */ + movq %mm2, %mm5 /* duplicate tmt2 */ + punpckhdq %mm3, %mm4 /* tmt6 ; free mm3 */ +/* moved from next block */ + movq %mm0, %mm3 /* duplicate tmt10 */ +/* column 0: odd part (after transpose) + *moved up to prev block + * movq %mm0, %mm3 duplicate tmt10 + * movq %mm2, %mm5 duplicate tmt2 + */ + psubsw %mm4, %mm0 /* V110 */ + paddsw %mm4, %mm3 /* V113 ; free mm4 */ + movq %mm0, %mm4 /* duplicate V110 */ + paddsw %mm1, %mm2 /* V111 */ + pmulhw x539f539f539f539f, %mm0 /* 21407-> V117 */ + psubsw %mm1, %mm5 /* V112 ; free mm1 */ + psubsw %mm5, %mm4 /* V116 */ + movq %mm2, %mm1 /* duplicate V111 */ + pmulhw x4546454645464546, %mm5 /* 17734-> V119 */ + psubsw %mm3, %mm2 /* V114 */ + pmulhw x61f861f861f861f8, %mm4 /* 25080-> V120 */ + paddsw %mm3, %mm1 /* V115 ; free mm3 */ + pmulhw x5a825a825a825a82, %mm2 /* 23170-> V118 */ + psllw $2, %mm0 /* t266 */ + movq %mm1, (%esi) /* save V115 */ + psllw $1, %mm5 /* t268 */ + psubsw %mm4, %mm5 /* V122 */ + psubsw %mm0, %mm4 /* V121 ; free mm0 */ + psllw $1, %mm5 /* t270 */ + psubsw %mm1, %mm5 /* V123 ; free mm1 */ + psllw $2, %mm2 /* t272 */ + psubsw %mm5, %mm2 /* V124 (keep V123) */ + psllw $1, %mm4 /* t274 */ + movq %mm5, 8*2(%esi) /* save V123 ; free mm5 */ + paddsw %mm2, %mm4 /* V125 (keep V124) */ +/* column 0: even part (after transpose) */ + movq 8*12(%esi), %mm0 /* tmt12 */ + movq %mm6, %mm3 /* duplicate tmt4 */ + psubsw %mm0, %mm6 /* V100 */ + paddsw %mm0, %mm3 /* V101 ; free mm0 */ + pmulhw x5a825a825a825a82, %mm6 /* 23170 ->V102 */ + movq %mm7, %mm5 /* duplicate tmt0 */ + movq 8*8(%esi), %mm1 /* tmt8 */ + paddsw %mm1, %mm7 /* V103 */ + psubsw %mm1, %mm5 /* V104 ; free mm1 */ + movq %mm7, %mm0 /* duplicate V103 */ + psllw $2, %mm6 /* t245 */ + paddsw %mm3, %mm7 /* V106 */ + movq %mm5, %mm1 /* duplicate V104 */ + psubsw %mm3, %mm6 /* V105 */ + psubsw %mm3, %mm0 /* V109; free mm3 */ + paddsw %mm6, %mm5 /* V107 */ + psubsw %mm6, %mm1 /* V108 ; free mm6 */ +/* column 0: output butterfly (after transform) */ + movq %mm1, %mm3 /* duplicate V108 */ + paddsw %mm2, %mm1 /* out4 */ + psraw $4, %mm1 + psubsw %mm2, %mm3 /* out10 ; free mm2 */ + psraw $4, %mm3 + movq %mm0, %mm6 /* duplicate V109 */ + movq %mm1, 8*4(%esi) /* out4 ; free mm1 */ + psubsw %mm4, %mm0 /* out6 */ + movq %mm3, 8*10(%esi) /* out10 ; free mm3 */ + psraw $4, %mm0 + paddsw %mm4, %mm6 /* out8 ; free mm4 */ + movq %mm7, %mm1 /* duplicate V106 */ + movq %mm0, 8*6(%esi) /* out6 ; free mm0 */ + psraw $4, %mm6 + movq (%esi), %mm4 /* V115 */ + movq %mm6, 8*8(%esi) /* out8 ; free mm6 */ + movq %mm5, %mm2 /* duplicate V107 */ + movq 8*2(%esi), %mm3 /* V123 */ + paddsw %mm4, %mm7 /* out0 */ +/* moved up from next block */ + movq scratch3, %mm0 + psraw $4, %mm7 +/* moved up from next block */ + movq scratch5, %mm6 + psubsw %mm4, %mm1 /* out14 ; free mm4 */ + paddsw %mm3, %mm5 /* out2 */ + psraw $4, %mm1 + movq %mm7, (%esi) /* out0 ; free mm7 */ + psraw $4, %mm5 + movq %mm1, 8*14(%esi) /* out14 ; free mm1 */ + psubsw %mm3, %mm2 /* out12 ; free mm3 */ + movq %mm5, 8*2(%esi) /* out2 ; free mm5 */ + psraw $4, %mm2 +/* moved up to the prev block */ + movq scratch7, %mm4 +/* moved up to the prev block */ + psraw $4, %mm0 + movq %mm2, 8*12(%esi) /* out12 ; free mm2 */ +/* moved up to the prev block */ + psraw $4, %mm6 +/* move back the data to its correct place +* moved up to the prev block + * movq scratch3, %mm0 + * movq scratch5, %mm6 + * movq scratch7, %mm4 + * psraw $4, %mm0 + * psraw $4, %mm6 +*/ + movq scratch1, %mm1 + psraw $4, %mm4 + movq %mm0, 8*3(%esi) /* out3 */ + psraw $4, %mm1 + movq %mm6, 8*5(%esi) /* out5 */ + movq %mm4, 8*7(%esi) /* out7 */ + movq %mm1, 8(%esi) /* out1 */ + popl %edi + popl %esi + popl %edx + popl %ecx + popl %ebx + movl %ebp,%esp + popl %ebp + ret +.Lfe1: + .size IDCT_mmx,.Lfe1-IDCT_mmx + .section .note.GNU-stack,"",%progbits + + +#endif + diff --git a/mpeglib/lib/mpegplay/motionVector.cpp b/mpeglib/lib/mpegplay/motionVector.cpp new file mode 100644 index 00000000..ebec0369 --- /dev/null +++ b/mpeglib/lib/mpegplay/motionVector.cpp @@ -0,0 +1,130 @@ +/* + class for motionvectors + 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 "motionVector.h" + + + + + +MotionVector::MotionVector() { +} + + +MotionVector::~MotionVector() { +} + + + +/* + *-------------------------------------------------------------- + * + * ComputeVector -- + * + * Computes motion vector given parameters previously parsed + * and reconstructed. + * + * Results: + * Reconstructed motion vector info is put into recon_* parameters + * passed to this function. Also updated previous motion vector + * information. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ +void MotionVector::computeVector(int* recon_right_ptr, + int* recon_down_ptr, + int& recon_right_prev, + int& recon_down_prev, + unsigned int& f, + unsigned int& full_pel_vector, + int& motion_h_code, + int& motion_v_code, + unsigned int& motion_h_r, + unsigned int& motion_v_r) { + + + int comp_h_r, comp_v_r; + int right_little, right_big, down_little, down_big; + int max, min, new_vector; + + /* The following procedure for the reconstruction of motion vectors + is a direct and simple implementation of the instructions given + in the mpeg December 1991 standard draft. + */ + + if (f == 1 || motion_h_code == 0) + comp_h_r = 0; + else + comp_h_r = f - 1 - motion_h_r; + + if (f == 1 || motion_v_code == 0) + comp_v_r = 0; + else + comp_v_r = f - 1 - motion_v_r; + + right_little = motion_h_code * f; + if (right_little == 0) + right_big = 0; + else { + if (right_little > 0) { + right_little = right_little - comp_h_r; + right_big = right_little - 32 * f; + } + else { + right_little = right_little + comp_h_r; + right_big = right_little + 32 * f; + } + } + + down_little = motion_v_code * f; + if (down_little == 0) + down_big = 0; + else { + if (down_little > 0) { + down_little = down_little - comp_v_r; + down_big = down_little - 32 * f; + } + else { + down_little = down_little + comp_v_r; + down_big = down_little + 32 * f; + } + } + + max = 16 * f - 1; + min = -16 * f; + + new_vector = recon_right_prev + right_little; + + if (new_vector <= max && new_vector >= min) + *recon_right_ptr = recon_right_prev + right_little; + /* just new_vector */ + else + *recon_right_ptr = recon_right_prev + right_big; + recon_right_prev = *recon_right_ptr; + if (full_pel_vector) + *recon_right_ptr = *recon_right_ptr << 1; + + new_vector = recon_down_prev + down_little; + if (new_vector <= max && new_vector >= min) + *recon_down_ptr = recon_down_prev + down_little; + /* just new_vector */ + else + *recon_down_ptr = recon_down_prev + down_big; + recon_down_prev = *recon_down_ptr; + if (full_pel_vector) + *recon_down_ptr = *recon_down_ptr << 1; + +} diff --git a/mpeglib/lib/mpegplay/motionVector.h b/mpeglib/lib/mpegplay/motionVector.h new file mode 100644 index 00000000..5a58e027 --- /dev/null +++ b/mpeglib/lib/mpegplay/motionVector.h @@ -0,0 +1,40 @@ +/* + class for motionvectors + 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 __MOTIONVECTOR_H +#define __MOTIONVECTOR_H + + +#include "picture.h" + + +class MotionVector { + + + public: + MotionVector(); + ~MotionVector(); + + void computeVector(int* recon_right_ptr, + int* recon_down_ptr, + int& recon_right_prev, + int& recon_down_prev, + unsigned int& f, + unsigned int& full_pel_vector, + int& motion_h_code, + int& motion_v_code, + unsigned int& motion_h_r, + unsigned int& motion_v_r); + +}; +#endif diff --git a/mpeglib/lib/mpegplay/mpegExtension.cpp b/mpeglib/lib/mpegplay/mpegExtension.cpp new file mode 100644 index 00000000..657fe683 --- /dev/null +++ b/mpeglib/lib/mpegplay/mpegExtension.cpp @@ -0,0 +1,258 @@ +/* + parses extension data (picture and sequence) + 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 "mpegExtension.h" + +#include <iostream> + +using namespace std; + +MpegExtension::MpegExtension() { + userData=NULL; + extData=NULL; + extraBit=NULL; +} + + +MpegExtension::~MpegExtension() { + if (userData != NULL) { + delete userData; + } + if (extData != NULL) { + delete extData; + } + if (extraBit != NULL) { + delete extraBit; + } +} + + +int MpegExtension::processExtensionData(MpegVideoStream* mpegVideoStream) { + + /* Goto next start code. */ + mpegVideoStream->next_start_code(); + + /* + * If next start code is extension/user start code, + * parse off extension data. + */ + + /* + * If next start code is extension start code, parse off extension data. + */ + if (next_bits(32, EXT_START_CODE,mpegVideoStream)) { + mpegVideoStream->flushBits(32); + if (extData != NULL) { + delete extData; + extData = NULL; + } + cout << "ext"<<endl; + extData = get_ext_data(mpegVideoStream); + } + + /* + * If next start code is user start code, parse off user data. + */ + if (next_bits(32, USER_START_CODE,mpegVideoStream)) { + mpegVideoStream->flushBits(32); + if (userData != NULL) { + delete userData; + userData=NULL; + } + userData =get_ext_data(mpegVideoStream); + } + + return true; +} + + + +int MpegExtension::processExtra_bit_info(MpegVideoStream* mpegVideoStream) { + if (extraBit != NULL) { + delete extraBit; + extraBit = NULL; + } + get_extra_bit_info(mpegVideoStream); + return true; +} + + + + +int MpegExtension::next_bits(int num,unsigned int mask, + MpegVideoStream* input) { + unsigned int data; + + /* Get next num bits, no buffer pointer advance. */ + + data=input->showBits(num); + + /* Compare bit stream and mask. Set return value toTRUE if equal, FALSE if + differs. + */ + + if (mask == data) { + return true; + } + return false; +} + +/* + *-------------------------------------------------------------- + * + * get_ext_data -- + * + * Assumes that bit stream is at begining of extension + * data. Parses off extension data into dynamically + * allocated space until start code is hit. + * + * Results: + * Pointer to dynamically allocated memory containing + * extension data. + * + * Side effects: + * Bit stream irreversibly parsed. + * + *-------------------------------------------------------------- + */ +char* MpegExtension::get_ext_data(MpegVideoStream* mpegVideoStream) { + unsigned int size, marker; + char *dataPtr; + unsigned int data; + + /* Set initial ext data buffer size. */ + + size = EXT_BUF_SIZE; + + /* Allocate ext data buffer. */ + + dataPtr = (char *) malloc(size); + + /* Initialize marker to keep place in ext data buffer. */ + + marker = 0; + + /* While next data is not start code... */ + while (!next_bits(24, 0x000001,mpegVideoStream )) { + + /* Get next byte of ext data. */ + + data=mpegVideoStream->getBits(8); + + + + /* Put ext data into ext data buffer. Advance marker. */ + + dataPtr[marker] = (char) data; + marker++; + + /* If end of ext data buffer reached, resize data buffer. */ + + if (marker == size) { + size += EXT_BUF_SIZE; + dataPtr = (char *) realloc(dataPtr, size); + } + } + + /* Realloc data buffer to free any extra space. */ + + dataPtr = (char *) realloc(dataPtr, marker); + delete dataPtr; + dataPtr=NULL; + /* Return pointer to ext data buffer. */ + return dataPtr; +} + +void MpegExtension::processExtBuffer(MpegVideoStream* mpegVideoStream){ + unsigned int size, marker; + char *dataPtr; + unsigned int data=1; + + /* Initialize size of extra bit info buffer and allocate. */ + + + size = EXT_BUF_SIZE; + dataPtr = (char *) malloc(size); + + /* Reset marker to hold place in buffer. */ + + marker = 0; + + /* While flag bit is true. */ + + while (data) { + + /* Get next 8 bits of data. */ + data=mpegVideoStream->getBits(8); + + /* Place in extra bit info buffer. */ + + dataPtr[marker] = (char) data; + marker++; + + /* If buffer is full, reallocate. */ + + if (marker == size) { + size += EXT_BUF_SIZE; + dataPtr = (char *) realloc(dataPtr, size); + } + + /* Get next flag bit. */ + data=mpegVideoStream->getBits(1); + } + + /* Reallocate buffer to free extra space. */ + + dataPtr = (char *) realloc(dataPtr, marker); + delete dataPtr; + dataPtr=NULL; + /* Return pointer to extra bit info buffer. */ +} + + +/* + *-------------------------------------------------------------- + * + * get_extra_bit_info -- + * + * Parses off extra bit info stream into dynamically + * allocated memory. Extra bit info is indicated by + * a flag bit set to 1, followed by 8 bits of data. + * This continues until the flag bit is zero. Assumes + * that bit stream set to first flag bit in extra + * bit info stream. + * + * Results: + * Pointer to dynamically allocated memory with extra + * bit info in it. Flag bits are NOT included. + * + * Side effects: + * Bit stream irreversibly parsed. + * + *-------------------------------------------------------------- + */ + +char* MpegExtension::get_extra_bit_info(MpegVideoStream* mpegVideoStream) { + unsigned int data; + + /* Get first flag bit. */ + data=mpegVideoStream->getBits(1); + + /* If flag is false, return NULL pointer (i.e. no extra bit info). */ + + if (!data) { + return NULL; + } + processExtBuffer(mpegVideoStream); + return NULL; +} diff --git a/mpeglib/lib/mpegplay/mpegExtension.h b/mpeglib/lib/mpegplay/mpegExtension.h new file mode 100644 index 00000000..23b79c5b --- /dev/null +++ b/mpeglib/lib/mpegplay/mpegExtension.h @@ -0,0 +1,49 @@ +/* + parses extension data (picture and sequence) + 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 __MPEGEXTENSION_H +#define __MPEGEXTENSION_H + +#include "mpegVideoStream.h" + +#define EXT_BUF_SIZE 1024 + +class MpegExtension { + + char* userData; + char* extData; + char* extraBit; + + public: + MpegExtension(); + ~MpegExtension(); + + inline char* getExtData() { return extData;} + inline char* getUserData() { return userData;} + inline char* getExtraBit() { return extraBit;} + + int processExtensionData(class MpegVideoStream* mpegVideoStream); + int processExtra_bit_info(class MpegVideoStream* mpegVideoStream); + void processExtBuffer(class MpegVideoStream* mpegVideoStream); + char* get_ext_data(class MpegVideoStream* mpegVideoStream); + + private: + char* get_extra_bit_info(MpegVideoStream* mpegVideoStream); + + int next_bits(int num,unsigned int mask,MpegVideoStream* input); + +}; +#endif diff --git a/mpeglib/lib/mpegplay/mpegSystemHeader.cpp b/mpeglib/lib/mpegplay/mpegSystemHeader.cpp new file mode 100644 index 00000000..e8fe1d91 --- /dev/null +++ b/mpeglib/lib/mpegplay/mpegSystemHeader.cpp @@ -0,0 +1,786 @@ +/* + stores info about system stream and sends data to audio/video + 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 "mpegSystemHeader.h" + +#include <iostream> + +using namespace std; + +// we do a fast mod based lookup pid->Map +#define MAX_PIDS 23 + + +MpegSystemHeader::MpegSystemHeader() { + + packetLen=0; + pesPacketLen=0; + tsPacketLen=0; + + + audioLayerSelect=0; + videoLayerSelect=0; + lmpeg2=false; + lPTSFlag=false; + + layer=_PACKET_UNKNOWN_LAYER; + lHasPSHeader=false; + + // + // MPEG2 Stuff [START] + // + + lOriginal=false; + lCopyRight=false; + lDataAlignmentIndicator=false; + lPesPriority=false; + lEncrypted=false; + startCodePrefix=0; + + lPTSDTSFlag=false; + lESCR=false; + lESRateFlag=false; + lDMSTRICKFLAG=false; + lADDITIONAL_COPY_FLAG=false; + lPES_CRC_FLAG=false; + lPES_EXT_FLAG=false; + nPES_HEADER_DATA_LENGTH=0; + + // EXT FILED [START] + + lPrivateDataFlag=false; + lPackHeaderFieldFlag=false; + lSequenceCounterFlag=false; + lSTDBufferFlag=false; + lPES_EXT_FLAG_2=false; + nPES_EXT_FIELD_LENGTH=0; + // EXT FILED [END] + + subStreamID=0; + // + // MPEG2 Stuff [END] + // + + // TS Stuff [START] + lHasTSHeader=false; + programs=0; + programNumber=INVALID_PROGRAM; + pmtPID=INVALID_PID; + + mapPidStreamArray=new MapPidStream*[MAX_PIDS]; + int i; + for(i=0;i<MAX_PIDS;i++) { + mapPidStreamArray[i]=new MapPidStream(); + mapPidStreamArray[i]->isValid=false; + } + currentPos=0; + + + + // TS Stuff [END] +} + + +MpegSystemHeader::~MpegSystemHeader() { + int i; + for(i=0;i<MAX_PIDS;i++) { + delete mapPidStreamArray[i]; + } + delete mapPidStreamArray; +} + + +void MpegSystemHeader::setHeader(unsigned int header) { + setPSHeader(header); + setTSHeader(header); + this->header=header; +} + +int MpegSystemHeader::hasRAWHeader() { + return header==_SEQ_START_CODE; +} + + +unsigned int MpegSystemHeader::getHeader() { + return header; +} + +double MpegSystemHeader::getSCRTimeStamp() { + return scrTimeStamp; +} + + +double MpegSystemHeader::getPTSTimeStamp() { + return ptsTimeStamp; +} + + +int MpegSystemHeader::getPTSFlag() { + return lPTSFlag; +} + + +void MpegSystemHeader::setPTSFlag(int lPTSFlag) { + this->lPTSFlag=lPTSFlag; +} + + +double MpegSystemHeader::getDTSTimeStamp() { + return dtsTimeStamp; +} + + +void MpegSystemHeader::setSCRTimeStamp(double scrTimeStamp) { + this->scrTimeStamp=scrTimeStamp; +} + + +void MpegSystemHeader::setPTSTimeStamp(double ptsTimeStamp) { + this->ptsTimeStamp=ptsTimeStamp; +} + + +void MpegSystemHeader::setDTSTimeStamp(double dtsTimeStamp) { + this->dtsTimeStamp=dtsTimeStamp; +} + + + +int MpegSystemHeader::getLayer() { + return layer; +} + + +void MpegSystemHeader::setLayer(int layer) { + this->layer=layer; +} + +int MpegSystemHeader::hasPSHeader() { + return lHasPSHeader; +} + + +void MpegSystemHeader::addAvailableLayer(int streamID) { + switch (streamID>>4){ + case _PAKET_ID_AUDIO_1>>4: + case _PAKET_ID_AUDIO_2>>4: + availableAudioLayers |= 1<<(streamID - 0xc0); + break; + case _PAKET_ID_VIDEO>>4: + availableVideoLayers |= 1<<(streamID - 0xe0); + break; + case _SUBSTREAM_AC3_ID>>4: + availableAudioLayers |= 1<<(streamID - 0x80); + break; + default: + cout << "unknown streamID MpegSystemHeader::addAvailableLayer"<<endl; + } + + +} +void MpegSystemHeader::resetAvailableLayers() { + availableAudioLayers = 0; + availableVideoLayers = 0; +} + +int MpegSystemHeader::getAudioLayerSelect() { + if (availableAudioLayers & (1<<audioLayerSelect)) + return audioLayerSelect; + else + return 0; +} + +void MpegSystemHeader::setAudioLayerSelect(int layer) { + audioLayerSelect = layer; +} + +int MpegSystemHeader::getVideoLayerSelect() { + if (availableVideoLayers & (1<<videoLayerSelect)) + return videoLayerSelect; + else + return 0; +} + +void MpegSystemHeader::setVideoLayerSelect(int layer) { + videoLayerSelect = layer; +} + + + + + +int MpegSystemHeader::getPacketID() { + return packetID; +} + + +void MpegSystemHeader::setPacketID(int packetID) { + this->packetID=packetID; +} + +int MpegSystemHeader::getPacketLen() { + return packetLen; +} + + +void MpegSystemHeader::setPacketLen(int packetLen) { + this->packetLen=packetLen; +} + + +int MpegSystemHeader::getPESPacketLen() { + return pesPacketLen; +} + +void MpegSystemHeader::setPESPacketLen(int packetLen) { + this->pesPacketLen=packetLen; +} + + +int MpegSystemHeader::getTSPacketLen() { + return tsPacketLen; +} + + +void MpegSystemHeader::setTSPacketLen(int packetLen) { + this->tsPacketLen=packetLen; +} + + + + +int MpegSystemHeader::getRate() { + return rate; +} + + +void MpegSystemHeader::setRate(int rate) { + this->rate=rate; +} + + +int MpegSystemHeader::getStdBufferScale() { + return stdBufferScale; +} + + +void MpegSystemHeader::setStdBufferScale(int stdBufferScale) { + this->stdBufferScale=stdBufferScale; +} + +unsigned long MpegSystemHeader::getStdBufferSize() { + return stdBufferSize; +} + + +void MpegSystemHeader::setStdBufferSize(unsigned long stdBufferSize) { + this->stdBufferSize=stdBufferSize; +} + + +int MpegSystemHeader::getMPEG2() { + return lmpeg2; +} + + +// +// MPEG2 Stuff [START] +// + + +int MpegSystemHeader::getOriginalOrCopy() { + return lOriginal; +} + + +void MpegSystemHeader::setOriginalOrCopy(int lOriginal) { + this->lOriginal=lOriginal; +} + + +int MpegSystemHeader::getCopyRight() { + return lCopyRight; +} + + +void MpegSystemHeader::setCopyRight(int lCopyRight) { + this->lCopyRight=lCopyRight; +} + + + +int MpegSystemHeader::getDataAlignmentIndicator() { + return lDataAlignmentIndicator; +} + + +void MpegSystemHeader::setDataAlignmentIndicator(int lDataAlignmentIndicator) { + this->lDataAlignmentIndicator=lDataAlignmentIndicator; +} + + +int MpegSystemHeader::getPesPriority() { + return lPesPriority; +} + + +void MpegSystemHeader::setPesPriority(int lPesPriority) { + this->lPesPriority=lPesPriority; +} + + + +int MpegSystemHeader::getEncrypted() { + return lEncrypted; +} + + +void MpegSystemHeader::setEncrypted(int lEncrypted) { + this->lEncrypted=lEncrypted; +} + + +int MpegSystemHeader::getStartCodePrefix() { + return startCodePrefix; +} + + +void MpegSystemHeader::setStartCodePrefix(int startCodePrefix) { + this->startCodePrefix=startCodePrefix; +} + + +int MpegSystemHeader::getPTSDTSFlag(){ + return lPTSDTSFlag; +} + + +void MpegSystemHeader::setPTSDTSFlag(int lPTSDTSFlag){ + this->lPTSDTSFlag=lPTSDTSFlag; +} + + +int MpegSystemHeader::getESCRFlag() { + return lESCR; +} + + +void MpegSystemHeader::setESCRFlag(int lESCR) { + this->lESCR=lESCR; +} + + +int MpegSystemHeader::getES_RATE_Flag() { + return lESRateFlag; +} + + +void MpegSystemHeader::setES_RATE_Flag(int lESRateFlag) { + this->lESRateFlag=lESRateFlag; +} + + + +int MpegSystemHeader::getDMSTRICKFLAG(){ + return lDMSTRICKFLAG; +} + + +void MpegSystemHeader::setDMSTRICKFLAG(int lDMSTRICKFLAG) { + this->lDMSTRICKFLAG=lDMSTRICKFLAG; +} + + +int MpegSystemHeader::getADDITIONAL_COPY_FLAG() { + return lADDITIONAL_COPY_FLAG; +} + + +void MpegSystemHeader::setADDITIONAL_COPY_FLAG(int lADDITIONAL_COPY_FLAG) { + this->lADDITIONAL_COPY_FLAG=lADDITIONAL_COPY_FLAG; +} + + + +int MpegSystemHeader::getPES_CRC_FLAG() { + return lPES_CRC_FLAG; +} + + +void MpegSystemHeader::setPES_CRC_FLAG(int lPES_CRC_FLAG) { + this->lPES_CRC_FLAG=lPES_CRC_FLAG; +} + + +int MpegSystemHeader::getPES_EXT_FLAG() { + return lPES_EXT_FLAG; +} + + +void MpegSystemHeader::setPES_EXT_FLAG(int lPES_EXT_FLAG) { + this->lPES_EXT_FLAG=lPES_EXT_FLAG; +} + + + // + // PES EXTENSION [START] + // + +int MpegSystemHeader::getPrivateDataFlag() { + return lPrivateDataFlag; +} + + +void MpegSystemHeader::setPrivateDataFlag(int lPrivateDataFlag) { + this->lPrivateDataFlag=lPrivateDataFlag; +} + + +int MpegSystemHeader::getPackHeaderFieldFlag() { + return lPackHeaderFieldFlag; +} + + +void MpegSystemHeader::setPackHeaderFieldFlag(int lPackHeaderFieldFlag) { + this->lPackHeaderFieldFlag=lPackHeaderFieldFlag; +} + + +int MpegSystemHeader::getSequenceCounterFlag() { + return lSequenceCounterFlag; +} + + +void MpegSystemHeader::setSequenceCounterFlag(int lSequenceCounterFlag) { + this->lSequenceCounterFlag=lSequenceCounterFlag; +} + + + +int MpegSystemHeader::getSTDBufferFlag() { + return lSTDBufferFlag; +} + + +void MpegSystemHeader::setSTDBufferFlag(int lSTDBufferFlag) { + this->lSTDBufferFlag=lSTDBufferFlag; +} + + + +int MpegSystemHeader::getPES_EXT_FLAG_2() { + return lPES_EXT_FLAG_2; +} + + +void MpegSystemHeader::setPES_EXT_FLAG_2(int lPES_EXT_FLAG_2) { + this->lPES_EXT_FLAG_2=lPES_EXT_FLAG_2; +} + + +int MpegSystemHeader::getPES_EXT_FIELD_LENGTH() { + return nPES_EXT_FIELD_LENGTH; +} + + +void MpegSystemHeader::setPES_EXT_FIELD_LENGTH(int nPES_EXT_FIELD_LENGTH) { + this->nPES_EXT_FIELD_LENGTH=nPES_EXT_FIELD_LENGTH; +} + + + + // + // PES EXTENSION [END] + // + + + +int MpegSystemHeader::getPES_HEADER_DATA_LENGTH() { + return nPES_HEADER_DATA_LENGTH; +} + + +void MpegSystemHeader::setPES_HEADER_DATA_LENGTH(int nPES_HEADER_DATA_LENGTH){ + this->nPES_HEADER_DATA_LENGTH=nPES_HEADER_DATA_LENGTH; +} + + +int MpegSystemHeader::getSubStreamID() { + return subStreamID; +} + + +void MpegSystemHeader::setSubStreamID(int subStreamID) { + this->subStreamID=subStreamID; +} + +// +// MPEG2 Stuff [END] +// + + +// +// Transport Stream Header [START] +// + +int MpegSystemHeader:: hasTSHeader() { + return lHasTSHeader; +} + +void MpegSystemHeader::setTSHeader(unsigned int header) { + + lHasTSHeader=false; + + int byte3=header & 0xff; + header>>=8; + int byte2=header & 0xff; + header>>=8; + int byte1=header & 0xff; + header>>=8; + int byte0=header & 0xff; + + + sync_byte=byte0; + header=header >> 8; + transport_error_indicator = (byte1 >> 7) & 0x01; + payload_unit_start_indicator = (byte1 >> 6) & 0x01; + transport_priority = (byte1 >> 5) & 0x01; + pid = ((byte1 << 8) | byte2) & 0x1fff; + transport_scrambling_control = (byte3 >> 6) & 0x03; + adaption_field_control = (byte3 >> 4) & 0x03; + continuity_counter = byte3 & 0x0f; + + if (sync_byte != 0x47) { + return ; + } + if (transport_error_indicator) { + return ; + } + + + lHasTSHeader=true; + +} + +unsigned int MpegSystemHeader::getSync_byte() { + return sync_byte; +} + + +unsigned int MpegSystemHeader::getTransport_error_indicator() { + return transport_error_indicator; +} + + +unsigned int MpegSystemHeader::getPayload_unit_start_indicator() { + return payload_unit_start_indicator; +} + + +unsigned int MpegSystemHeader::getTransport_priority() { + return transport_priority; +} + + +unsigned int MpegSystemHeader::getPid() { + return pid; +} + + +unsigned int MpegSystemHeader::getTransport_scrambling_control() { + return transport_scrambling_control; +} + + +unsigned int MpegSystemHeader::getAdaption_field_control() { + return adaption_field_control; +} + + +unsigned int MpegSystemHeader::getContinuity_counter() { + return continuity_counter; +} + +unsigned int MpegSystemHeader::getPrograms() { + return programs; +} + + +void MpegSystemHeader::setPrograms(unsigned int programs) { + this->programs=programs; +} + + +unsigned int MpegSystemHeader::getProgramNumber() { + return programNumber; +} + + +void MpegSystemHeader::setProgramNumber(unsigned int programNumber) { + this->programNumber=programNumber; +} + + +unsigned int MpegSystemHeader::getPMTPID() { + return pmtPID; +} + + +void MpegSystemHeader::setPMTPID(unsigned int pmtPID) { + this->pmtPID=pmtPID; +} + + +MapPidStream* MpegSystemHeader::lookup(unsigned int pid) { + return mapPidStreamArray[pid % MAX_PIDS]; +} + + +/* + Here we do a mapping from the pid to the "meaning" for the + pid (defined in the TS spec) and then we map this to + a normal mpeg stream ID. + (Which is used in the MpegSystemHeder to identify the + kind of packet we have) +*/ +void MpegSystemHeader::insert(unsigned int pid,unsigned int tsType, + MpegSystemHeader* mpegHeader) { + if (currentPos >= MAX_PIDS) { + cout << "error to much pids in stream.TSSystemStream::insert"<<endl; + return; + } + printf("tsType:%x\n",tsType); + switch(tsType) { + case ISO_11172_VIDEO: + case ISO_13818_VIDEO: + case ISO_11172_AUDIO: + case ISO_13818_AUDIO: + case ISO_13818_PRIVATE: + case ISO_13818_PES_PRIVATE: + case ISO_13522_MHEG: + case ISO_13818_DSMCC: + case ISO_13818_TYPE_A: + case ISO_13818_TYPE_B: + case ISO_13818_TYPE_C: + case ISO_13818_TYPE_D: + case ISO_13818_TYPE_E: + case ISO_13818_AUX: + break; + default: + cout << "ignoring unknown tsType in TSSystemStream::insert"<<endl; + return; + } + + MapPidStream* mapPidStream=lookup(pid); + int psType=_PAKET_ID_NUKE; + + mapPidStream->pid=pid; + mapPidStream->tsType=tsType; + mapPidStream->psType=psType; + mapPidStream->isValid=true; + + currentPos++; +} + + +void MpegSystemHeader::printTSHeader() { + if (hasTSHeader() == false) { + cout << "MpegSystemHeader::printTSHeader: NO TS HEADER"<<endl; + return; + } + + printf("sync:%02X TE:%02X PUS:%02X TP:%02X PID:%04X TSC:%02X " + "AFC:%02X CC:%02X\n", + sync_byte, + transport_error_indicator, + payload_unit_start_indicator, + transport_priority, + pid, + transport_scrambling_control, + adaption_field_control, + continuity_counter); + +} + + +void MpegSystemHeader::printProgramInfo() { + if (programs == 0) { + cout << "MpegSystemHeader::printProgramInfo: NO programs"<<endl; + } else { + cout << "MpegSystemHeader::printProgramInfo: programs:"<<programs<<endl; + } + printf("MPTS: programNumber=%x pmtPid=%x\n",programNumber, pmtPID); + +} + +void MpegSystemHeader::printMap(MapPidStream* mapPidStream) { + if (mapPidStream->isValid == false) { + cout << "TSSystemStream::printMap ** INVALID** "<<endl; + return; + } + + printf("printMap->isValid:%x\n",mapPidStream->isValid); + printf("printMap->pid:%x\n",mapPidStream->pid); + printf("printMap->tsType:%x\n",mapPidStream->tsType); + printf("printMap->psType:%x\n",mapPidStream->psType); + +} + + +// +// Transport Stream Header [END] +// + + + +void MpegSystemHeader::setMPEG2(int lmpeg2) { + this->lmpeg2=lmpeg2; +} + + +void MpegSystemHeader::print() { + cout << "MpegSystemHeader [START]"<<endl; + cout << "layer:"<<getLayer()<<endl; + cout << "MpegSystemHeader [END]"<<endl; + +} + + +void MpegSystemHeader::setPSHeader(unsigned int header) { + lHasPSHeader=false; + if (header == _PACK_START_CODE) { + lHasPSHeader=true; + } + if (header == _SYSTEM_HEADER_START_CODE) { + lHasPSHeader=true; + } +} + +int MpegSystemHeader::isSystemHeader(unsigned int header) { + + if (header == _PACK_START_CODE) return true; + if (header == _SYSTEM_HEADER_START_CODE) return true; + + int byte3=header & 0xff; + header>>=8; + int byte2=header & 0xff; + header>>=8; + int byte1=header & 0xff; + header>>=8; + int byte0=header & 0xff; + + if (byte0 != 0x47) return false; + if ((byte1 >> 7) & 0x01) return false; + + return true; +} diff --git a/mpeglib/lib/mpegplay/mpegSystemHeader.h b/mpeglib/lib/mpegplay/mpegSystemHeader.h new file mode 100644 index 00000000..abad3794 --- /dev/null +++ b/mpeglib/lib/mpegplay/mpegSystemHeader.h @@ -0,0 +1,484 @@ +/* + stores info about system stream and sends data to audio/video + 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 __MPEGSYSTEMHEADER_H +#define __MPEGSYSTEMHEADER_H + + + +#define _PACKET_SYSLAYER 1 +#define _PACKET_NO_SYSLAYER 0 +#define _PACKET_UNKNOWN_LAYER -1 +#define _PACKET_HEADER_SIZE 8 + + +// note: packetid 1 & 2 are normalized to _PAKET_ID_AUDIO +// see packet.cpp + +#define _PAKET_ID_AUDIO_1 ((unsigned char) 0xc0) +#define _PAKET_ID_AUDIO_2 ((unsigned char) 0xd0) +#define _PAKET_ID_VIDEO ((unsigned char) 0xe0) +#define _PAKET_ID_NUKE ((unsigned char) 0x0) + +#define _STD_SYSTEM_CLOCK_FREQ (unsigned long)90000 +#define _MUX_RATE_SCALE_FACTOR 50 +#define _MAX_STREAMS 8 +#define _NOT_PACKET_ID ((unsigned char) 0xff) +#define _KILL_BUFFER ((unsigned char) 0xfe) + + + +#define _STD_AUDIO_STREAM_ID ((unsigned char) 0xb8) +#define _STD_VIDEO_STREAM_ID ((unsigned char) 0xb9) +#define _MIN_STREAM_ID_ID ((unsigned char) 0xbc) +#define _RESERVED_STREAM_ID ((unsigned char) 0xbc) +#define _PRIVATE_STREAM_1_ID ((unsigned char) 0xbd) +#define _PADDING_STREAM_ID ((unsigned char) 0xbe) +#define _PRIVATE_STREAM_2_ID ((unsigned char) 0xbf) +#define _ECM_STREAM_ID ((unsigned char) 0xf0) +#define _EMM_STREAM_ID ((unsigned char) 0xf1) +#define _PROGRAM_STREAM_DIRECTORY_ID ((unsigned char) 0xff) +#define _DSMCC_STREAM_ID ((unsigned char) 0xf2) +#define _ITUTRECH222TYPEE_STREAM_ID ((unsigned char) 0xf8) +#define _SUBSTREAM_AC3_ID ((unsigned char) 0x80) +#define _SUBSTREAM_LPCM_ID ((unsigned char) 0xA0) +#define _SUBSTREAM_SUBPIC_ID ((unsigned char) 0x20) + + +/* Silly Constants.... */ +#define _PACK_START_CODE ((unsigned int)0x000001ba) +#define _SYSTEM_HEADER_START_CODE ((unsigned int)0x000001bb) +#define _PACKET_START_CODE_MASK ((unsigned int)0xffffff00) +#define _PACKET_START_CODE_PREFIX ((unsigned int)0x00000100) +#define _ISO_11172_END_CODE ((unsigned int)0x000001b9) + +#define _SEQ_START_CODE 0x000001b3 + + +// More constants for TS streams +#define NULL_PID 8191 +#define INVALID_PID ((unsigned int)(-1)) +#define INVALID_PROGRAM ((unsigned int)(-1)) +#define INVALID_CC ((unsigned int)(-1)) + +#define ISO_11172_VIDEO 1 +#define ISO_13818_VIDEO 2 +#define ISO_11172_AUDIO 3 +#define ISO_13818_AUDIO 4 +#define ISO_13818_PRIVATE 5 +#define ISO_13818_PES_PRIVATE 6 +#define ISO_13522_MHEG 7 +#define ISO_13818_DSMCC 8 +#define ISO_13818_TYPE_A 9 +#define ISO_13818_TYPE_B 10 +#define ISO_13818_TYPE_C 11 +#define ISO_13818_TYPE_D 12 +#define ISO_13818_TYPE_E 13 +#define ISO_13818_AUX 14 + + +struct MapPidStream_s { + // if this structure "is Valid" (association pid->tsType is ok) + int isValid; + // a not nearer defined int + unsigned int pid; + // the type for the pid defined in Transportstream + unsigned int tsType; + // runtime associated "fake" type for PS stream + unsigned int psType; + // outstanding bytes for PES packet + unsigned int pesPacketSize; +}; + +typedef MapPidStream_s MapPidStream; + + + + + +// More useful things + +#define FLOAT_0x10000 (double)((unsigned long)1 << 16) + + +// MPEG2 PACK HEADER +// SCRbase and SCRext +// 32 .......................................0 9.........0 +// [PACK_START_CODE][01---1--][--------][-----1--][--------][-----1--][-------1 + +#define ui64 unsigned long +#define ui32 unsigned int +#define i64 long +#define i32 int + +#define MPEG1_CLK_REF (i64)90000 +#define MPEG2_CLK_REF (i64)27000000 + +#define ZERO (i64)0 +#define GET_SCRBASE(buf) ( ((ui64)buf[4]&0xF8)>>3 | \ + (ui64)buf[3]<<5 | \ + ((ui64)buf[2]&0x03)<<13 | \ + ((ui64)buf[2]&0xF8)<<12 | \ + (ui64)buf[1]<<20 | \ + ((ui64)buf[0]&0x03)<<28 | \ + (ui64)buf[0]&0x38 <<27 ) + +#define GET_SCREXT(buf) ( ((ui64)buf[5]&0xFE)>>1 | \ + ((ui64)buf[4]&0x03)<<7 ) + +// muxrate +// 22 ......................0 stl +// ... [--------][--------][------11][rrrrr---] +#define GET_MPEG2MUXRATE(buf) ( (ui32)buf[6]<<14 | \ + ((ui32)buf[7])<<6 | \ + ((ui32)buf[8]&0x03)>>2) \ + +#define GET_MPEG2STUFFING(buf) ((buf[9]&0x07)) + +// MPEG1 PACK HEADER +// SCR muxrate +// 32........................................0 22...... +//[PACK_START_CODE][0010---1][--------][-------1][--------][-------1][1-------] +#define GET_SCR(buf) ( ((ui64)buf[4]&0xFE) >>1 | \ + ((ui64)buf[3]) <<7 | \ + ((ui64)buf[2]&0xFE) <<14 | \ + ((ui64)buf[1]) <<22 | \ + ((ui64)buf[0]&0x0E) <<29 ) + +#define GET_MPEG1_PTS(x) (GET_SCR(x)) //they follow the same pattern + +#define GET_MPEG1_MUXRATE(x) ( ((ui32)x[7]&0xFE) >>1 | \ + ((ui32)x[6]) <<7 | \ + ((ui32)x[5]&0x7F) <<15 ) + +#define GET_MPEG2_PTS_FLAGS(buf) ( ((ui8)buf[3]&0xC0)>>6 ) +// MPEG2 PES packet (optional parameters) +// PTS +// 32........................................0 +// [PACKET_START_CODE][001x---1][--------][-------1][--------][-------1] +#define GET_MPEG2_PTS(buf) GET_MPEG1_PTS(buf) + + + +#include <stdio.h> + + +class MpegSystemHeader { + + int lPTSFlag; + double scrTimeStamp; + double ptsTimeStamp; + double dtsTimeStamp; + + int layer; + unsigned int header; + int lHasPSHeader; + + int lmpeg2; + + int packetID; + int packetLen; + + int pesPacketLen; + int tsPacketLen; + + unsigned long rate; + int stdBufferScale; + unsigned long stdBufferSize; + + /* This are bitmaps, if bit x is a 1 the stream number x is + available */ + unsigned long availableAudioLayers; + unsigned long availableVideoLayers; + + int audioLayerSelect; + int videoLayerSelect; + + // + // MPEG2 Header Info [START] + // + int lOriginal; + int lCopyRight; + int lDataAlignmentIndicator; + int lPesPriority; + int lEncrypted; + int startCodePrefix; + + + + int lPTSDTSFlag; + int lESCR; + int lESRateFlag; + int lDMSTRICKFLAG; + int lADDITIONAL_COPY_FLAG; + int lPES_CRC_FLAG; + int lPES_EXT_FLAG; + int nPES_HEADER_DATA_LENGTH; + + // EXT FILED [START] + + int lPrivateDataFlag; + int lPackHeaderFieldFlag; + int lSequenceCounterFlag; + int lSTDBufferFlag; + int lPES_EXT_FLAG_2; + int nPES_EXT_FIELD_LENGTH; + // EXT FILED [END] + + int subStreamID; + // + // MPEG2 Header Info [END] + // + + // + // Transport Stream Header [START] + // + + int lHasTSHeader; + + unsigned int sync_byte; + unsigned int transport_error_indicator; + unsigned int payload_unit_start_indicator; + unsigned int transport_priority; + unsigned int pid; + unsigned int transport_scrambling_control; + unsigned int adaption_field_control; + unsigned int continuity_counter; + + unsigned int programs; + unsigned int programNumber; + unsigned int pmtPID; + + MapPidStream** mapPidStreamArray; + int currentPos; + + // + // Transport Stream Header [END] + // + + public: + MpegSystemHeader(); + ~MpegSystemHeader(); + + void setHeader(unsigned int header); + unsigned int getHeader(); + int hasRAWHeader(); + + + int getPTSFlag(); + void setPTSFlag(int lPTSFlag); + + double getSCRTimeStamp(); + double getPTSTimeStamp(); + double getDTSTimeStamp(); + + + void setSCRTimeStamp(double timeStamp); + void setPTSTimeStamp(double ptsTimeStamp); + void setDTSTimeStamp(double dtsTimeStamp); + + // returns 1 if it is a syslayer 0 if non syslayer -1 if unknown + int getLayer(); + void setLayer(int layer); + int hasPSHeader(); + + // + // MPEG2 Stuff [START] + // + + int getMPEG2(); + void setMPEG2(int lmpeg2); + + // 1 Byte [Start] + int getOriginalOrCopy(); + void setOriginalOrCopy(int lOriginal); + + int getCopyRight(); + void setCopyRight(int lCopyRight); + + int getDataAlignmentIndicator(); + void setDataAlignmentIndicator(int lDataAlignmentIndicator); + + int getPesPriority(); + void setPesPriority(int lPesPriority); + + int getEncrypted(); + void setEncrypted(int lEncrypted); + + int getStartCodePrefix(); + void setStartCodePrefix(int startCodePrefix); + + // 1. Byte [End] + + int getPTSDTSFlag(); + void setPTSDTSFlag(int lPTSDTSFlag); + + int getESCRFlag(); + void setESCRFlag(int lESCR); + + int getES_RATE_Flag(); + void setES_RATE_Flag(int lESRateFlag); + + + int getDMSTRICKFLAG(); + void setDMSTRICKFLAG(int lDMSTRICKFLAG); + + int getADDITIONAL_COPY_FLAG(); + void setADDITIONAL_COPY_FLAG(int lADDITIONAL_COPY_FLAG); + + int getPES_CRC_FLAG(); + void setPES_CRC_FLAG(int lPES_CRC_FLAG); + + int getPES_EXT_FLAG(); + void setPES_EXT_FLAG(int lPES_EXT_FLAG); + + // + // PES EXTENSION [START] + // + + int getPrivateDataFlag(); + void setPrivateDataFlag(int lPrivateDataFlag); + + int getPackHeaderFieldFlag(); + void setPackHeaderFieldFlag(int lPackHeaderFieldFlag); + + int getSequenceCounterFlag(); + void setSequenceCounterFlag(int lSequenceCounterFlag); + + int getSTDBufferFlag(); + void setSTDBufferFlag(int lSTDBufferFlag); + + int getPES_EXT_FLAG_2(); + void setPES_EXT_FLAG_2(int lPES_EXT_FLAG_2); + + int getPES_EXT_FIELD_LENGTH(); + void setPES_EXT_FIELD_LENGTH(int nPES_EXT_FIELD_LENGTH); + + + + // + // PES EXTENSION [END] + // + + int getPES_HEADER_DATA_LENGTH(); + void setPES_HEADER_DATA_LENGTH(int nPES_HEADER_DATA_LENGTH); + + + int getSubStreamID(); + void setSubStreamID(int subStreamID); + + + // + // MPEG2 Stuff [END] + // + + + // + // Transport Stream Header [START] + // + + // returns true if it is ts header & sets the TS + // values in this class. + int hasTSHeader(); + + + unsigned int getSync_byte(); + unsigned int getTransport_error_indicator(); + unsigned int getPayload_unit_start_indicator(); + unsigned int getTransport_priority(); + unsigned int getPid(); + unsigned int getTransport_scrambling_control(); + unsigned int getAdaption_field_control(); + unsigned int getContinuity_counter(); + + unsigned int getPrograms(); + void setPrograms(unsigned int programs); + + unsigned int getProgramNumber(); + void setProgramNumber(unsigned int programNumber); + + unsigned int getPMTPID(); + void setPMTPID(unsigned int pmtPID); + + // + // manage different pids and their tsTypes and the fake psTypes + // + + MapPidStream* lookup(unsigned int pid); + void insert(unsigned int pid,unsigned int tsType, + MpegSystemHeader* mpegHeader); + + + void printTSHeader(); + void printProgramInfo(); + void printMap(MapPidStream* mapPidStream); + + // + // Transport Stream Header [END] + // + + + + void addAvailableLayer(int streamID); + void resetAvailableLayers(); + + int getAudioLayerSelect(); + void setAudioLayerSelect(int layer); + + int getVideoLayerSelect(); + void setVideoLayerSelect(int layer); + + + int getPacketID(); + void setPacketID(int packetID); + + // data which can be safley read and belongs to packetID + int getPacketLen(); + void setPacketLen(int packetLen); + + // length of PES packet (normally == getPacketLent) + int getPESPacketLen(); + void setPESPacketLen(int packetLen); + + // rest lenght of TS packet. + int getTSPacketLen(); + void setTSPacketLen(int packetLen); + + + + int getRate(); + void setRate(int rate); + + int getStdBufferScale(); + void setStdBufferScale(int stdBufferScale); + + unsigned long getStdBufferSize(); + void setStdBufferSize(unsigned long stdBufferSize); + + void print(); + + // return true is system header in some kind (TS or 1ba/1bb) + static int isSystemHeader(unsigned int header); + + private: + void setTSHeader(unsigned int header); + void setPSHeader(unsigned int header); + +}; + +#endif + + + diff --git a/mpeglib/lib/mpegplay/mpegSystemStream.cpp b/mpeglib/lib/mpegplay/mpegSystemStream.cpp new file mode 100644 index 00000000..ca25d7e8 --- /dev/null +++ b/mpeglib/lib/mpegplay/mpegSystemStream.cpp @@ -0,0 +1,235 @@ +/* + reads paket 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 "mpegSystemStream.h" + +#define _RESYNC_STATE_INIT 0 +#define _RESYNC_STATE_NEED_PACKET 1 +#define _RESYNC_STATE_NEED_START 2 + +#include <iostream> + +using namespace std; + + +MpegSystemStream::MpegSystemStream(InputStream* input) { + this->input=input; + syncCode=0xff; // invalid + lState=_RESYNC_STATE_INIT; + tsSystemStream=new TSSystemStream(input); + psSystemStream=new PSSystemStream(input); + pesSystemStream=new PESSystemStream(input); +} + + +MpegSystemStream::~MpegSystemStream() { + delete tsSystemStream; + delete psSystemStream; + delete pesSystemStream; +} + + +int MpegSystemStream::getByteDirect() { + unsigned char byte; + if (input->read((char*)&byte,1) != 1) { + return -1; + } + return (int)byte; +} + +int MpegSystemStream::readSyncCode() { + int byte; + byte=getByteDirect(); + if (byte==-1) { + return false; + } + + syncCode<<=8; + syncCode|=byte; + syncCode&=0xffffffff; + return true; + +} + +int MpegSystemStream::firstInitialize(MpegSystemHeader* mpegHeader) { + + if (readSyncCode() == false) { + return false; + } + mpegHeader->setHeader(syncCode); + + // SEQ_START_CODE: 1b3 + if (mpegHeader->hasRAWHeader()) { + // If we found a seq_heade_start code we assume + // that we are a video only stream + // we must directly insert it. + + // here we set for all future calls fixed + // parameter + mpegHeader->setLayer(_PACKET_NO_SYSLAYER); // no syslayer + mpegHeader->setPacketID(_PAKET_ID_VIDEO); + mpegHeader->setPacketLen(8192); + mpegHeader->resetAvailableLayers(); + return true; + } + // no 1bb + if (syncCode == _SYSTEM_HEADER_START_CODE) return false; + + // TS 1ba + if (processSystemHeader(mpegHeader) == true) { + // have init. we are a syslayer + mpegHeader->setLayer(_PACKET_SYSLAYER); // syslayer + lState=_RESYNC_STATE_NEED_START; + return true; + } + return false; + +} + +void MpegSystemStream::reset() { + lState=_RESYNC_STATE_NEED_PACKET; +} + + +int MpegSystemStream::nextPacket(MpegSystemHeader* mpegHeader) { + int layer=mpegHeader->getLayer(); + if (layer == _PACKET_NO_SYSLAYER) { + return true; + } + // seek to packet + if (readSyncCode() == false) { + return false; + } + + + // default to "HLT" operation + mpegHeader->setPacketID(_PAKET_ID_NUKE); + mpegHeader->setPacketLen(0); + + + // here we know that we are a SYSLAYER (TS or 1ba) + if (lState == _RESYNC_STATE_NEED_PACKET) { + // no 1bb codes in resync state + if (syncCode == _SYSTEM_HEADER_START_CODE) return false; + } + + // is this a syslayer _STARTCODE_ ? + if (MpegSystemHeader::isSystemHeader(syncCode)==true) { + // set startcode & process it + mpegHeader->setHeader(syncCode); + // TS 1ba 1bb + if (processSystemHeader(mpegHeader) == true) { + lState=_RESYNC_STATE_NEED_START; + return true; + } + reset(); + return false; + } + + if (lState != _RESYNC_STATE_NEED_START) return false; + + // no syslayer startcode. PES processing + if ((syncCode & 0xFFFFFF00) == 0x00000100) { + int bytes=pesSystemStream->processStartCode(syncCode,mpegHeader); + if (bytes == 0) { + reset(); + return false; + } + // if we are a TS layer we cannot read getPESPacketLength byte + // but only the bytes given by getTSPacketLength + // additionally we must store the mapping between pid and real packetID. + if (mpegHeader->hasTSHeader()) { + unsigned int pid=mpegHeader->getPid(); + unsigned int id =mpegHeader->getPacketID(); + printf("current PID:%x current PacketID:%x\n",pid,id); + MapPidStream* mapPidStream=mpegHeader->lookup(pid); + mapPidStream->psType=id; + mapPidStream->pesPacketSize=mpegHeader->getPESPacketLen(); + + int ts=mpegHeader->getTSPacketLen(); + if (bytes > ts) { + cout << "ERROR PES READ MORE than TS HAS"<<endl; + return false; + } + mpegHeader->setTSPacketLen(ts-bytes); + return demux_ts_pes_buffer(mpegHeader); + } + // 1ba stream + mpegHeader->setPacketLen(mpegHeader->getPESPacketLen()); + return true; + } + + // something unknown/else went wrong + return false; +} + +int MpegSystemStream::demux_ts_pes_buffer(MpegSystemHeader* mpegHeader) { + + + if (lState == _RESYNC_STATE_NEED_PACKET) { + cout << "NO ts_pes because of resync"<<endl; + return false; + } + MapPidStream* mapPidStream=mpegHeader->lookup(mpegHeader->getPid()); + + int pes=mapPidStream->pesPacketSize; + int ts=mpegHeader->getTSPacketLen(); + int wantRead=pes; + + // bug workaround for PES packetlength == 0 + if (pes > 0) { + if (ts < wantRead) { + cout << "TS is less setting wantRead:"<<ts<<endl; + mapPidStream->pesPacketSize=pes-ts; + wantRead=ts; + } else { + // pes < ts + mpegHeader->setTSPacketLen(ts-pes); + wantRead=pes; + } + } else { + // in case of bug, always put the whole packet for pid in + wantRead=ts; + } + mpegHeader->setPacketID(mapPidStream->psType); + mpegHeader->setPacketLen(wantRead); + return true; +} + + +int MpegSystemStream::processSystemHeader(MpegSystemHeader* mpegHeader) { + if (mpegHeader->hasTSHeader()) { + if (tsSystemStream->processStartCode(mpegHeader) == true) { + if (mpegHeader->getPacketID() == _PAKET_ID_NUKE) { + // nuke the data by signalling how much bytes to nuke + mpegHeader->setPacketLen(mpegHeader->getTSPacketLen()); + return true; + } + unsigned int pus=mpegHeader->getPayload_unit_start_indicator(); + if (pus == false) { + // we need to append data + return demux_ts_pes_buffer(mpegHeader); + } + return true; + } + return false; + } + if (mpegHeader->hasPSHeader()) { + return (psSystemStream->processStartCode(mpegHeader)); + } + return false; + +} + + + diff --git a/mpeglib/lib/mpegplay/mpegSystemStream.h b/mpeglib/lib/mpegplay/mpegSystemStream.h new file mode 100644 index 00000000..8c5d5ffa --- /dev/null +++ b/mpeglib/lib/mpegplay/mpegSystemStream.h @@ -0,0 +1,53 @@ +/* + reads paket input data + 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 __MPEGSYSTEMSTREAM_H +#define __MPEGSYSTEMSTREAM_H + + + +#include "tsSystemStream.h" +#include "psSystemStream.h" +#include "pesSystemStream.h" + + +class MpegSystemStream { + + InputStream* input; + int lHasLength; + unsigned int syncCode; + int lState; + TSSystemStream* tsSystemStream; + PSSystemStream* psSystemStream; + PESSystemStream* pesSystemStream; + + public: + MpegSystemStream(InputStream* input); + ~MpegSystemStream(); + + // returns true if init successful + int firstInitialize(MpegSystemHeader* mpegHeader); + int nextPacket(MpegSystemHeader* mpegHeader); + inline int eof() { return input->eof(); } + void reset(); + + private: + int readSyncCode(); + int getByteDirect(); + int demux_ts_pes_buffer(MpegSystemHeader* mpegHeader); + + int processSystemHeader(MpegSystemHeader* mpegHeader); + + +}; + +#endif diff --git a/mpeglib/lib/mpegplay/mpegVideoBitWindow.cpp b/mpeglib/lib/mpegplay/mpegVideoBitWindow.cpp new file mode 100644 index 00000000..87467a9c --- /dev/null +++ b/mpeglib/lib/mpegplay/mpegVideoBitWindow.cpp @@ -0,0 +1,258 @@ +/* + bitwindow mpeg video + 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 "mpegVideoBitWindow.h" + +#include <iostream> + +using namespace std; + + +MpegVideoBitWindow::MpegVideoBitWindow() { + // Make buffer length multiple of 4. + + this->size=80000; + + + + if ((size % 4) != 0) { + cout << "MpegVideoStream not multiple of 4"<<endl; + exit(-1); + } + + /* Create MpegVideoStream. */ + buf_start = (unsigned int*) malloc (sizeof(unsigned int)*(size*4)); + + /* + * Set max_buf_length to one less than actual length to deal with messy + * data without proper seq. end codes. + */ + max_buf_length=size-1; + + + /* Initialize bitstream i/o fields. */ + + bit_offset = 0; + buffer = buf_start; + buf_length = 0; + num_left=0; + leftover_bytes=0; + curBits = 0; + + + + + nBitMask[0] = 0x00000000; + nBitMask[1] = 0x80000000; + nBitMask[2] = 0xc0000000; + nBitMask[3] = 0xe0000000; + nBitMask[4] = 0xf0000000; + nBitMask[5] = 0xf8000000; + nBitMask[6] = 0xfc000000; + nBitMask[7] = 0xfe000000; + nBitMask[8] = 0xff000000; + nBitMask[9] = 0xff800000; + nBitMask[10] = 0xffc00000; + nBitMask[11] = 0xffe00000; + nBitMask[12] = 0xfff00000; + nBitMask[13] = 0xfff80000; + nBitMask[14] = 0xfffc0000; + nBitMask[15] = 0xfffe0000; + nBitMask[16] = 0xffff0000; + nBitMask[17] = 0xffff8000; + nBitMask[18] = 0xffffc000; + nBitMask[19] = 0xffffe000; + nBitMask[20] = 0xfffff000; + nBitMask[21] = 0xfffff800; + nBitMask[22] = 0xfffffc00; + nBitMask[23] = 0xfffffe00; + nBitMask[24] = 0xffffff00; + nBitMask[25] = 0xffffff80; + nBitMask[26] = 0xffffffc0; + nBitMask[27] = 0xffffffe0; + nBitMask[28] = 0xfffffff0; + nBitMask[29] = 0xfffffff8; + nBitMask[30] = 0xfffffffc; + nBitMask[31] = 0xfffffffe; + nBitMask[32] = 0xffffffff; + + +} + + +MpegVideoBitWindow::~MpegVideoBitWindow() { + delete buf_start; +} + + + +int MpegVideoBitWindow::appendToBuffer(unsigned char* ptr,int len) { + int byte_length = getLength()*4; + + + resizeBuffer(len); + + if (num_left != 0) { + byte_length += num_left; + *(buffer+buf_length)=leftover_bytes; + } + memcpy(((unsigned char *)buffer)+byte_length,ptr,len); + + if ((unsigned long int)1 != ntohl(1)) { + unsigned int *mark = buffer+buf_length; + int i; + int n=(len+num_left)&0xfffffffc; + for (i=0; i < n; i+=4) { + *mark=ntohl(*mark); + mark++; + } + } + byte_length = byte_length + len; + num_left = byte_length % 4; + buf_length = byte_length / 4; + updateCurBits(); + + leftover_bytes = *(buffer +buf_length); + return true; +} + +int MpegVideoBitWindow::getLinearFree() { + unsigned int* endPos=buf_start+size; + unsigned int* currPos=buffer+buf_length; + + int back=endPos-currPos; + return back; +} + + + + + +void MpegVideoBitWindow::flushByteOffset() { + int byteoff; + + byteoff = bit_offset % 8; + + if (byteoff != 0) { + flushBitsDirect((8-byteoff)); + } +} + + +void MpegVideoBitWindow::appendToBuffer(unsigned int startCode) { + unsigned int startCodeRaw=htonl(startCode); + resizeBuffer(4); + appendToBuffer((unsigned char*)&startCodeRaw,4); +} + + +void MpegVideoBitWindow::clear() { + buffer = buf_start; + buf_length = 0; + bit_offset = 0; + curBits = 0; +} + + +int MpegVideoBitWindow::getLength() { + return buf_length; +} + + + + + + + +void MpegVideoBitWindow::printChar(int bytes) { + int i; + unsigned char* mark; + + mark=(unsigned char *)buffer; + + for(i=0;i<bytes;i++) { + printf("i:%d read=%x\n",i,mark[i]); + } + printf("*********\n"); + +} + + +void MpegVideoBitWindow::printInt(int bytes) { + int i; + int n; + unsigned int* mark; + + mark=(unsigned int*)buf_start; + + n=bytes/sizeof(int); + for(i=0;i<n;i++) { + printf("i:%d read=%x\n",i,mark[i]); + } + printf("*********\n"); + +} + + +void MpegVideoBitWindow::print() { + int byte_length = getLength()*4; + + printf("bit_offset:%x\n",bit_offset); + printf("num_left:%x\n",num_left); + printf("leftover_bytes:%x\n",leftover_bytes); + printf("buf_length:%x\n",buf_length); + printf("curBits:%x\n",curBits); + printf("pos:%8x\n",byte_length); + printChar(8); +} + + +void MpegVideoBitWindow::resizeBuffer(int insertBytes) { + /* Read all the headers, now make room for packet */ + if (buf_start+max_buf_length < buffer+insertBytes/4+buf_length) { + + if (max_buf_length - buf_length < (int) insertBytes/4) { + + /* Buffer too small for a packet (plus whats there), + * time to enlarge it! + */ + + unsigned int *old = buf_start; + max_buf_length=buf_length+insertBytes/4+1; + + buf_start=(unsigned int*) malloc(sizeof(unsigned int)*max_buf_length); + if (buf_start == NULL) { + cout << "allocation of:"<<max_buf_length<<" bytes failed"<<endl; + exit(0); + } + memcpy((unsigned char *)buf_start,buffer,(unsigned int)buf_length*4); + delete old; + buffer = buf_start; + cout << "enlarge buffer-1 end***********"<<endl; + + } else { + memcpy((unsigned char *)buf_start, + buffer, (unsigned int) buf_length*4); + buffer = buf_start; + } + } +} + + +void MpegVideoBitWindow::fillWithIsoEndCode(int bytes) { + int i; + int n=bytes/4; + for (i=0;i<n;i++) { + appendToBuffer(ISO_11172_END_CODE); + } +} diff --git a/mpeglib/lib/mpegplay/mpegVideoBitWindow.h b/mpeglib/lib/mpegplay/mpegVideoBitWindow.h new file mode 100644 index 00000000..46abe44e --- /dev/null +++ b/mpeglib/lib/mpegplay/mpegVideoBitWindow.h @@ -0,0 +1,108 @@ +/* + bitwindow mpeg video + 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 __MPEGVIDEOBITWINDOW_H +#define __MPEGVIDEOBITWINDOW_H + +#include "../input/inputPlugin.h" + + +#define ISO_11172_END_CODE ((unsigned int)0x000001b9) + +class MpegVideoBitWindow { + int size; /* size of buffer */ + unsigned int bit_offset; /* Bit offset in stream. */ + unsigned int *buffer; /* Pointer to next byte in buffer */ + int buf_length; /* Length of remaining buffer.*/ + unsigned int *buf_start; /* Pointer to buffer start. */ + int max_buf_length; /* Max length of buffer. */ + unsigned int num_left; /* from ReadPacket - leftover */ + unsigned int leftover_bytes; /* from ReadPacket - leftover */ + unsigned int curBits; /* current bits */ + + + unsigned int nBitMask[33]; + + + public: + MpegVideoBitWindow(); + ~MpegVideoBitWindow(); + + int appendToBuffer(unsigned char* ptr,int len); + int getLinearFree(); + // true if feof() is true and the buffer is emtpy + int isEof(); + void flushByteOffset(); + void appendToBuffer(unsigned int startCode); + + + inline void updateCurBits() { + curBits = *buffer << bit_offset; + } + + inline unsigned int showBits(int bits) { + + unsigned int mask=nBitMask[bits]; + int shift=32-(bits); + int bO; + shift=(curBits & mask)>>shift; + bO = bit_offset + bits; + if (bO > 32) { + return (shift | (*(buffer+1)>>(64-bO))); + } + return shift; + } + + inline unsigned int showBits32() { + if (bit_offset) { + return (curBits | (*(buffer+1) >> (32 - bit_offset))); + } + return curBits; + } + + inline void flushBitsDirect(unsigned int bits) { + bit_offset += bits; + if (bit_offset & 0x20) { + bit_offset -= 32; + bit_offset &= 0x1f; + buffer++; + updateCurBits(); + buf_length--; + } + else { + curBits <<= bits; + } + } + + inline unsigned int getBits(int bits) { + unsigned int result=showBits(bits); + flushBitsDirect(bits); + return result; + } + + void clear(); + int getLength(); + + int hasBytes(int bytes); + + void printChar(int bytes); + void printInt(int bytes); + void print(); + void resizeBuffer(int insertBytes); + void fillWithIsoEndCode(int bytes); + + + +}; +#endif diff --git a/mpeglib/lib/mpegplay/mpegVideoHeader.cpp b/mpeglib/lib/mpegplay/mpegVideoHeader.cpp new file mode 100644 index 00000000..e91401a8 --- /dev/null +++ b/mpeglib/lib/mpegplay/mpegVideoHeader.cpp @@ -0,0 +1,293 @@ +/* + stores sequence header info, for reinit of stream + 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 "mpegVideoHeader.h" + +#include "mpegExtension.h" +#include "mpegVideoStream.h" + +#include <iostream> + +using namespace std; + +/* Video rates table */ +/* Cheat on Vid rates, round to 30, and use 30 if illegal value + Except for 9, where Xing means 15, and given their popularity, we'll + be nice and do it */ + +static double VidRateNum[16]={29.97, 24, 24, 25, 29.97, 29.97, 50, 59.94, + 59.94, 14.985, 29.97, 29.97, 29.97, 29.97, + 29.97, 29.97}; + + + +static const unsigned char default_intra_matrix[64] = { + 8, 16, 19, 22, 26, 27, 29, 34, + 16, 16, 22, 24, 27, 29, 34, 37, + 19, 22, 26, 27, 29, 34, 34, 38, + 22, 22, 26, 27, 29, 34, 37, 40, + 22, 26, 27, 29, 32, 35, 40, 48, + 26, 27, 29, 32, 35, 40, 48, 58, + 26, 27, 29, 34, 38, 46, 56, 69, + 27, 29, 35, 38, 46, 56, 69, 83}; + + + +/* Set up array for fast conversion from zig zag order to row/column + coordinates. +*/ + +const int zigzag[64][2] = { + {0,0},{1,0},{0,1},{0,2},{1,1},{2,0},{3,0},{2,1},{1,2},{0,3},{0,4},{1,3}, + {2,2},{3,1},{4,0},{5,0},{4,1},{3,2},{2,3},{1,4},{0,5},{0,6},{1,5},{2,4}, + {3,3},{4,2},{5,1},{6,0},{7,0},{6,1},{5,2},{4,3},{3,4},{2,5},{1,6},{0,7}, + {1,7},{2,6},{3,5},{4,4},{5,3},{6,2},{7,1},{7,2},{6,3},{5,4},{4,5},{3,6}, + {2,7},{3,7},{4,6},{5,5},{6,4},{7,3},{7,4},{6,5},{5,6},{4,7},{5,7},{6,6}, + {7,5},{7,6},{6,7},{7,7} }; + + + + + +MpegVideoHeader::MpegVideoHeader() { + init(); + +} + + +void MpegVideoHeader::init() { + + h_size=0; + v_size=0; + mb_height=0; + mb_width=0; + mb_size=0; + aspect_ratio=0; + bit_rate=0; + vbv_buffer_size=0; + const_param_flag=0; + picture_rate=0.0; + extension=new MpegExtension(); + init_quanttables(); + +} + +void MpegVideoHeader::init_quanttables() { + int i; + int j; + + /* Copy default intra matrix. */ + + for (i = 0; i < 8; i++) { + for (j = 0; j < 8; j++) { + intra_quant_matrix[i][j]=default_intra_matrix[i*8+j]; + } + } + + /* Initialize non intra quantization matrix. */ + + for (i = 0; i < 8; i++) { + for (j = 0; j < 8; j++) { + non_intra_quant_matrix[i][j] = 16; + } + } +} + + +MpegVideoHeader::~MpegVideoHeader() { + + delete extension; + +} + + + +/* + *-------------------------------------------------------------- + * + * ParseSeqHead -- + * + * Assumes bit stream is at the END of the sequence + * header start code. Parses off the sequence header. + * + * Results: + * Fills the vid_stream structure with values derived and + * decoded from the sequence header. Allocates the pict image + * structures based on the dimensions of the image space + * found in the sequence header. + * + * Side effects: + * Bit stream irreversibly parsed off. + * + *-------------------------------------------------------------- + */ +int MpegVideoHeader::parseSeq(MpegVideoStream* mpegVideoStream) { + unsigned int data; + int i ; + + // seq_start_code already flushed!!! + + /* Get horizontal size of image space. */ + + h_size=mpegVideoStream->getBits(12); + + /* Get vertical size of image space. */ + + v_size=mpegVideoStream->getBits(12); + + + /* Calculate macroblock width and height of image space. */ + + mb_width = (h_size + 15) / 16; + mb_height = (v_size + 15) / 16; + mb_size=mb_height * mb_width-1; + + + + /* Parse of aspect ratio code. */ + + data=mpegVideoStream->getBits(4); + + aspect_ratio = (unsigned char) data; + + /* Parse off picture rate code. */ + + data=mpegVideoStream->getBits(4); + picture_rate=VidRateNum[data]; + + /* Parse off bit rate. */ + + data=mpegVideoStream->getBits(18); + bit_rate = data; + + /* Flush marker bit. */ + + mpegVideoStream->flushBits(1); + + /* Parse off vbv buffer size. */ + + data=mpegVideoStream->getBits(10); + vbv_buffer_size = data; + + /* Parse off contrained parameter flag. */ + + data=mpegVideoStream->getBits(1); + if (data) { + const_param_flag = true; + } else + const_param_flag = false; + + /* + * If intra_quant_matrix_flag set, parse off intra quant matrix values. + */ + data=mpegVideoStream->getBits(1); + if (data) { + for (i = 0; i < 64; i++) { + data=mpegVideoStream->getBits(8); + intra_quant_matrix[zigzag[i][1]][zigzag[i][0]]=(unsigned char)data; + } + } + /* + * If non intra quant matrix flag set, parse off non intra quant matrix + * values. + */ + + data=mpegVideoStream->getBits(1); + if (data) { + for (i = 0; i < 64; i++) { + data=mpegVideoStream->getBits(8); + + non_intra_quant_matrix[zigzag[i&0x3f][1]][zigzag[i&0x3f][0]]= + (unsigned char) data; + } + } + /* + * If next start code is extension/user start code, + * parse off extension data. + */ + extension->processExtensionData(mpegVideoStream); + + return true; + +} + + + + +void MpegVideoHeader::copyTo(MpegVideoHeader* dest) { + + + dest->h_size=h_size; + dest->v_size=v_size; + dest->mb_height=mb_height; + dest->mb_width=mb_width; + dest->mb_size=mb_size; + dest->aspect_ratio=aspect_ratio; + dest->bit_rate=bit_rate; + dest->vbv_buffer_size=vbv_buffer_size; + dest->const_param_flag=const_param_flag; + dest->picture_rate=picture_rate; + + int i; + int j; + + + /* Copy default intra matrix. */ + + for (i = 0; i < 8; i++) { + for (j = 0; j < 8; j++) { + dest->intra_quant_matrix[i][j]=intra_quant_matrix[i][j]; + + } + } + + /* Initialize non intra quantization matrix. */ + + for (i = 0; i < 8; i++) { + for (j = 0; j < 8; j++) { + dest->non_intra_quant_matrix[i][j] =non_intra_quant_matrix[i][j] ; + } + } + +} + + + + +double MpegVideoHeader::getPictureTime() { + if (picture_rate > 0) { + return 1.0/picture_rate; + } + return 0.0; +} + + + + + + + +void MpegVideoHeader::print(char* description) { + cout << "MpegVideoHeader [START]:"<<description<<endl; + cout <<"h_size:"<<h_size<<endl; + cout <<"v_size:"<<v_size<<endl; + cout <<"mb_height:"<<mb_height<<endl; + cout <<"mb_width:"<<mb_width<<endl; + cout <<"mb_size:"<<mb_size<<endl; + cout <<"aspect_ratio:"<<aspect_ratio<<endl; + cout <<"bit_rate:"<<bit_rate<<endl; + cout <<"vbv_buffer_size:"<<vbv_buffer_size<<endl; + cout <<"const_param_flag:"<<const_param_flag<<endl; + cout << "MpegVideoHeader [END]:"<<endl; + +} diff --git a/mpeglib/lib/mpegplay/mpegVideoHeader.h b/mpeglib/lib/mpegplay/mpegVideoHeader.h new file mode 100644 index 00000000..bb3302a1 --- /dev/null +++ b/mpeglib/lib/mpegplay/mpegVideoHeader.h @@ -0,0 +1,83 @@ +/* + stores sequence header info, for reinit of stream + 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 __MPEGVIDEOHEADER_H +#define __MPEGVIDEOHEADER_H + + + +/** + Some vcd do only have one sequence header for the whole + cd. + This means we must store this info even after a seek + which usually destroy the video stream object. + We then can re-init the video object with the values + we store here. + + Here we have the "header" for an mpeg video stream. + +*/ + + +class MpegVideoHeader { + + unsigned int h_size; /* Horiz. size in pixels. */ + unsigned int v_size; /* Vert. size in pixels. */ + int mb_height; /* Vert. size in mblocks. */ + int mb_width; /* Horiz. size in mblocks. */ + int mb_size; /* mb_height*mb_width-1 */ + unsigned char aspect_ratio; /* Code for aspect ratio. */ + unsigned int bit_rate; /* Bit rate. */ + unsigned int vbv_buffer_size; /* Minimum buffer size. */ + int const_param_flag; /* Contrained parameter flag. */ + float picture_rate; /* Parse off picture rate code*/ + unsigned int intra_quant_matrix[8][8]; /* Quantization matrix for + intracoded frames. */ + unsigned int non_intra_quant_matrix[8][8]; /* Quanitization matrix for + non intracoded frames. */ + class MpegExtension* extension; + + + public: + + MpegVideoHeader(); + ~MpegVideoHeader(); + + int parseSeq(class MpegVideoStream* mpegVideoStream); + void copyTo(MpegVideoHeader* dest); + void print(char* description); + void init_quanttables(); + + inline int getMB_Height() { return mb_height;} + inline int getMB_Size() { return mb_size;} + inline int getMB_Width() { return mb_width;} + + inline float getPictureRate() { return picture_rate ;} + double getPictureTime(); + + inline unsigned int* getIntra_quant_matrix() { + // printf("getI:%p\n",intra_quant_matrix[0]); + return intra_quant_matrix[0]; } + inline unsigned int* getNon_intra_quant_matrix() { + // printf("getN:%p\n",non_intra_quant_matrix[0]); + return non_intra_quant_matrix[0]; } + + private: + void init(); + +}; + +#endif diff --git a/mpeglib/lib/mpegplay/mpegVideoLength.cpp b/mpeglib/lib/mpegplay/mpegVideoLength.cpp new file mode 100644 index 00000000..4befa31a --- /dev/null +++ b/mpeglib/lib/mpegplay/mpegVideoLength.cpp @@ -0,0 +1,424 @@ +/* + 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 "mpegVideoLength.h" + +#include "../mpegplay/mpegVideoStream.h" +#include "../mpegplay/gop.h" + +#include <iostream> + +using namespace std; + +#define SEARCH_SIZE 1024*1024*6 +#define SEEKWINDOW 1024*1024 + +MpegVideoLength::MpegVideoLength(InputStream* input) { + + this->input=input; + this->mpegVideoStream=new MpegVideoStream(input); + + startGOP=new GOP(); + endGOP=new GOP(); + lengthGOP=new GOP(); + mpegVideoHeader=new MpegVideoHeader(); + + + lHasStart=false; + lHasEnd=false; + lHasStream=false; + lHasResync=false; + lHasSystemStream=false; + lHasRawStream=false; + lSysLayer=false; + + mpegSystemStream=new MpegSystemStream(input); + mpegSystemHeader=new MpegSystemHeader(); + + + lCanSeek=input->seek(0); + if (lCanSeek == false) { + cout << "mpegVideoLength: stream does not support seek"<<endl; + } + realLength=input->getByteLength(); + upperEnd=realLength; + if (realLength > 1024*1024*600) { + upperEnd=1024*1024*600; + } +} + + +MpegVideoLength::~MpegVideoLength() { + delete startGOP; + delete endGOP; + delete lengthGOP; + delete mpegVideoStream; + delete mpegVideoHeader; + delete mpegSystemHeader; + delete mpegSystemStream; +} + + +/** + This long and ugly functions initialize a reader from + where to get the time informations. + All these switches deal with the problem, that we really should + have never a while loop, because this makes the decoder + thread unresponsive and can lead to deadlocks. +*/ + +int MpegVideoLength::firstInitialize() { + + // no seek means no length detection + if (lCanSeek==false) { + // no detection possible, initialized ready + input->seek(0); + return true; + } + // do we have already a reader from where to get time? + if (lHasStream == false) { + // still init system ? + if (lHasSystemStream == false) { + if (mpegSystemStream->firstInitialize(mpegSystemHeader) == true) { + lHasSystemStream=true; + + // if non system, reset everything and work on raw stream + if (mpegSystemHeader->getLayer() == _PACKET_SYSLAYER) { + lSysLayer=true; + } + if (lSysLayer == false) { + input->seek(0); + } + } + return false; + } + // if working on syslayer level we dont need the raw stream + // set it to true + if (lSysLayer == true) { + lHasRawStream=true; + } + if (lHasRawStream == false) { + if (mpegVideoStream->firstInitialize(mpegVideoHeader) == true) { + lHasRawStream=true; + } + return false; + } + lHasStream=true; + return false; + } + if (lHasStart == false) { + if (seekToStart() == true) { + lHasStart=true; + } + + // clear and jump near the end + mpegVideoStream->clear(); + int success=input->seek(upperEnd-SEARCH_SIZE); + if (success == false) { + cout << "mpegVideoStreamStream does not support seek"<<endl; + // we can't find an upper end, thus we are ready + input->seek(0); + return true; + } + return false; + } + if (lHasResync==false) { + if (lSysLayer) { + if (mpegSystemStream->nextPacket(mpegSystemHeader) == false) { + return false; + } + } else { + if (mpegVideoStream->nextGOP()==false) { + return false; + } + } + lHasResync=true; + return false; + } + if (lHasEnd == false) { + if (seekToEnd() == true) { + lHasEnd=true; + if (endGOP->substract(startGOP,lengthGOP) == false) { + cout << "substract error in final length detection"<<endl; + if (startGOP->substract(endGOP,lengthGOP) == true) { + cout << "this stream counts the time backwards"<<endl; + } else { + cout << "couldnt determine stream length"<<endl; + GOP dummy; + dummy.copyTo(lengthGOP); + } + } + // ok now we have the length but we must calculate + // the length of the whole stream + // we do not jump ofer 600 MB because this makes problems + // on some cdrom. + // here we calculate the real length if upperEnd != realEnd + int hour=lengthGOP->getHour(); + int minute=lengthGOP->getMinutes(); + long seconds=lengthGOP->getSeconds(); + seconds=seconds+minute*60+hour*60*60; + if (upperEnd > 1) { + if (realLength > upperEnd) { + float ratio=realLength/upperEnd; + float realSeconds=seconds*ratio; + hour=(int)(realSeconds/(float)(60*60)); + realSeconds=realSeconds-hour*60*60; + minute=(int)(realSeconds/60.0); + realSeconds=realSeconds-minute*60; + seconds=(int)realSeconds; + lengthGOP->setHour(hour); + lengthGOP->setMinute(minute); + lengthGOP->setSecond(seconds); + } + } + } + } + input->seek(0); + return true; +} + + +long MpegVideoLength::getLength() { + long back=0; + back=lengthGOP->getHour()*60*60; + back+=lengthGOP->getMinutes()*60; + back+=lengthGOP->getSeconds(); + + // length in second + return back; +} + + +long MpegVideoLength::getSeekPos(int seconds) { + // calculate from seconds to predicted position in stream + long back=0; + double ratio; + + ratio=(double)realLength*(double)seconds; + ratio=ratio/((double)getLength()+1.0); + back=(long)ratio; + + return back; + +} + + +// We try to search the first SEARCH_SIZE KB for a valid picture start. +int MpegVideoLength::seekToStart() { + int success; + + /** + If we are a system Layer we calculate the startGOP + by the system Packets + */ + if (lSysLayer == true) { + success=parseToPTS(startGOP); + } else { + + mpegVideoStream->hasBytes(100); + + success=parseToGOP(startGOP); + } + + if (success == false) { + cout << "picture startcode not found [START]"<<endl; + + } + // we return always true + // if we really have the start, fine, otherwithe we can + // nothing do about it, nor yet, nor in future, thus + // we have even success (in terms of failure) + return true; +} + + + +int MpegVideoLength::seekToEnd() { + int success; + + if (lSysLayer == true) { + success=parseToPTS(endGOP); + } else { + mpegVideoStream->hasBytes(100); + success=parseToGOP(endGOP); + } + if (success == false) { + cout << "picture endcode not found [END]"<<endl; + } + + return true; +} + + +int MpegVideoLength::parseToGOP(GOP* dest) { + int success; + // we try ten attempts + // and the diff between each must be (less) than one second + + int successCnt=0; + + + long maxArea=0; + long area=0; + + GOP lastGOP; + GOP currentGOP; + GOP diffGOP; + + + while(successCnt < 4) { + if (mpegVideoStream->eof()) { + return false; + } + if (input->eof() == true) { + cout << "abort"<<endl; + return false; + } + if (maxArea > SEARCH_SIZE) { + return false; + } + + + success=seekValue(GOP_START_CODE,area); + maxArea+=area; + if (success == false) { + continue; + } + + + + currentGOP.copyTo(&lastGOP); + // currentGOP.print("current"); + successCnt++; + currentGOP.processGOP(mpegVideoStream); + if (currentGOP.substract(&lastGOP,&diffGOP) == false) { + cout << "substract error"<<endl; + } + /* + currentGOP.print("current"); + lastGOP.print("last"); + diffGOP.print("diff"); + */ + if (diffGOP.getHour() != 0) { + successCnt=0; + continue; + } + if (diffGOP.getMinutes() != 0) { + successCnt=0; + continue; + } + if (diffGOP.getSeconds() > 8) { + successCnt=0; + continue; + } + + } + currentGOP.copyTo(dest); + return true; +} + + + + + + +int MpegVideoLength::seekValue(unsigned int ,long& valueSeeked) { + long start=input->getBytePosition(); + long cnt=0; + long end=start+SEEKWINDOW; + long area=0; + + // if we have not enough space we skip + // because of the mpeg frame garbage "mb_stuffing,etc..." + + if (end > upperEnd-SEEKWINDOW){ + valueSeeked=SEEKWINDOW; + return false; + } + area=end-start; + while(mpegVideoStream->nextGOP() == false) { + if (mpegVideoStream->eof()) { + return false; + } + cnt++; + if (cnt >= area) { + valueSeeked=cnt; + cout << "nothing found"<<area<<endl; + return false; + } + } + return true; +} + + + +int MpegVideoLength::parseToPTS(GOP* dest) { + + // we try ten attempts + // and the diff between each must be (less) than one second + + int successCnt=0; + + long startArea=input->getBytePosition(); + long maxArea=0; + + + double lastPTS=0; + double currentPTS=0; + double diffPTS=0; + + + while(successCnt < 4) { + if (input->eof() == true) { + cout << "abort"<<endl; + return false; + } + maxArea=input->getBytePosition()-startArea; + if (maxArea > SEARCH_SIZE) { + return false; + } + if (mpegSystemStream->nextPacket(mpegSystemHeader) == false) { + continue; + } + if (mpegSystemHeader->getPTSFlag()==false) { + continue; + } + // we have a packet + lastPTS=currentPTS; + currentPTS=mpegSystemHeader->getPTSTimeStamp(); + diffPTS=currentPTS-lastPTS; + successCnt++; + + if (diffPTS > 1.0) { + successCnt=0; + continue; + } + } + + // now put it into the gop structure + // this is the interface for the time. + // a little hack here and there.... + unsigned int hour=((long)currentPTS) / 3600; + currentPTS=currentPTS-hour*3600; + unsigned int minute=((long)currentPTS) / 60; + currentPTS=currentPTS-minute*60; + unsigned int seconds=((long)currentPTS); + + + dest->setHour(hour); + dest->setMinute(minute); + dest->setSecond(seconds); + return true; +} + + diff --git a/mpeglib/lib/mpegplay/mpegVideoLength.h b/mpeglib/lib/mpegplay/mpegVideoLength.h new file mode 100644 index 00000000..79bece6a --- /dev/null +++ b/mpeglib/lib/mpegplay/mpegVideoLength.h @@ -0,0 +1,93 @@ +/* + 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 __MPEGVIDEOLENGTH_H +#define __MPEGVIDEOLENGTH_H + +#include "../input/inputPlugin.h" + + + + + + +/** + This class calculates the length (in seconds) of an mpeg stream. + I do not know how to make it right, my approach + seeks at the beginning of the stream for the timecode in + the picture gop then jumps near the end and does the same. + then it substracts the values. + It has some limitations, it does not seek higher than 600 MB, + because it seems the kernel has some problems with this. + (It resets the scsi system, and sometimes hang/crash) + Thus it only seek near 600 and assumes linear relation + for the rest. (Means: it calculates the length of the rest + with the sec/mb value calculates from the 600 mb + should be exact enough. +*/ + +class MpegVideoStream; +class MpegVideoHeader; +class MpegSystemStream; +class MpegSystemHeader; +class GOP; + +class MpegVideoLength { + + // these are used fo non system streams + MpegVideoHeader* mpegVideoHeader; + MpegVideoStream* mpegVideoStream; + + // these for system streams + MpegSystemHeader* mpegSystemHeader; + MpegSystemStream* mpegSystemStream; + + + InputStream* input; + GOP* startGOP; + GOP* endGOP; + GOP* lengthGOP; + + + int lHasStart; + int lHasEnd; + int lCanSeek; + int lHasStream; + int lHasSystemStream; + int lHasRawStream; + int lHasResync; + int lSysLayer; + long upperEnd; + long realLength; + + public: + MpegVideoLength(InputStream* input); + ~MpegVideoLength(); + + int firstInitialize(); + + long getLength(); + long getSeekPos(int seconds); + + + private: + int seekToStart(); + int seekToEnd(); + int seekValue(unsigned int code,long& endPos); + int parseToGOP(GOP* gop); + int parseToPTS(GOP* gop); + + +}; +#endif + diff --git a/mpeglib/lib/mpegplay/mpegVideoStream.cpp b/mpeglib/lib/mpegplay/mpegVideoStream.cpp new file mode 100644 index 00000000..5e16b116 --- /dev/null +++ b/mpeglib/lib/mpegplay/mpegVideoStream.cpp @@ -0,0 +1,224 @@ +/* + a mpegVideoStream buffer + 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 "mpegVideoStream.h" + +#include <iostream> + +using namespace std; + +MpegVideoStream::MpegVideoStream(InputStream* input) { + + + this->input=input; + lHasStream=false; + + mpegSystemStream=new MpegSystemStream(input); + mpegSystemHeader=new MpegSystemHeader(); + mpegVideoBitWindow= new MpegVideoBitWindow(); + + +} + + +MpegVideoStream::~MpegVideoStream() { + delete mpegSystemStream; + delete mpegSystemHeader; + delete mpegVideoBitWindow; +} + + + + +int MpegVideoStream::firstInitialize(MpegVideoHeader* mpegHeader) { + if (lHasStream == false) { + if (mpegSystemStream->firstInitialize(mpegSystemHeader)==false) { + return false; + } + fill_videoBuffer(mpegSystemHeader); + lHasStream=true; + } + // now find SEQ_START_CODE + hasBytes(4); + mpegVideoBitWindow->flushByteOffset(); + + if (mpegSystemHeader->getLayer() == _PACKET_SYSLAYER) { + unsigned int startCode=showBits(32); + if (startCode != _SEQ_START_CODE) { + flushBits(8); + return false; + } + flushBits(32); + } + if (mpegHeader->parseSeq(this)==false) { + return false; + } + return true; +} + + +int MpegVideoStream::isStartCode(unsigned int data) { + + switch(data) { + case SEQ_END_CODE: + case SEQ_START_CODE: + case GOP_START_CODE: + case PICTURE_START_CODE: + case SLICE_MIN_START_CODE: + case SLICE_MAX_START_CODE: + case EXT_START_CODE: + case USER_START_CODE: + case SEQUENCE_ERROR_CODE: + case SYSTEM_HEADER_START_CODE: + case ISO_11172_END_CODE: + case EOF: + return true; + } + if ((SLICE_MIN_START_CODE < data) && (data < SLICE_MAX_START_CODE)) { + return true; + } + return false; +} + +int MpegVideoStream::next_start_code() { + flushByteOffset(); + + unsigned int data; + data=showBits(32); + + + while(eof()==false) { + data=showBits(32); + if (isStartCode(data)) { + return true; + } + flushBits(8); + } + return true; +} + + +int MpegVideoStream::nextGOP() { + + mpegVideoBitWindow->flushByteOffset(); + unsigned int data=showBits(32); + if (data != GOP_START_CODE) { + flushBits(8); + return false; + } + return true; +} + + +int MpegVideoStream::nextPIC() { + mpegVideoBitWindow->flushByteOffset(); + unsigned int data=showBits(32); + if ( (data != PICTURE_START_CODE) && + (data != GOP_START_CODE) && + (data != SEQ_START_CODE) ) { + flushBits(8); + return false; + } + return true; +} + + + + + +int MpegVideoStream::hasBytes(int byteCnt) { + if (mpegVideoBitWindow->getLength() < byteCnt) { + get_more_video_data(); + if (mpegVideoBitWindow->getLength() < byteCnt) { + return hasBytes(byteCnt); + } + } + return true; +} + + + + +int MpegVideoStream::eof() { + if (input->eof()) { + return true; + } + return false; +} + + +int MpegVideoStream::getByteDirect() { + unsigned char byte; + if (input->read((char*)&byte,1) != 1) { + return -1; + } + return (int)byte; +} + + +int MpegVideoStream::get_more_video_data() { + + + while(1) { + if (mpegSystemStream->nextPacket(mpegSystemHeader)==false) { + continue; + } + if (mpegSystemStream->eof() == true) { + printf ("\n"); + mpegVideoBitWindow->fillWithIsoEndCode(1024); + cout <<"Unexpected read error."<<endl; + return false; + } + if (mpegSystemHeader->getPacketID() == _PAKET_ID_VIDEO) { + break; + } + + } + + + fill_videoBuffer(mpegSystemHeader); + return true; +} + + +void MpegVideoStream::fill_videoBuffer(MpegSystemHeader* mpegSystemHeader) { + int bytes; + + bytes=mpegSystemHeader->getPacketLen(); + unsigned char* packetBuffer= new unsigned char[bytes]; + int didRead; + didRead=input->read((char*)packetBuffer,bytes); + if (bytes==0) { + mpegVideoBitWindow->fillWithIsoEndCode(1024); + return ; + } + + mpegVideoBitWindow->appendToBuffer(packetBuffer,didRead); + if (input->eof()) { + mpegVideoBitWindow->fillWithIsoEndCode(bytes-didRead); + } + + delete packetBuffer; +} + + +TimeStamp* MpegVideoStream::getCurrentTimeStamp() { + long pos=input->getBytePosition(); + int transfered=4*mpegVideoBitWindow->getLength(); + pos=pos-transfered; + + TimeStamp* timeStamp=input->getTimeStamp(pos); + + return timeStamp; +} + diff --git a/mpeglib/lib/mpegplay/mpegVideoStream.h b/mpeglib/lib/mpegplay/mpegVideoStream.h new file mode 100644 index 00000000..86b80553 --- /dev/null +++ b/mpeglib/lib/mpegplay/mpegVideoStream.h @@ -0,0 +1,110 @@ +/* + a buffer + 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 __MPEGVIDEOSTREAM_H +#define __MPEGVIDEOSTREAM_H + +#include "startCodes.h" +#include "mpegVideoHeader.h" +#include "mpegSystemStream.h" +#include "mpegVideoBitWindow.h" + +#define _BYTE_TEST 1024 + +/** + A really ugly class. Most of the methods have names + which does not make it clear for what they are useful. + (Don't touch a running system :-) + + We wrap the inputStream and offer functions for getting + bits, appending to the internal buffer, flushing, syncing + all this stuff. + + +*/ + +class MpegVideoStream { + + int size; + InputStream* input; + MpegSystemStream* mpegSystemStream; + MpegSystemHeader* mpegSystemHeader; + MpegVideoBitWindow* mpegVideoBitWindow; + + int lHasStream; + + public: + MpegVideoStream(InputStream* input); + ~MpegVideoStream(); + + // returns true if init successful + int firstInitialize(MpegVideoHeader* mpegHeader); + int nextGOP(); + int nextPIC(); + int next_start_code(); + + int hasBytes(int bytes); + int eof(); + + inline void clear() { + mpegVideoBitWindow->clear(); + } + + inline void flushBits(int bits) { + hasBytes(_BYTE_TEST); + mpegVideoBitWindow->flushBitsDirect(bits); + } + + inline unsigned int showBits(int bits) { + hasBytes(_BYTE_TEST); + return mpegVideoBitWindow->showBits(bits); + } + + inline unsigned int showBits32() { + return mpegVideoBitWindow->showBits32(); + } + + inline unsigned int showBits16() { + return mpegVideoBitWindow->showBits(16); + } + + inline void flushBitsDirect(unsigned int bits) { + mpegVideoBitWindow->flushBitsDirect(bits); + } + + unsigned int getBits(int bits) { + hasBytes(_BYTE_TEST); + return mpegVideoBitWindow->getBits(bits); + } + + inline void flushByteOffset() { + mpegVideoBitWindow->flushByteOffset(); + } + + TimeStamp* getCurrentTimeStamp(); + + private: + int getByteDirect(); + int get_more_video_data(); + void fill_videoBuffer(MpegSystemHeader* mpegSystemHeader); + int isStartCode(unsigned int data); + + +}; +#endif + + + diff --git a/mpeglib/lib/mpegplay/pesSystemStream.cpp b/mpeglib/lib/mpegplay/pesSystemStream.cpp new file mode 100644 index 00000000..10787f21 --- /dev/null +++ b/mpeglib/lib/mpegplay/pesSystemStream.cpp @@ -0,0 +1,498 @@ +/* + demux pes mpeg stream + Copyright (C) 2001 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 "pesSystemStream.h" + +#include <iostream> + +using namespace std; + +PESSystemStream::PESSystemStream(InputStream* input) { + this->input=input; +} + + +PESSystemStream::~PESSystemStream() { +} + + + +int PESSystemStream::getByteDirect() { + unsigned char byte; + if (input->read((char*)&byte,1) != 1) { + return -1; + } + bytes_read++; + return (int)byte; +} + +int PESSystemStream::read(char* pointer,int bytes) { + if (input->read(pointer,bytes) != bytes) { + return false; + } + bytes_read+=bytes; + + return true; +} + +int PESSystemStream::processStartCode(unsigned int startCode, + MpegSystemHeader* mpegHeader) { + int lok=true; + bytes_read=4; // startcode + mpegHeader->setPacketLen(0); + mpegHeader->setPacketID(_PAKET_ID_NUKE); + + // handle default + bytes_read=processPacket(startCode,mpegHeader); + return bytes_read; +} + + +/* Returns: + 0 - no error, but not video packet we want + -1 - error + >0 - length of packet +*/ +int PESSystemStream::processPacket(unsigned int startCode, + MpegSystemHeader* mpegHeader) { + + int ioBytes; + unsigned short packetLength; + int packetDataLength; + + /* Leftovers from previous video packets */ + + int packetID=startCode & 0xff; + mpegHeader->setPacketID(packetID); + int lPacket=startCode & _PACKET_START_CODE_MASK &_PACKET_START_CODE_PREFIX; + if ((lPacket == false) || (packetID < 0xbc)) { + //printf("unknown startcode,packet or packetID:%8x\n",startCode); + return false; + } + + if (packetID == _NOT_PACKET_ID) { + cout << "(vid_stream->mpegVideoStream)->makeEnd()"<<endl; + } else if (packetID==_KILL_BUFFER) { + printf("packetID==_KILL_BUFFER\n"); + } + + if (read((char*)&packetLength, 2) == false) return false; + packetLength = htons(packetLength); + + mpegHeader->setPTSFlag(false); + mpegHeader->setPacketID(packetID); + mpegHeader->setPESPacketLen(packetLength); + switch (packetID>>4) { + case _PAKET_ID_AUDIO_1>>4: + case _PAKET_ID_AUDIO_2>>4: + case _PAKET_ID_VIDEO>>4: + break; + default: + switch(packetID) { + case _PRIVATE_STREAM_1_ID: + break; + default: + switch (packetID) { + case _PRIVATE_STREAM_2_ID: + case _PADDING_STREAM_ID: + case _RESERVED_STREAM_ID: + case _ECM_STREAM_ID: + case _EMM_STREAM_ID: + case _PROGRAM_STREAM_DIRECTORY_ID: + case _DSMCC_STREAM_ID: + case _ITUTRECH222TYPEE_STREAM_ID: + return bytes_read; + } + printf("\nUnknown packet type. (%x) at %ld\n", + packetID,input->getBytePosition()); + return bytes_read; + } + } + // this is only processed if audio or video found + + if (mpegHeader->getMPEG2()==false) { + packetDataLength = packetLength-processPacketHeader(mpegHeader); + } else { + int len=processMPEG2PacketHeader(mpegHeader); + + if (len < 0) { + return false; + } + packetDataLength = packetLength-len; + + // now check in private stream for AC3 + if ( packetID == _PRIVATE_STREAM_1_ID ) { + packetDataLength = packetDataLength-processPrivateHeader(mpegHeader); + } + } + + if (packetDataLength <= 0) { + if (mpegHeader->hasPSHeader()) return false; + // -> buggy TS stream + packetDataLength=0; + } + mpegHeader->setPESPacketLen(packetDataLength); + + return bytes_read; + +} + + +int PESSystemStream::processPrivateHeader(MpegSystemHeader* mpegHeader) { + char nukeBuffer[30]; + int pos=0; + int one=getByteDirect(); + pos++; + mpegHeader->setSubStreamID(one); + switch(one>>4) { + case _SUBSTREAM_AC3_ID>>4: + if (read(nukeBuffer,3) == false) return false; + mpegHeader->addAvailableLayer(one); + cout << "addAvailableLayer:"<<one<<endl; + pos+=3; + break; + case _SUBSTREAM_LPCM_ID>>4: + if (read(nukeBuffer,6) == false) return false; + pos+=6; + break; + case _SUBSTREAM_SUBPIC_ID>>4: + if (read(nukeBuffer,3) == false) return false; + pos+=3; + break; + default: + printf("unknown sub id :%8x\n",one); + } + return pos; + +} + + +int PESSystemStream::processMPEG2PacketHeader(MpegSystemHeader* mpegHeader){ + + int stdCnt=0; + int pos=0; + + // 1. Byte + /* + FROM FLASK: + int getbits(2); + encrypted = getbits(2); // PES_scrambling_control + getbits(4); + //LIVID + u_char original_or_copy : 1; + u_char copyright : 1; + u_char data_alignment_indicator : 1; + u_char pes_priority : 1; + u_char pes_scrambling_control : 2; + u_char start_code_prefix : 2; // 0x02 + + */ + int first=getByteDirect(); + stdCnt++; + mpegHeader->setOriginalOrCopy(first&(128)>>7); + mpegHeader->setCopyRight(first&(64)>>6); + mpegHeader->setDataAlignmentIndicator(first&(32)>>5); + mpegHeader->setPesPriority(first&(16)>>4); + mpegHeader->setEncrypted((first&(8+4))>>2); + mpegHeader->setStartCodePrefix(first&(1+2)); + + + // 2. Byte + /* + PTS_DTS_flags = getbits(2); + ESCR_flag = get1bit(); + ES_rate_flag = get1bit(); + DSM_trick_mode_flag = get1bit(); + additional_copy_info_flag = get1bit(); + PES_CRC_flag = get1bit(); + PES_extension_flag = get1bit(); + */ + int second=getByteDirect(); + stdCnt++; + + mpegHeader->setPTSDTSFlag((second&(128+64))>>6); + mpegHeader->setESCRFlag((second&(32))>>5); + mpegHeader->setES_RATE_Flag((second%(16))>>4); + mpegHeader->setDMSTRICKFLAG((second&(8))>>3); + mpegHeader->setADDITIONAL_COPY_FLAG((second&(4))>>2); + mpegHeader->setPES_CRC_FLAG((second&(2))>>1); + mpegHeader->setPES_EXT_FLAG(second&(1)); + + + // 3. Byte + /* + PES_header_data_length = getbits(8); + */ + int third=getByteDirect(); + stdCnt++; + mpegHeader->setPES_HEADER_DATA_LENGTH(third); + + + // + // PARSING MPEG 2 HEADER FLAGS [START] + // + unsigned char nukeBuffer[300]; + + int PTS_DTS_flags=mpegHeader->getPTSDTSFlag(); + if (PTS_DTS_flags == 0) { + mpegHeader->setPTSFlag(false); + } else { + mpegHeader->setPTSFlag(true); + } + + if (PTS_DTS_flags > 0x1) { + if (read((char*)nukeBuffer,5) == false) return false; + double pts=GET_MPEG2_PTS(nukeBuffer); + pts=(pts*300.0)/(double)MPEG2_CLK_REF; + mpegHeader->setPTSTimeStamp(pts); + pos+=5; + } + if (PTS_DTS_flags > 0x2) { + if (read((char*)nukeBuffer,5) == false) return false; + double dts=GET_MPEG2_PTS(nukeBuffer); + mpegHeader->setDTSTimeStamp((dts*300.0)/(double)MPEG2_CLK_REF); + pos+=5; + } + + int ESCRFlag=mpegHeader->getESCRFlag(); + if (ESCRFlag == 1){ + cout << "ESCRFlag == 1"<<endl; + if (read((char*)nukeBuffer,6) == false) return false; + pos+=6; + } + + int ES_rate_flag=mpegHeader->getES_RATE_Flag(); + if (ES_rate_flag == 1){ + cout << "ES_rate_flag == 1"<<endl; + if (read((char*)nukeBuffer,3) == false) return false; + pos+=3; + } + + int DSM_trick_mode_flag=mpegHeader->getDMSTRICKFLAG(); + if (DSM_trick_mode_flag == 1){ + cout << "DSM_trick_mode_flag == 1"<<endl; + if (read((char*)nukeBuffer,1) == false) return false; + pos++; + } + + int additional_copy_info_flag=mpegHeader->getADDITIONAL_COPY_FLAG(); + if (additional_copy_info_flag == 1) { + cout << "additional_copy_info_flag == 1"<<endl; + if (read((char*)nukeBuffer,1) == false) return false; + pos++; + } + + int PES_CRC_flag=mpegHeader->getPES_CRC_FLAG(); + if (PES_CRC_flag == 1) { + cout << "PES_CRC_flag == 1"<<endl; + if (read((char*)nukeBuffer,2) == false) return false; + pos+=2; + } + + // + // PES Extension [START] + // + + int PES_extension_flag=mpegHeader->getPES_EXT_FLAG(); + if (PES_extension_flag == 1) { + /* + FLASK: + PES_private_data_flag = get1bit(); + pack_header_field_flag = get1bit(); + program_packet_sequence_counter_flag = get1bit(); + PSTD_buffer_flag = get1bit(); + getbits(3); + PES_extension_flag_2 = get1bit(); + */ + int extensionByte=getByteDirect(); + + pos++; + mpegHeader->setPrivateDataFlag((extensionByte&(128))>>7); + mpegHeader->setPackHeaderFieldFlag((extensionByte&(64))>>6); + mpegHeader->setSequenceCounterFlag((extensionByte&(32))>>5); + mpegHeader->setSTDBufferFlag((extensionByte&(16))>>4); + mpegHeader->setPES_EXT_FLAG_2(extensionByte&(1)); + + int PES_private_data_flag=mpegHeader->getPrivateDataFlag(); + if (PES_private_data_flag == 1) { + if (read((char*)nukeBuffer,128) == false) return false; + pos+=128; + } + + int pack_header_field_flag=mpegHeader->getPackHeaderFieldFlag(); + if (pack_header_field_flag == 1) { + printf("pack header field flag value not allowed in program streams\n"); + return false; + } + + int sequence_counter_flag=mpegHeader->getSequenceCounterFlag(); + if (sequence_counter_flag==1) { + cout<<"sequence_counter_flag ==1"<<endl; + if (read((char*)nukeBuffer,2) == false) return false; + pos+=2; + } + + int PSTD_buffer_flag=mpegHeader->getSTDBufferFlag(); + if (PSTD_buffer_flag==1) { + if (read((char*)nukeBuffer,2) == false) return false; + pos+=2; + } + + int PES_extension_flag_2=mpegHeader->getPES_EXT_FLAG_2(); + if (PES_extension_flag_2 == 1) { + int extension2_byte=getByteDirect(); + pos++; + mpegHeader->setPES_EXT_FIELD_LENGTH(extension2_byte&(254)); + + + int PES_field_length=mpegHeader->getPES_EXT_FIELD_LENGTH(); + int j; + for (j=0;j<PES_field_length ; j++) { + cout << "PES_field_length (nuke)"<<endl; + getByteDirect(); + pos++; + } + } + } + // + // PES Extension [END] + // + + // now nuke remaining bytes from PES DATA Length + int PES_HEADER_DATA_LENGTH=mpegHeader->getPES_HEADER_DATA_LENGTH(); + int tmp=PES_HEADER_DATA_LENGTH-pos; + if (tmp>0) { + if (read((char*)nukeBuffer,tmp) == false) return false; + pos+=tmp; + } + + + + + + // + // PARSING MPEG 2 HEADER FLAGS [START] + // + + int parsed=stdCnt+pos; + return parsed; + +} + + +int PESSystemStream::processPacketHeader(MpegSystemHeader* mpegHeader) { + unsigned char nextByte; + int pos; + int val; + unsigned char scratch[10]; + + + nextByte=getByteDirect(); + + mpegHeader->setPTSFlag(false); + + pos = 1; + while (nextByte & 0x80) { + ++pos; + val=getByteDirect(); + if (val == -1) return false; + scratch[0]=val; + + nextByte=scratch[0]; + } + if ((nextByte >> 6) == 0x01) { + pos += 2; + scratch[1]=getByteDirect(); + scratch[2]=getByteDirect(); + nextByte=scratch[2]; + } + if ((nextByte >> 4) == 0x02) { + scratch[0] = nextByte; + if (read((char*)&scratch[1],4) == false) return false; + /* presentation time stamps */ + unsigned char hiBit; + unsigned long low4Bytes; + double ptsTimeStamp; + double dtsTimeStamp=0.0; + readTimeStamp((unsigned char*)scratch,&hiBit,&low4Bytes); + makeClockTime(hiBit,low4Bytes,&ptsTimeStamp); + mpegHeader->setPTSFlag(true); + mpegHeader->setPTSTimeStamp(ptsTimeStamp); + mpegHeader->setDTSTimeStamp(dtsTimeStamp); + + pos += 4; + } + else if ((nextByte >> 4) == 0x03) { + scratch[0] = nextByte; + if (read((char*)&scratch[1],9) == false) return false; + /* presentation and decoding time stamps */ + unsigned char hiBit; + unsigned long low4Bytes; + double ptsTimeStamp; + double dtsTimeStamp; + readTimeStamp((unsigned char*)scratch,&hiBit,&low4Bytes); + makeClockTime(hiBit,low4Bytes,&ptsTimeStamp); + + readTimeStamp((unsigned char*)&(scratch[5]),&hiBit,&low4Bytes); + makeClockTime(hiBit,low4Bytes,&dtsTimeStamp); + mpegHeader->setPTSFlag(true); + mpegHeader->setPTSTimeStamp(ptsTimeStamp); + mpegHeader->setDTSTimeStamp(dtsTimeStamp); + + pos += 9; + } + return pos; +} + + + +void PESSystemStream::readTimeStamp(unsigned char* inputBuffer, + unsigned char* hiBit, + unsigned long* low4Bytes) { + *hiBit = ((unsigned long)inputBuffer[0] >> 3) & 0x01; + *low4Bytes = (((unsigned long)inputBuffer[0] >> 1) & 0x03) << 30; + *low4Bytes |= (unsigned long)inputBuffer[1] << 22; + *low4Bytes |= ((unsigned long)inputBuffer[2] >> 1) << 15; + *low4Bytes |= (unsigned long)inputBuffer[3] << 7; + *low4Bytes |= ((unsigned long)inputBuffer[4]) >> 1; +} + + +void PESSystemStream::readSTD(unsigned char* inputBuffer, + MpegSystemHeader* mpegHeader) { + int stdBufferScale; + unsigned long stdBufferSize; + stdBufferScale = ((int)(inputBuffer[0] & 0x20) >> 5); + stdBufferSize = ((unsigned long)inputBuffer[0] & 0x1f) << 8; + stdBufferSize |= (unsigned long)inputBuffer[1]; + mpegHeader->setStdBufferScale(stdBufferScale); + mpegHeader->setStdBufferSize(stdBufferSize); +} + + +int PESSystemStream::makeClockTime(unsigned char hiBit, + unsigned long low4Bytes, + double * clockTime) { + if (hiBit != 0 && hiBit != 1) { + *clockTime = 0.0; + return 1; + } + *clockTime = (double)hiBit*FLOAT_0x10000*FLOAT_0x10000 + (double)low4Bytes; + *clockTime /= (double)_STD_SYSTEM_CLOCK_FREQ; + return 0; +} + + + + diff --git a/mpeglib/lib/mpegplay/pesSystemStream.h b/mpeglib/lib/mpegplay/pesSystemStream.h new file mode 100644 index 00000000..f7b650c5 --- /dev/null +++ b/mpeglib/lib/mpegplay/pesSystemStream.h @@ -0,0 +1,57 @@ +/* + demux pes mpeg stream + Copyright (C) 2001 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 __PESSYSTEMSTREAM_H +#define __PESSYSTEMSTREAM_H + + +#include <stdlib.h> +#include "../input/inputPlugin.h" +#include "mpegSystemHeader.h" + + +class PESSystemStream { + + + InputStream* input; + + int bytes_read; + + public: + PESSystemStream(InputStream* input); + ~PESSystemStream(); + + // called when we found a valid ts startcode + // return number of bytes read from input and zero on error + int processStartCode(unsigned int startCode,MpegSystemHeader* mpegHeader); + + private: + int getByteDirect(); + int read(char* prt,int bytes); + int processPacket(unsigned int startCode,MpegSystemHeader* mpegHeader); + int processPacketHeader(MpegSystemHeader* mpegHeader); + int processMPEG2PacketHeader(MpegSystemHeader* mpegHeader); + int processPrivateHeader(MpegSystemHeader* mpegHeader); + + int readStartCode(unsigned int startCode,MpegSystemHeader* mpegHeader); + + void readSTD(unsigned char* inputBuffer,MpegSystemHeader* mpegHeader); + void readTimeStamp(unsigned char* inputBuffer,unsigned char* hiBit, + unsigned long* low4Bytes); + + int makeClockTime(unsigned char hiBit, unsigned long low4Bytes, + double * clockTime); + + +}; +#endif diff --git a/mpeglib/lib/mpegplay/picture.cpp b/mpeglib/lib/mpegplay/picture.cpp new file mode 100644 index 00000000..6d8c1efe --- /dev/null +++ b/mpeglib/lib/mpegplay/picture.cpp @@ -0,0 +1,149 @@ +/* + mpeg video picture + 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 "picture.h" + + +Picture::Picture() { + + /* Initialize pointers to extension and user data. */ + extraBit=0; + startOfPicStamp=new TimeStamp(); + extension=new MpegExtension(); +} + + + +Picture::~Picture() { + delete startOfPicStamp; + delete extension; +} + + +/* + *-------------------------------------------------------------- + * + * ParsePicture -- + * + * Parses picture header. Marks picture to be presented + * at particular time given a time stamp. + * + * Results: + * Values from picture header put into video stream structure. + * + * Side effects: + * Bit stream irreversibly parsed. + * + *-------------------------------------------------------------- + */ +int Picture::processPicture(MpegVideoStream* mpegVideoStream) { + TimeStamp* stamp; + + /* Flush header start code. */ + mpegVideoStream->flushBits(32); + + /* Parse off temporal reference. */ + temp_ref=mpegVideoStream->getBits(10); + + /* Parse of picture type. */ + code_type=mpegVideoStream->getBits(3); + + + // get timestamp from stamp queue + stamp=mpegVideoStream->getCurrentTimeStamp(); + + stamp->copyTo(startOfPicStamp); + // now invalidate the PTSFlag + stamp->setPTSFlag(false); + + + /* Parse off vbv buffer delay value. */ + vbv_delay=mpegVideoStream->getBits(16); + + + /* If P or B type frame... */ + + if ((code_type == P_TYPE) || (code_type == B_TYPE)) { + + /* Parse off forward vector full pixel flag. sets it to true/false*/ + full_pel_forw_vector=mpegVideoStream->getBits(1); + + + /* Parse of forw_r_code. */ + /* Decode forw_r_code into forw_r_size and forw_f. */ + forw_r_size=mpegVideoStream->getBits(3); + forw_r_size--; + + + forw_f = (1 << forw_r_size); + } + /* If B type frame... */ + + if (code_type == B_TYPE) { + + /* Parse off back vector full pixel flag. */ + full_pel_back_vector=mpegVideoStream->getBits(1); + + + /* Parse off back_r_code. */ + /* Decode back_r_code into back_r_size and back_f. */ + back_r_size=mpegVideoStream->getBits(3); + back_r_size--; + + + back_f = (1 << back_r_size); + } + /* Get extra bit picture info. */ + + + /* + extraBit=mpegVideoStream->getBits(1); + if (extraBit) { + cout << "extraBit"<<endl; + exit(0); + extension->processExtBuffer(mpegVideoStream); + } + */ + extension->processExtra_bit_info(mpegVideoStream); + extension->processExtensionData(mpegVideoStream); + + + + + + return true; +} + +int Picture::processPictureCodingExtension(MpegVideoStream* ) { + return true; +} + +unsigned int Picture::geth_back_r(MpegVideoStream* mpegVideoStream) { + return mpegVideoStream->getBits(back_r_size); +} + + +unsigned int Picture::getv_back_r(MpegVideoStream* mpegVideoStream) { + return mpegVideoStream->getBits(back_r_size); +} + + +unsigned int Picture::geth_forw_r(MpegVideoStream* mpegVideoStream) { + return mpegVideoStream->getBits(forw_r_size); +} + + +unsigned int Picture::getv_forw_r(MpegVideoStream* mpegVideoStream) { + return mpegVideoStream->getBits(forw_r_size); +} + diff --git a/mpeglib/lib/mpegplay/picture.h b/mpeglib/lib/mpegplay/picture.h new file mode 100644 index 00000000..7be35ab7 --- /dev/null +++ b/mpeglib/lib/mpegplay/picture.h @@ -0,0 +1,82 @@ +/* + mpeg video picture + 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 __PICTURE_H +#define __PICTURE_H + + +#include "mpegExtension.h" + + +class Picture { + +/* Picture structure. */ + + unsigned int temp_ref; /* Temporal reference. */ + unsigned int code_type; /* Frame type: P, B, I */ + unsigned int vbv_delay; /* Buffer delay. */ + int full_pel_forw_vector; /* Forw. vectors specified in full + pixel values flag. */ + unsigned int forw_r_size; /* Used for vector decoding. */ + unsigned int forw_f; /* Used for vector decoding. */ + int full_pel_back_vector; /* Back vectors specified in full + pixel values flag. */ + unsigned int back_r_size; /* Used in decoding. */ + unsigned int back_f; /* Used in decoding. */ + + + // MPEG 2 [START] + + + MpegExtension* extension; + // sync info + class TimeStamp* startOfPicStamp; + + // MPEG 2 things + int extraBit; + + public: + Picture(); + ~Picture(); + + int processPicture(class MpegVideoStream* mpegVideoStream); + int processPictureCodingExtension(class MpegVideoStream* mpegVideoStream); + + + inline unsigned int getCodeType() { return code_type; } + inline unsigned int getForw_f() { return forw_f;} + inline unsigned int getBack_f() { return back_f;} + inline void setForw_f(unsigned int f) { forw_f=f;} + inline void setBack_f(unsigned int f) { back_f=f;} + + inline int getExtraBit() { return extraBit; } + + inline TimeStamp* getStartOfPicStamp() { return startOfPicStamp;} + inline unsigned int getFull_pel_forw_vector() {return full_pel_forw_vector;} + inline unsigned int getFull_pel_back_vector() {return full_pel_back_vector;} + + inline void setFull_pel_forw_vector(unsigned int v) {full_pel_forw_vector=v;} + inline void setFull_pel_back_vector(unsigned int v) {full_pel_back_vector=v;} + + unsigned int geth_back_r(class MpegVideoStream* mpegVideoStream); + unsigned int getv_back_r(class MpegVideoStream* mpegVideoStream); + + unsigned int geth_forw_r(class MpegVideoStream* mpegVideoStream); + unsigned int getv_forw_r(class MpegVideoStream* mpegVideoStream); + + +}; +#endif diff --git a/mpeglib/lib/mpegplay/proto.h b/mpeglib/lib/mpegplay/proto.h new file mode 100644 index 00000000..b9c35c2d --- /dev/null +++ b/mpeglib/lib/mpegplay/proto.h @@ -0,0 +1,36 @@ + + +#ifndef __PROTO_H +#define __PROTO_H + + + + +#include "videoDecoder.h" +#include "mpegVideoHeader.h" + + + +/* decoders.c */ +void init_tables (void); +extern "C" void Fast16Dither(unsigned char *lum, + unsigned char *cr, + unsigned char *cb, + unsigned char *out, + int rows, + int cols, + int mod); + + +/* floatdct.c */ +void init_float_idct (void); +void float_idct (short* block); +extern "C" void IDCT_mmx(short *); + + + + + + +#endif + diff --git a/mpeglib/lib/mpegplay/psSystemStream.cpp b/mpeglib/lib/mpegplay/psSystemStream.cpp new file mode 100644 index 00000000..b63843bc --- /dev/null +++ b/mpeglib/lib/mpegplay/psSystemStream.cpp @@ -0,0 +1,163 @@ +/* + demux "normal" mpeg stream (does this have a name?) + Copyright (C) 2001 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 "psSystemStream.h" + +#include <iostream> + +using namespace std; + +PSSystemStream::PSSystemStream(InputStream* input) { + this->input=input; +} + + +PSSystemStream::~PSSystemStream() { +} + + +int PSSystemStream::read(char* ptr,int bytes) { + if (input->read(ptr,bytes) != bytes) { + return false; + } + paket_read+=bytes; + + return true; +} + +int PSSystemStream::getByteDirect() { + unsigned char byte; + if (input->read((char*)&byte,1) != 1) { + return -1; + } + paket_read++; + return (int)byte; +} + + +// nuke bytes modulo 10 +int PSSystemStream::nukeBytes(int bytes) { + // nukebuffer + char nuke[10]; + + while(bytes > 0) { + int doNuke=10; + if (bytes < 10) doNuke=bytes; + if (input->read((char*)&nuke,doNuke) != doNuke) { + return false; + } + bytes-=doNuke; + paket_read+=doNuke; + } + return true; +} + + +int PSSystemStream::processStartCode(MpegSystemHeader* mpegHeader) { + unsigned int header=mpegHeader->getHeader(); + mpegHeader->setPacketLen(0); + mpegHeader->setPacketID(_PAKET_ID_NUKE); + + switch(header) { + case _PACK_START_CODE: + return processPackHeader(mpegHeader); + case _SYSTEM_HEADER_START_CODE: + return processSystemHeader(mpegHeader); + default: + cout << "PSSystemStream::processStartCode unknown PS header"<<endl; + exit(-1); + } + // never + return false; +} + + +int PSSystemStream::processPackHeader(MpegSystemHeader* mpegHeader) { + int back=false; + int numRead; + unsigned long scrbase; + unsigned long scrext; + unsigned long rate; + + double timeStamp; + + unsigned char inputBuffer[_PACKET_HEADER_SIZE+2]; + if (read((char*)inputBuffer, _PACKET_HEADER_SIZE) == false) return false; + + + // only set this if we do an initialize + int layer=mpegHeader->getLayer(); + if (layer == _PACKET_UNKNOWN_LAYER) { + if ((inputBuffer[0]>>6)==1) { + mpegHeader->setMPEG2(true); + } + } + + if (mpegHeader->getMPEG2()) { + if (read((char*)inputBuffer+_PACKET_HEADER_SIZE, 2) == false) return false; + + scrbase=GET_SCRBASE(inputBuffer); + scrext=GET_SCREXT(inputBuffer); + + // BUGGY: + timeStamp = (double)(scrbase*300 + scrext) / (double)MPEG2_CLK_REF; + + rate=GET_MPEG2MUXRATE(inputBuffer); + + int stuffing = GET_MPEG2STUFFING(inputBuffer); // always <= 7 + + numRead=stuffing; + if (stuffing) { + if (read((char*)inputBuffer, stuffing) == false) return false; + } + } else { + + // MPEG 1 + scrbase=GET_SCR(inputBuffer); + timeStamp=(double)scrbase/MPEG1_CLK_REF; + rate=GET_MPEG1_MUXRATE(inputBuffer); + rate*=_MUX_RATE_SCALE_FACTOR; + } + mpegHeader->setSCRTimeStamp(timeStamp); + mpegHeader->setRate(rate); + + + return true; +} + + +int PSSystemStream::processSystemHeader(MpegSystemHeader* mpegHeader) { + unsigned char *inputBuffer = NULL; + int numRead; + unsigned short headerSize; + + + if (read((char *)&headerSize, 2) == false) return false; + headerSize = ntohs(headerSize); + + inputBuffer = (unsigned char*) malloc (sizeof(unsigned char)*(headerSize+1)); + inputBuffer[headerSize]=0; + if (read((char*)inputBuffer, headerSize) == false) return false; + + mpegHeader->resetAvailableLayers(); + int i = 6; + while (i<headerSize) { + if (inputBuffer[i] & 0x80) { + mpegHeader->addAvailableLayer(inputBuffer[i]); + } + i += 3; + } + free(inputBuffer); + return true; +} + diff --git a/mpeglib/lib/mpegplay/psSystemStream.h b/mpeglib/lib/mpegplay/psSystemStream.h new file mode 100644 index 00000000..bb3b23fd --- /dev/null +++ b/mpeglib/lib/mpegplay/psSystemStream.h @@ -0,0 +1,57 @@ +/* + demux "normal" mpeg stream (does this have a name?) + Copyright (C) 2001 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 __PSSYSTEMSTREAM_H +#define __PSSYSTEMSTREAM_H + + +#include <stdlib.h> +#include "../input/inputPlugin.h" +#include "mpegSystemHeader.h" + +/** + This class is used inside mpegSystemStream.h when we found + during initialisation an "normal" mpeg stream. + This means: 1ba,1bb startcodes. + + +*/ + +class PSSystemStream { + + InputStream* input; + + int paket_len; + int paket_read; + + public: + PSSystemStream(InputStream* input); + ~PSSystemStream(); + + // called when we found a valid ts startcode + int processStartCode(MpegSystemHeader* mpegHeader); + + private: + + // read stream methods + int read(char* ptr,int bytes); + int getByteDirect(); + int nukeBytes(int bytes); + int skipNextByteInLength(); + + int processPackHeader(MpegSystemHeader* mpegHeader); + int processSystemHeader(MpegSystemHeader* mpegHeader); + + +}; +#endif diff --git a/mpeglib/lib/mpegplay/recon.cpp b/mpeglib/lib/mpegplay/recon.cpp new file mode 100644 index 00000000..6116157a --- /dev/null +++ b/mpeglib/lib/mpegplay/recon.cpp @@ -0,0 +1,735 @@ +/* + class for reconstruction + 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 "recon.h" + + +#define DEBUG_RECON(x) +//#define DEBUG_RECON(x) x + + + +Recon::Recon() { + copyFunctions=new CopyFunctions(); +} + + +Recon::~Recon() { + delete copyFunctions; +} + + +/* + *-------------------------------------------------------------- + * + * ReconIMBlock -- + * + * Reconstructs intra coded macroblock. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int Recon::ReconIMBlock(int bnum,int mb_row,int mb_col,int row_size, + short int* dct_start,PictureArray* pictureArray) { + int row, col; + unsigned char *dest; + unsigned char *picDest; + int lumLength=(pictureArray->getCurrent())->getLumLength(); + int colorLength=(pictureArray->getCurrent())->getColorLength(); + int endDest=0; + + + + /* If block is luminance block... */ + + if (bnum < 4) { + + /* Calculate row and col values for upper left pixel of block. */ + + row = mb_row << 4; + col = mb_col << 4; + if (bnum > 1) + row += 8; + if (bnum % 2) + col += 8; + + /* Set dest to luminance plane of current pict image. */ + + picDest = (pictureArray->getCurrent())->getLuminancePtr(); + endDest=lumLength; + + } + /* Otherwise if block is Cr block... */ + /* Cr first because of the earlier mixup */ + + else if (bnum == 5) { + + /* Set dest to Cr plane of current pict image. */ + + picDest = (pictureArray->getCurrent())->getCrPtr(); + endDest=colorLength; + + /* Establish row size. yuv color is half of whole size*/ + row_size >>=1; + + /* Calculate row,col for upper left pixel of block. */ + + row = mb_row << 3; + col = mb_col << 3; + } + /* Otherwise block is Cb block, and ... */ + + else { + + /* Set dest to Cb plane of current pict image. */ + + picDest = (pictureArray->getCurrent())->getCbPtr(); + endDest=colorLength; + + + /* Establish row size. yuv color is half of whole size*/ + + row_size /=2; + + /* Calculate row,col for upper left pixel value of block. */ + + row = mb_row << 3; + col = mb_col << 3; + } + + + /* + * For each pixel in block, set to cropped reconstructed value from inverse + * dct. + */ + + dest = picDest+row * row_size + col; + + + if ((dest+7*row_size+7 >= picDest+endDest) || (dest < picDest)) { + DEBUG_RECON(cout << "urg! last resort caught before sigsev -4"<<endl;) + return false; + } + + + copyFunctions->copy8_src1linear_crop(dct_start,dest,row_size); + + + return true; +} + + + +/* + *-------------------------------------------------------------- + * + * ReconPMBlock -- + * + * Reconstructs forward predicted macroblocks. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int Recon::ReconPMBlock(int bnum, + int recon_right_for, + int recon_down_for, + int zflag, + int mb_row,int mb_col, + int row_size,short int* dct_start, + PictureArray* pictureArray,int codeType) { + int row, col, rr; + unsigned char *picDest, *past; + unsigned char *rindex1, *rindex2, *rindex3, *rindex4; + unsigned char *index; + int lumLength=(pictureArray->getCurrent())->getLumLength(); + int colorLength=(pictureArray->getCurrent())->getColorLength(); + int endPast=0; + int endDest=0; + + + int right_for; + int down_for; + int right_half_for; + int down_half_for; + + + + picDest=0; + + if (bnum < 4) { + + + + /* Set dest to luminance plane of current pict image. */ + + picDest = (pictureArray->getCurrent())->getLuminancePtr(); + endDest=lumLength; + + if (codeType == B_TYPE) { + past = (pictureArray->getPast())->getLuminancePtr(); + } else { + + /* Set predictive frame to current future frame. */ + + past = (pictureArray->getFuture())->getLuminancePtr(); + } + endPast=lumLength; + + + /* Calculate row,col of upper left pixel in block. */ + + row = mb_row << 4; + col = mb_col << 4; + if (bnum > 1) + row += 8; + if (bnum % 2) + col += 8; + + /* Otherwise, block is NOT luminance block, ... */ + + } else { + + /* Construct motion vectors. */ + + recon_right_for >>= 1; + recon_down_for >>= 1; + + /* Establish row size. yuv color is half of whole size*/ + + row_size /= 2; + + + /* Calculate row,col of upper left pixel in block. */ + + row = mb_row << 3; + col = mb_col << 3; + + /* If block is Cr block... */ + /* 5 first because order was mixed up in earlier versions */ + + if (bnum == 5) { + + /* Set dest to Cr plane of current pict image. */ + + picDest = (pictureArray->getCurrent())->getCrPtr(); + + if (codeType == B_TYPE) { + + past = (pictureArray->getPast())->getCrPtr(); + } else { + past = (pictureArray->getFuture())->getCrPtr(); + } + } + /* Otherwise, block is Cb block... */ + + else { + + /* Set dest to Cb plane of current pict image. */ + + picDest = (pictureArray->getCurrent())->getCbPtr(); + + if (codeType == B_TYPE) { + past = (pictureArray->getPast())->getCbPtr(); + } else { + past = (pictureArray->getFuture())->getCbPtr(); + } + } + endPast=colorLength; + endDest=colorLength; + + } + + /* Calculate right_back, down_back motion vectors. */ + right_for = recon_right_for >> 1; + down_for = recon_down_for >> 1; + right_half_for = recon_right_for & 0x1; + down_half_for = recon_down_for & 0x1; + + + /* For each pixel in block... */ + + index = picDest + (row * row_size) + col; + rindex1 = past + (row + down_for) * row_size + col + right_for; + + + + + if ((rindex1+7*row_size+7 >= past+endPast) || (rindex1 < past)) { + DEBUG_RECON(cout << "urg! last resort caught before sigsev -1"<<endl;) + return false; + } + if ((index+7*row_size+7 >= picDest+endDest) || (index < picDest)) { + DEBUG_RECON(cout << "urg! last resort caught before sigsev -2"<<endl;) + return false; + } + + + /* + * Calculate predictive pixel value based on motion vectors and copy to + * dest plane. + */ + + if ((!down_half_for) && (!right_half_for)) { + + if (!zflag) { + copyFunctions->copy8_src2linear_crop(rindex1,dct_start,index,row_size); + } else { + if (right_for & 0x1) { + + /* No alignment, used byte copy */ + copyFunctions->copy8_byte(rindex1,index,row_size); + + + } else if (right_for & 0x2) { + /* Half-word bit aligned, use 16 bit copy */ + unsigned short *src = (unsigned short *)rindex1; + unsigned short *dest = (unsigned short *)index; + row_size >>= 1; + copyFunctions->copy8_word(src,dest,row_size); + + } else { + /* Word aligned, use 32 bit copy */ + int *src = (int*) rindex1; + int *dest = (int*) index; + + row_size >>= 2; + + + for (rr = 0; rr < 8; rr++) { + dest[0] = src[0]; + dest[1] = src[1]; + dest += row_size; + src += row_size; + } + + } + } + } else { + rindex2 = rindex1 + right_half_for + (down_half_for * row_size); + + /* if one of the two is zero, then quality makes no difference */ + if ((!right_half_for) || (!down_half_for) || (!qualityFlag)) { + + if (!zflag) { + // was +1 + copyFunctions->copy8_div2_src3linear_crop(rindex1,rindex2,dct_start, + index,row_size); + } else { /* zflag */ + // was +1 + copyFunctions->copy8_div2_nocrop(rindex1,rindex2,index,row_size); + } + } else { /* qualityFlag on and both vectors are non-zero */ + rindex3 = rindex1 + right_half_for; + rindex4 = rindex1 + (down_half_for * row_size); + if (!zflag) { + copyFunctions->copy8_div4_src5linear_crop(rindex1,rindex2,rindex3, + rindex4,dct_start, + index,row_size); + } else { /* zflag */ + copyFunctions->copy8_div4_nocrop(rindex1,rindex2,rindex3,rindex4, + index,row_size); + } + } + + } + + return true; +} + + +/* + *-------------------------------------------------------------- + * + * ReconBMBlock -- + * + * Reconstructs back predicted macroblocks. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int Recon::ReconBMBlock(int bnum, + int recon_right_back, + int recon_down_back, + int zflag, + int mb_row,int mb_col, + int row_size,short int* dct_start, + PictureArray* pictureArray) { + int row, col, rr; + unsigned char *dest, *future; + int right_back, down_back, right_half_back, down_half_back; + unsigned char *rindex1, *rindex2, *rindex3, *rindex4; + unsigned char *index; + int lumLength=(pictureArray->getCurrent())->getLumLength(); + int colorLength=(pictureArray->getCurrent())->getColorLength(); + + int endFuture=0; + int endDest=0; + + + /* If block is luminance block... */ + + if (bnum < 4) { + + + /* Set dest to luminance plane of current pict image. */ + + dest = (pictureArray->getCurrent())->getLuminancePtr(); + endDest=lumLength; + /* + * If future frame exists, set future to luminance plane of future frame. + */ + + future = (pictureArray->getFuture())->getLuminancePtr(); + endFuture=lumLength; + + /* Calculate row,col of upper left pixel in block. */ + + row = mb_row << 4; + col = mb_col << 4; + if (bnum > 1) + row += 8; + if (bnum % 2) + col += 8; + + + } + /* Otherwise, block is NOT luminance block, ... */ + + else { + + /* Construct motion vectors. */ + + recon_right_back >>= 1; + recon_down_back >>= 1; + + /* Establish row size. yuv color is half of whole size*/ + + row_size >>= 1; + + /* Calculate row,col of upper left pixel in block. */ + + row = mb_row << 3; + col = mb_col << 3; + + + /* If block is Cr block... */ + /* They were switched earlier, so 5 is first - eyhung */ + + if (bnum == 5) { + + /* Set dest to Cr plane of current pict image. */ + + dest = (pictureArray->getCurrent())->getCrPtr(); + + /* + * If future frame exists, set future to Cr plane of future image. + */ + + future = (pictureArray->getFuture())->getCrPtr(); + } + /* Otherwise, block is Cb block... */ + + else { + + /* Set dest to Cb plane of current pict image. */ + + dest = (pictureArray->getCurrent())->getCbPtr(); + + /* + * If future frame exists, set future to Cb plane of future frame. + */ + + future = (pictureArray->getFuture())->getCbPtr(); + } + endDest=colorLength; + endFuture=colorLength; + } + + /* Calculate right_back, down_back motion vectors. */ + right_back = recon_right_back >> 1; + down_back = recon_down_back >> 1; + right_half_back = recon_right_back & 0x1; + down_half_back = recon_down_back & 0x1; + + /* For each pixel in block do... */ + + index = dest + (row * row_size) + col; + rindex1 = future + (row + down_back) * row_size + col + right_back; + + if ((index+7*row_size+7 >= dest+endDest) || (index < dest)) { + DEBUG_RECON(cout << "urg! last resort -9"<<endl;) + return false; + } + if ((rindex1+7*row_size+7 >= future+endFuture) || (rindex1 < future)) { + DEBUG_RECON(cout << "urg! last resort -8"<<endl;) + return false; + } + + if ((!right_half_back) && (!down_half_back)) { + if (!zflag) { + copyFunctions->copy8_src2linear_crop(rindex1,dct_start,index,row_size); + } else { + if (right_back & 0x1) { + /* No alignment, use byte copy */ + + copyFunctions->copy8_byte(rindex1,index,row_size); + + } else if (right_back & 0x2) { + /* Half-word bit aligned, use 16 bit copy */ + unsigned short *src = (unsigned short *)rindex1; + unsigned short *dest = (unsigned short *)index; + row_size >>= 1; + copyFunctions->copy8_word(src,dest,row_size); + + } else { + /* Word aligned, use 32 bit copy */ + int *src = (int *)rindex1; + int *dest = (int *)index; + row_size >>= 2; + for (rr = 0; rr < 8; rr++) { + dest[0] = src[0]; + dest[1] = src[1]; + dest += row_size; + src += row_size; + } + } + } + } else { + rindex2 = rindex1 + right_half_back + (down_half_back * row_size); + if (!qualityFlag) { + + if (!zflag) { + // was +1 + copyFunctions->copy8_div2_src3linear_crop(rindex1,rindex2,dct_start, + index,row_size); + } else { /* zflag */ + // was +1 + copyFunctions->copy8_div2_nocrop(rindex1,rindex2,index,row_size); + } + } else { /* qualityFlag on */ + rindex3 = rindex1 + right_half_back; + rindex4 = rindex1 + (down_half_back * row_size); + if (!zflag) { + copyFunctions->copy8_div4_src5linear_crop(rindex1,rindex2,rindex3, + rindex4,dct_start, + index,row_size); + } else { /* zflag */ + copyFunctions->copy8_div4_nocrop(rindex1,rindex2,rindex3,rindex4, + index,row_size); + } + } + + } + return true; +} + + +/* + *-------------------------------------------------------------- + * + * ReconBiMBlock -- + * + * Reconstructs bidirectionally predicted macroblocks. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ +int Recon::ReconBiMBlock(int bnum, + int recon_right_for, + int recon_down_for, + int recon_right_back, + int recon_down_back, + int zflag,int mb_row, + int mb_col,int row_size,short int* dct_start, + PictureArray* pictureArray) { + int row, col; + unsigned char *dest, *past=NULL, *future=NULL; + int right_for, down_for, right_half_for, down_half_for; + int right_back, down_back, right_half_back, down_half_back; + unsigned char *index, *rindex1, *bindex1; + int forw_row_start, back_row_start, forw_col_start, back_col_start; + int lumLength=(pictureArray->getCurrent())->getLumLength(); + int colorLength=(pictureArray->getCurrent())->getColorLength(); + int endPast=0; + int endFuture=0; + + + + + /* If block is luminance block... */ + + if (bnum < 4) { + + + /* Set dest to luminance plane of current pict image. */ + + dest = (pictureArray->getCurrent())->getLuminancePtr(); + + /* If past frame exists, set past to luminance plane of past frame. */ + + past = (pictureArray->getPast())->getLuminancePtr(); + endPast=lumLength; + + /* + * If future frame exists, set future to luminance plane of future frame. + */ + + future = (pictureArray->getFuture())->getLuminancePtr(); + endFuture=lumLength; + + /* Calculate row,col of upper left pixel in block. */ + + row = (mb_row << 4); + col = (mb_col << 4); + if (bnum > 1) + row += 8; + if (bnum & 0x01) + col += 8; + + + + } else { + /* Otherwise, block is NOT luminance block, ... */ + + /* Construct motion vectors. */ + recon_right_for >>= 1; + recon_down_for >>= 1; + recon_right_back >>= 1; + recon_down_back >>= 1; + + /* Establish row size. yuv color is half of whole size*/ + + row_size /= 2; + + + /* Calculate row,col of upper left pixel in block. */ + + row = (mb_row << 3); + col = (mb_col << 3); + + + + + /* If block is Cr block... */ + /* Switched earlier, so we test Cr first - eyhung */ + + if (bnum == 5) { + /* Set dest to Cr plane of current pict image. */ + + dest = (pictureArray->getCurrent())->getCrPtr(); + + /* If past frame exists, set past to Cr plane of past image. */ + + past = (pictureArray->getPast())->getCrPtr(); + endPast=colorLength; + /* + * If future frame exists, set future to Cr plane of future image. + */ + + future = (pictureArray->getFuture())->getCrPtr(); + endFuture=colorLength; + } + /* Otherwise, block is Cb block... */ + + else { + /* Set dest to Cb plane of current pict image. */ + dest = (pictureArray->getCurrent())->getCbPtr(); + + /* If past frame exists, set past to Cb plane of past frame. */ + + past = (pictureArray->getPast())->getCbPtr(); + endPast=colorLength; + + /* + * If future frame exists, set future to Cb plane of future frame. + */ + + future = (pictureArray->getFuture())->getCbPtr(); + endFuture=colorLength; + } + } + /* + * Calculate right_for, down_for, right_half_for, down_half_for, + * right_back, down_bakc, right_half_back, and down_half_back, motion + * vectors. + */ + + right_for = recon_right_for >> 1; + down_for = recon_down_for >> 1; + right_half_for = recon_right_for & 0x1; + down_half_for = recon_down_for & 0x1; + + right_back = recon_right_back >> 1; + down_back = recon_down_back >> 1; + right_half_back = recon_right_back & 0x1; + down_half_back = recon_down_back & 0x1; + + forw_col_start = col + right_for; + forw_row_start = row + down_for; + + back_col_start = col + right_back; + back_row_start = row + down_back; + + /* For each pixel in block... */ + + index = dest + (row * row_size) + col; + + rindex1 = past + forw_row_start * row_size + forw_col_start; + + bindex1 = future + back_row_start * row_size + back_col_start; + + if ((rindex1+7*row_size+7 >= past+endPast) || (rindex1 < past)) { + DEBUG_RECON(cout << "urg! last resort -1"<<endl;) + return false; + } + if ((bindex1+7*row_size+7 >= future+endFuture) || (bindex1 < future)) { + DEBUG_RECON(cout << "urg! last resort -2"<<endl;) + return false; + } + + + + if (!zflag) { + copyFunctions->copy8_div2_src3linear_crop(rindex1,bindex1,dct_start, + index,row_size); + } else { + copyFunctions->copy8_div2_nocrop(rindex1,bindex1,index,row_size); + } + + return true; +} + + diff --git a/mpeglib/lib/mpegplay/recon.h b/mpeglib/lib/mpegplay/recon.h new file mode 100644 index 00000000..26c3e92e --- /dev/null +++ b/mpeglib/lib/mpegplay/recon.h @@ -0,0 +1,55 @@ +/* + class for reconstruction + 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 __RECON_H +#define __RECON_H + + +#include <iostream> +#include "../util/render/pictureArray.h" +#include "copyFunctions.h" +#include "videoDecoder.h" + +class Recon { + + + CopyFunctions* copyFunctions; + + public: + Recon(); + ~Recon(); + + int ReconIMBlock(int bnum,int mb_row,int mb_col,int row_size, + short int* dct_start,PictureArray* pictureArray); + + int ReconPMBlock(int bnum,int recon_right_for, + int recon_down_for,int zflag, + int mb_row,int mb_col,int row_size, + short int* dct_start,PictureArray* pictureArray, + int codeType); + + int ReconBMBlock(int bnum,int recon_right_back, + int recon_down_back,int zflag, + int mb_row,int mb_col,int row_size, + short int* dct_start,PictureArray* pictureArray); + + int ReconBiMBlock(int bnum,int recon_right_for, + int recon_down_for,int recon_right_back, + int recon_down_back,int zflag, + int mb_row,int mb_col,int row_size, + short int* dct_start,PictureArray* pictureArray); + + + +}; +#endif diff --git a/mpeglib/lib/mpegplay/slice.cpp b/mpeglib/lib/mpegplay/slice.cpp new file mode 100644 index 00000000..1a64378f --- /dev/null +++ b/mpeglib/lib/mpegplay/slice.cpp @@ -0,0 +1,73 @@ +/* + reads/parse slice infos + 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 "slice.h" + + + + +Slice::Slice() { + mpegExtension=new MpegExtension(); +} + + +Slice::~Slice() { + delete mpegExtension; + +} + +unsigned int Slice::getVertPos() { + return vert_pos; +} + + + +void Slice::setQuantScale(unsigned int quant_scale) { + this->quant_scale=quant_scale; +} + +/* + *-------------------------------------------------------------- + * + * ParseSlice -- + * + * Parses off slice header. + * + * Results: + * Values found in slice header put into video stream structure. + * + * Side effects: + * Bit stream irreversibly parsed. + * + *-------------------------------------------------------------- + */ +int Slice::parseSlice(MpegVideoStream* mpegVideoStream) { + + /* Flush slice start code. */ + mpegVideoStream->flushBits(24); + + /* Parse off slice vertical position. */ + /* its the "slice number" */ + vert_pos=mpegVideoStream->getBits(8); + + /* Parse off quantization scale. */ + quant_scale=mpegVideoStream->getBits(5); + + /* Parse off extra bit slice info. */ + mpegExtension->processExtra_bit_info(mpegVideoStream); + + return true; +} + + + diff --git a/mpeglib/lib/mpegplay/slice.h b/mpeglib/lib/mpegplay/slice.h new file mode 100644 index 00000000..10689d34 --- /dev/null +++ b/mpeglib/lib/mpegplay/slice.h @@ -0,0 +1,48 @@ +/* + reads/parse slice infos + 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 __SLICE_H +#define __SLICE_H + +#include "jrevdct.h" +#include "mpegExtension.h" + +/* Size increment of extension data buffers. */ + +#define EXT_BUF_SIZE 1024 + +class Slice { + + + public: + Slice(); + ~Slice(); + int parseSlice(MpegVideoStream* mpegVideoStream); + unsigned int getVertPos(); + inline unsigned int getQuantScale() {return quant_scale;} + void setQuantScale(unsigned int quant_scale); + + + private: + + /* Slice structure. */ + + unsigned int vert_pos; /* Vertical position of slice. */ + unsigned int quant_scale; /* Quantization scale. */ + MpegExtension* mpegExtension; /* Extra bit slice info. */ + +}; + + +#endif diff --git a/mpeglib/lib/mpegplay/startCodes.h b/mpeglib/lib/mpegplay/startCodes.h new file mode 100644 index 00000000..c305a39f --- /dev/null +++ b/mpeglib/lib/mpegplay/startCodes.h @@ -0,0 +1,63 @@ +/* + definitions of common startcodes + 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 __STARTCODES_H +#define __STARTCODES_H + + + +/* Macros for picture code type. */ + +#define I_TYPE 1 +#define P_TYPE 2 +#define B_TYPE 3 +#define D_TYPE 4 + +/* Start codes. */ + + +#define SEQ_END_CODE 0x000001b7 +#define SEQ_START_CODE 0x000001b3 +#define GOP_START_CODE 0x000001b8 +#define PICTURE_START_CODE 0x00000100 +#define SLICE_MIN_START_CODE 0x00000101 +#define SLICE_MAX_START_CODE 0x000001af +#define EXT_START_CODE 0x000001b5 +#define USER_START_CODE 0x000001b2 +#define SEQUENCE_ERROR_CODE 0x000001b4 + +//extension start code ids +#define SEQUENCE_EXTENSION_ID 1 +#define SEQUENCE_DISPLAY_EXTENSION_ID 2 +#define QUANT_MATRIX_EXTENSION_ID 3 +#define COPYRIGHT_EXTENSION_ID 4 +#define SEQUENCE_SCALABLE_EXTENSION_ID 5 +#define PICTURE_DISPLAY_EXTENSION_ID 7 +#define PICTURE_CODING_EXTENSION_ID 8 +#define PICTURE_SPATIAL_SCALABLE_EXTENSION_ID 9 +#define PICTURE_TEMPORAL_SCALABLE_EXTENSION_ID 10 + +#define ISO_11172_END_CODE ((unsigned int)0x000001b9) +#define SYSTEM_HEADER_START_CODE ((unsigned int)0x000001bb) + +/* Macros used with macroblock address decoding. */ + +#define MB_STUFFING 34 +#define MB_ESCAPE 35 + + + +#endif diff --git a/mpeglib/lib/mpegplay/tsSystemStream.cpp b/mpeglib/lib/mpegplay/tsSystemStream.cpp new file mode 100644 index 00000000..4c9221ac --- /dev/null +++ b/mpeglib/lib/mpegplay/tsSystemStream.cpp @@ -0,0 +1,377 @@ +/* + demux transport stream + Copyright (C) 2001 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 "tsSystemStream.h" + + +#define PKT_SIZE 188 + + +TSSystemStream::TSSystemStream(InputStream* input) { + this->input=input; + +} + + +TSSystemStream::~TSSystemStream() { +} + +int TSSystemStream::read(char* ptr,int bytes) { + if (input->read(ptr,bytes) != bytes) { + return false; + } + paket_read+=bytes; + + return true; +} + +int TSSystemStream::getByteDirect() { + unsigned char byte; + if (input->read((char*)&byte,1) != 1) { + return -1; + } + paket_read++; + return (int)byte; +} + + +// nuke bytes modulo 10 +int TSSystemStream::nukeBytes(int bytes) { + // nukebuffer + char nuke[10]; + + while(bytes > 0) { + int doNuke=10; + if (bytes < 10) doNuke=bytes; + if (input->read((char*)&nuke,doNuke) != doNuke) { + return false; + } + bytes-=doNuke; + paket_read+=doNuke; + } + return true; +} + + +int TSSystemStream::skipNextByteInLength() { + int length=getByteDirect(); + if (length < 0) return false; + + /* + * Skip read byte in length, but check paket_size + */ + if (paket_read+length > PKT_SIZE) { + printf ("demux error! invalid payload size %d\n",length); + return false; + } + if (nukeBytes(length) == false) return false; + return true; +} + + + + +int TSSystemStream::processStartCode(MpegSystemHeader* mpegHeader) { + paket_len=PKT_SIZE; + paket_read=4; // startcode=4 bytes + + mpegHeader->setTSPacketLen(0); + mpegHeader->setPacketID(_PAKET_ID_NUKE); + + unsigned int pid=mpegHeader->getPid(); + unsigned int pmtPID=mpegHeader->getPMTPID(); + if ( (pmtPID == INVALID_PID) && (pid != 0)) { + return false; + } + + if ((mpegHeader->getAdaption_field_control() & 0x1)==0) { + return true; + } + + /* + * Has a payload! Calculate & check payload length. + */ + if (mpegHeader->getAdaption_field_control() & 0x2) { + if (skipNextByteInLength() == false) return false; + } + + /* + * Do the demuxing in based on the pids + */ + + if (pid == mpegHeader->getPMTPID()) { + return demux_ts_pmt_parse(mpegHeader); + } + + if (pid == 0) { + return demux_ts_pat_parse(mpegHeader); + } + // + // ok, no the only things left to do is the + // decision what to do with the packet + // + + mpegHeader->setTSPacketLen(paket_len-paket_read); + + if (pid == 0x1fff) { + printf("Nuke Packet\n"); + return true; + } + + + MapPidStream* mapPidStream=mpegHeader->lookup(pid); + + if (mapPidStream->isValid == true) { + // set to something different from "NUKE_PAKET" + mpegHeader->setPacketID(_PAKET_ID_AUDIO_1); + return true; + } + // well the raw stream has a TS header and a PID, but we have not a valid + // mapping pid->tsType. + // we return false here to have a recovery if our + // previous decision that we actually have a TS stream was wrong. + + // force resync + return false; +} + +/* + * NAME demux_ts_pmt_parse + * + * Parse a PMT. The PMT is expected to be exactly one section long, + * and that section is expected to be contained in a single TS packet. + * + * In other words, the PMT is assumed to describe a reasonable number of + * video, audio and other streams (with descriptors). + */ + +int TSSystemStream::demux_ts_pmt_parse(MpegSystemHeader* mpegHeader) { + int sectionLength=processSection(mpegHeader); + if (sectionLength == 0) return false; + + //? + if (nukeBytes(2) == false) return false; + sectionLength-=2; + + /* + * ES definitions start here...we are going to learn upto one video + * PID and one audio PID. + */ + + + unsigned char pkt[2]; + if (read((char*)pkt,2) == false) return false; + sectionLength-=2; + + unsigned int programInfoLength; + + programInfoLength=(((unsigned int)pkt[0] & 0x0f) << 8) | pkt[1]; + if (paket_read+programInfoLength > paket_len) { + printf ("demux error! PMT with inconsistent progInfo length\n"); + return false; + } + + if (nukeBytes(programInfoLength) == false) return false; + sectionLength-=programInfoLength; + + return processElementary(sectionLength,mpegHeader); + + +} + +/** + return false on error or section length info on success +*/ +int TSSystemStream::processSection(MpegSystemHeader* mpegHeader) { + unsigned int pus=mpegHeader->getPayload_unit_start_indicator(); + + /* + * A PAT in a single section should start with a payload unit start + * indicator set. + */ + if (pus==0) { + printf ("demux error! PAT without payload unit start\n"); + return false; + } + /* + * PAT packets with a pus start with a pointer. Skip it! + */ + if (skipNextByteInLength() == false) return false; + + // ?? + if (nukeBytes(1) == false) return false; + + // read sectionLength + unsigned char pkt[2]; + if (read((char*)pkt,2) ==false) return false; + + + int sectionLength=(((unsigned int)pkt[0] & 0x3) << 8) | pkt[1]; + if (paket_read+sectionLength > PKT_SIZE) { + printf ("demux error! invalid section size %d\n",sectionLength); + return false; + } + + // ?? + if (nukeBytes(2) == false) return false; + + int byte=getByteDirect(); + if (byte < 0) return false; + + if ((byte & 0x01) == false) { + /* + * Not current! + */ + return false; + } + if (read((char*)pkt,2) == false) return false; + + if ((pkt[0]) || (pkt[1])) { + printf ("demux error! PAT with invalid section %02x of %02x\n", + pkt[0], pkt[1]); + return false; + } + + /* + * TBD: at this point, we should check the CRC. Its not that expensive, and + * the consequences of getting it wrong are dire! + */ + return sectionLength-5; +} + +/* + * NAME demux_ts_pat_parse + * + * Parse a PAT. The PAT is expected to be exactly one section long, + * and that section is expected to be contained in a single TS packet. + * + * The PAT is assumed to contain a single program definition, though + * we can cope with the stupidity of SPTSs which contain NITs. + */ + +int TSSystemStream::demux_ts_pat_parse(MpegSystemHeader* mpegHeader) { + int sectionLength=processSection(mpegHeader); + if (sectionLength == 0) return false; + + return processPrograms(sectionLength,mpegHeader); + +} + + +/* + * Process all programs in the program loop. + */ +int TSSystemStream::processPrograms(int sectionLength, + MpegSystemHeader* mpegHeader) { + int programs=sectionLength / 4; + int i; + // what happens with the last 4 byte? + // seems they have no meaning? + programs--; + + for(i=0;i<programs;i++) { + unsigned char program[4]; + if (read((char*)program,4) == false) return false; + + + unsigned int programNumber; + unsigned int pmtPid; + unsigned int programCount; + programNumber = ((unsigned int)program[0] << 8) | program[1]; + + /* + * Skip NITs completely. + */ + if (!programNumber) + continue; + + pmtPid = (((unsigned int)program[2] & 0x1f) << 8) | program[3]; + + + /* + * If we have yet to learn our program number, then learn it. + */ + + if (mpegHeader->getProgramNumber() == INVALID_PROGRAM) { + mpegHeader->setProgramNumber(programNumber); + mpegHeader->setPMTPID(pmtPid); + } + + if (mpegHeader->getProgramNumber() != programNumber) { + printf("demux error! MPTS: programNumber=%u pmtPid=%04x\n", + programNumber, pmtPid); + } + + if (mpegHeader->getPMTPID() != pmtPid) { + printf("pmtPid changed %04x\n", pmtPid); + mpegHeader->setPMTPID(pmtPid); + } + + } + // nuke last four bytes + if (nukeBytes(4) == false) return false; + + // + // now we can nuke the rest of the PAKET_SIZE (188 byte) + // + mpegHeader->setTSPacketLen(paket_len-paket_read); + return true; +} + + + +int TSSystemStream::processElementary(int sectionLength, + MpegSystemHeader* mpegHeader) { + + + /* + * Extract the elementary streams. + */ + int mediaIndex=0; + // what happens with the last 4 byte? + // seems they have no meaning? + while (sectionLength > 4) { + unsigned int streamInfoLength; + unsigned char stream[5]; + if (read((char*)stream,5) == false) return false; + sectionLength-=5; + + unsigned int pid; + pid = (((unsigned int)stream[1] & 0x1f) << 8) | stream[2]; + + streamInfoLength = (((unsigned int)stream[3] & 0xf) << 8) | stream[4]; + if(paket_read+streamInfoLength > paket_len) { + printf ("demux error! PMT with inconsistent streamInfo length\n"); + return false; + } + mpegHeader->insert(pid,stream[0],mpegHeader); + + } + + // nuke last four bytes + if (nukeBytes(4) == false) return false; + // + // now we can nuke the rest of the PAKET_SIZE (188 byte) + // + mpegHeader->setTSPacketLen(paket_len-paket_read); + + // + // now we can be sure that we have in fact an TS stream + // so, switch to MPEG2 PES now + mpegHeader->setMPEG2(true); + + return true; +} + + diff --git a/mpeglib/lib/mpegplay/tsSystemStream.h b/mpeglib/lib/mpegplay/tsSystemStream.h new file mode 100644 index 00000000..114365c4 --- /dev/null +++ b/mpeglib/lib/mpegplay/tsSystemStream.h @@ -0,0 +1,68 @@ +/* + demux transport stream + Copyright (C) 2001 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 __TSSYSTEMSTREAM_H +#define __TSSYSTEMSTREAM_H + + +#include <stdlib.h> +#include "../input/inputPlugin.h" +#include "mpegSystemHeader.h" + + + +/** + This class is used inside mpegSystemStream.h when we found + during initialisation an transport stream. + + +*/ + +class TSSystemStream { + + InputStream* input; + + int paket_len; + int paket_read; + + + + public: + TSSystemStream(InputStream* input); + ~TSSystemStream(); + + // called when we found a valid ts startcode + int processStartCode(MpegSystemHeader* mpegHeader); + + + private: + + // read stream methods + int read(char* ptr,int bytes); + int getByteDirect(); + int nukeBytes(int bytes); + int skipNextByteInLength(); + + + // process Format methods + int processSection(MpegSystemHeader* mpegHeader); + int processPrograms(int sectionLength,MpegSystemHeader* mpegHeader); + int processElementary(int sectionLength,MpegSystemHeader* mpegHeader); + + int demux_ts_pat_parse(MpegSystemHeader* mpegHeader); + int demux_ts_pmt_parse(MpegSystemHeader* mpegHeader); + + +}; +#endif diff --git a/mpeglib/lib/mpegplay/videoDecoder.cpp b/mpeglib/lib/mpegplay/videoDecoder.cpp new file mode 100644 index 00000000..b1971795 --- /dev/null +++ b/mpeglib/lib/mpegplay/videoDecoder.cpp @@ -0,0 +1,476 @@ +/* + mpeg I video decoder (derived from mpeg_play) + 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 "videoDecoder.h" + +using namespace std; + + + +VideoDecoder::VideoDecoder(MpegVideoStream* inputStream, + MpegVideoHeader* initSequence) { + + /* Check for legal buffer length. */ + + init_tables(); + + + /* Initialize fields that used to be global */ + + mpegVideoStream=inputStream; + decoderClass=new DecoderClass(this,mpegVideoStream); + recon=new Recon(); + motionVector=new MotionVector(); + slice=new Slice(); + group=new GOP(); + mpegVideoHeader=new MpegVideoHeader(); + picture=new Picture(); + macroBlock=new MacroBlock(this); + + // init this stream with the init sequence + initSequence->copyTo(mpegVideoHeader); + + syncState=SYNC_TO_CLOSED_GOP; + extension=new MpegExtension(); + frameCounter=0; +} + + +VideoDecoder::~VideoDecoder() { + + delete mpegVideoHeader; + delete picture; + delete decoderClass; + delete recon; + delete motionVector; + delete slice; + delete group; + delete extension; + delete macroBlock; +} + + + + + +/* + *-------------------------------------------------------------- + * + * mpegVidRsrc -- + * + * Parses bit stream until MB_QUANTUM number of + * macroblocks have been decoded or current slice or + * picture ends, whichever comes first. If the start + * of a frame is encountered, the frame is time stamped + * with the value passed in time_stamp. If the value + * passed in buffer is not null, the video stream buffer + * is set to buffer and the length of the buffer is + * expected in value passed in through length. The current + * video stream is set to vid_stream. If vid_stream + * is passed as NULL, a new VideoDecoder structure is created + * and initialized and used as the current video stream. + * + * Results: + * A pointer to the video stream structure used. + * + * Side effects: + * Bit stream is irreversibly parsed. If a picture is completed, + * a function is called to display the frame at the correct time. + * + *-------------------------------------------------------------- + */ + +int VideoDecoder::mpegVidRsrc(PictureArray* pictureArray) { + int back=_SYNC_TO_NONE; + + unsigned int data; + int i; + + + /* + * If called for the first time, find start code, make sure it is a + * sequence start code. + */ + + + /* Get next 32 bits (size of start codes). */ + + data=mpegVideoStream->showBits(32); + + + /* + * Process according to start code (or parse macroblock if not a start code + * at all). + */ + switch (data) { + /* + case PACK_START_CODE: + case SYSTEM_HEADER_START_CODE: + cout << "Packet in Loop **************"<<endl; + mpegVideoStream->flushBits(32); + packet->read_sys(data,vid_stream->bufferReader); + */ + case SEQ_END_CODE: + case ISO_11172_END_CODE: /* handle ISO_11172_END_CODE too */ + + /* Display last frame. */ + + // removed! + + /* Sequence done. Do the right thing. For right now, exit. */ + + + cout << "******** flushin end code"<<endl; + mpegVideoStream->flushBits(32); + goto done; + break; + case EXT_START_CODE: + cout << "found EXT_START_CODE skipping"<<endl; + mpegVideoStream->flushBits(32); + /* Goto next start code. */ + mpegVideoStream->next_start_code(); + + break; + case USER_START_CODE: + mpegVideoStream->flushBits(32); + /* Goto next start code. */ + mpegVideoStream->next_start_code(); + + break; + case SEQ_START_CODE: + + /* Sequence start code. Parse sequence header. */ + if (ParseSeqHead() == false) { + printf("SEQ_START_CODE 1-error\n"); + goto error; + } + goto done; + + case GOP_START_CODE: + /* Group of Pictures start code. Parse gop header. */ + if (ParseGOP() == false) { + printf("GOP_START_CODE 1-error\n"); + goto error; + } + goto done; + + case PICTURE_START_CODE: + + /* Picture start code. Parse picture header and first slice header. */ + + + back=ParsePicture(); + if (back != _SYNC_TO_NONE) { + //cout << "skip B Frame we are late"<<endl; + return back; + } + + // parse ok + if (ParseSlice() == false) { + printf("PICTURE_START_CODE 2-error\n"); + goto error; + } + break; + + case SEQUENCE_ERROR_CODE: + mpegVideoStream->flushBits(32); + mpegVideoStream->next_start_code(); + + goto done; + + + default: + + /* Check for slice start code. */ + if ((data >= SLICE_MIN_START_CODE) && (data <= SLICE_MAX_START_CODE)) { + + /* Slice start code. Parse slice header. */ + if (ParseSlice() == false) { + printf("default 1-error\n"); + goto error; + } + } + break; + } + + /* Parse next MB_QUANTUM macroblocks. */ + for (i = 0; i < MB_QUANTUM; i++) { + + /* Check to see if actually a startcode and not a macroblock. */ + data=mpegVideoStream->showBits(23); + if (data != 0x0) { + /* Not start code. Parse Macroblock. fill yuv pictures*/ + if (macroBlock->processMacroBlock(pictureArray) == false) { + goto error; + } + } else { + /* Not macroblock, actually start code. Get start code. */ + mpegVideoStream->next_start_code(); + + /* + * If start code is outside range of slice start codes, frame is + * complete, display frame. + */ + data=mpegVideoStream->showBits(32); + + if (((data < SLICE_MIN_START_CODE) || (data > SLICE_MAX_START_CODE)) && + (data != SEQUENCE_ERROR_CODE)) { + doPictureDisplay(pictureArray); + } + goto done; + } + } + data=mpegVideoStream->showBits(23); + /* Check if we just finished a picture on the MB_QUANTUM macroblock */ + if (data == 0x0) { + mpegVideoStream->next_start_code(); + + data=mpegVideoStream->showBits(32); + if ((data < SLICE_MIN_START_CODE) || (data > SLICE_MAX_START_CODE)) { + doPictureDisplay(pictureArray); + } + } + + /* Return pointer to video stream structure. */ + + goto done; + +error: + init_tables(); + back=_SYNC_TO_GOP; + mpegVideoHeader->init_quanttables(); + + goto done; + +done: + return back; + +} + + + + + + +int VideoDecoder::ParseSeqHead() { + int back; + + /* Flush off sequence start code. */ + + mpegVideoStream->flushBits(32); + + back=mpegVideoHeader->parseSeq(mpegVideoStream); + + return back; + +} + + + + +int VideoDecoder::ParseGOP() { + if (syncState==SYNC_TO_CLOSED_GOP) { + syncState=SYNC_HAS_CLOSED_GOP; + } + + return group->processGOP(mpegVideoStream); +} + + + + +int VideoDecoder::ParsePicture() { + int back; + back=picture->processPicture(mpegVideoStream); + + macroBlock->resetPastMacroBlock(); + if (back == false) { + return _SYNC_TO_GOP; + } + + + return _SYNC_TO_NONE; +} + + + +int VideoDecoder::ParseSlice() { + + + slice->parseSlice(mpegVideoStream); + macroBlock->resetMacroBlock(); + decoderClass->resetDCT(); + return true; +} + + + + +/** + After a seek we can only start with an I frame +*/ + +void VideoDecoder::resyncToI_Frame() { + + syncState=SYNC_TO_CLOSED_GOP; +} + + +void VideoDecoder::doPictureDisplay(PictureArray* pictureArray) { + + + // insert end timestamp to current picture + YUVPicture* pic=pictureArray->getCurrent(); + unsigned int code_type=picture->getCodeType(); + + TimeStamp* startTimeStamp=picture->getStartOfPicStamp(); + + pic->setStartTimeStamp(startTimeStamp); + float rate=mpegVideoHeader->getPictureRate(); + + pictureArray->setPicturePerSecond(rate); + + + + pic->setMpegPictureType(code_type); + + if (syncState < SYNC_HAS_CLOSED_GOP) { + return; + } + if (syncState < SYNC_HAS_I_FRAME_SYNC) { + if (code_type != I_TYPE) { + return; + } + } + if (code_type == I_TYPE) { + YUVPicture* past=pictureArray->getPast(); + YUVPicture* future=pictureArray->getFuture(); + YUVPicture* current=pictureArray->getCurrent(); + + YUVPicture* tmp=past; + past = future; + future = current; + current = tmp; + + pic=past; + + + pictureArray->setPast(past); + pictureArray->setCurrent(current); + pictureArray->setFuture(future); + + if (syncState < SYNC_HAS_I_FRAME_SYNC) { + syncState=SYNC_HAS_I_FRAME_SYNC; + return; + } + if (syncState == SYNC_HAS_P_FRAME_SYNC) { + syncState=SYNC_HAS_FRAME_SYNC; + return; + } + if (syncState == SYNC_HAS_I_FRAME_SYNC) { + syncState=SYNC_HAS_P_FRAME_SYNC; + return; + } + + + + } + + if (code_type == P_TYPE) { + YUVPicture* past=pictureArray->getPast(); + YUVPicture* future=pictureArray->getFuture(); + YUVPicture* current=pictureArray->getCurrent(); + + YUVPicture* tmp=past; + past = future; + future = current; + current = tmp; + + pic = past; + + + + pictureArray->setPast(past); + pictureArray->setCurrent(current); + pictureArray->setFuture(future); + + if (syncState < SYNC_HAS_P_FRAME_SYNC) { + syncState=SYNC_HAS_P_FRAME_SYNC; + return; + } + + } + if (code_type == B_TYPE) { + if (syncState == SYNC_HAS_P_FRAME_SYNC) { + syncState=SYNC_HAS_FRAME_SYNC; + YUVPicture* past=pictureArray->getPast(); + pic=past; + } + /** + Now check for PTS timeStamp error. It seems some encoders + handles this different. + If the P frame has a timeStamp earlier than our B stamp + we swap them. + */ + YUVPicture* pframe=pictureArray->getFuture(); + YUVPicture* bframe=pictureArray->getCurrent(); + + TimeStamp* pTime=pframe->getStartTimeStamp(); + TimeStamp* bTime=bframe->getStartTimeStamp(); + + double pPTS=pTime->getPTSTimeStamp(); + double bPTS=bTime->getPTSTimeStamp(); + if (pPTS < bPTS) { + //cout << "********P/B Frame PTS error -> enable swap and pray"<<endl; + bTime->copyTo(pTime); + } + + + + // we display the current picture + // (already set) + } + + + if (pic == NULL) { + cout << "pic NULL"<<endl; + exit(0); + return; + } + if (syncState < SYNC_HAS_FRAME_SYNC) { + return; + } + + double val=pictureArray->getPicturePerSecond(); + pic->setPicturePerSecond(val); + + TimeStamp* currentStamp=pic->getStartTimeStamp(); + + + frameCounter++; + + if (currentStamp->getPTSFlag()==true) { + frameCounter=0; + } + currentStamp->setVideoFrameCounter(frameCounter); + + + // let plugin "rip" the picture + pictureArray->setYUVPictureCallback(pic); +} + + + + + diff --git a/mpeglib/lib/mpegplay/videoDecoder.h b/mpeglib/lib/mpegplay/videoDecoder.h new file mode 100644 index 00000000..cba45a29 --- /dev/null +++ b/mpeglib/lib/mpegplay/videoDecoder.h @@ -0,0 +1,118 @@ +/* + mpeg I video decoder (derived from mpeg_play) + 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 __VIDEO_H +#define __VIDEO_H + + +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> + +#include "decoderClass.h" +#include "recon.h" +#include "motionVector.h" +#include "slice.h" +#include "proto.h" +#include "../input/inputStream.h" +#include "../output/outputStream.h" +#include "../util/timeStamp.h" +#include "mpegVideoHeader.h" +#include "gop.h" +#include "picture.h" +#include "macroBlock.h" +#include "startCodes.h" + + + +/* Define Parsing error codes. */ + + + +#define SYNC_TO_CLOSED_GOP 1 +#define SYNC_HAS_CLOSED_GOP 2 +#define SYNC_HAS_I_FRAME_SYNC 3 +#define SYNC_HAS_P_FRAME_SYNC 4 +#define SYNC_HAS_FRAME_SYNC 5 + +#define _SYNC_TO_GOP 1 +#define _SYNC_TO_PIC 2 +#define _SYNC_TO_NONE 3 + + + +/* Number of macroblocks to process in one call to mpegVidRsrc. */ + +#define MB_QUANTUM 100 + + +/* Video stream structure. */ +class VideoDecoder { + + + public: + VideoDecoder(MpegVideoStream* mpegVideoStream, + MpegVideoHeader* initSequence); + + ~VideoDecoder(); + int mpegVidRsrc(PictureArray* pictureArray); + + + // ugly callbacks FIX ME! + class MpegVideoStream* mpegVideoStream; + class DecoderClass* decoderClass; + class Recon* recon; + class MotionVector* motionVector; + class Slice* slice; /* Current slice. */ + class MpegVideoHeader* mpegVideoHeader; /* Sequence info in stream */ + class GOP* group; + class Picture* picture; /* Current picture. */ + class MacroBlock* macroBlock; /* Current macroblock. */ + + void resyncToI_Frame(); + + + + private: + + int syncState; + + int ParseSeqHead(); + int ParseGOP(); + int ParsePicture(); + int ParseSlice(); + void doPictureDisplay(PictureArray* pictureArray); + MpegExtension* extension; + int frameCounter; + +}; + + + +/* Declaration of global display pointer. */ + + + +extern int qualityFlag; + + + + +extern int gXErrorFlag; + + + + +#endif /* videoDecoder.h already included */ + + diff --git a/mpeglib/lib/mpgplayer/Makefile.am b/mpeglib/lib/mpgplayer/Makefile.am new file mode 100644 index 00000000..b10b247a --- /dev/null +++ b/mpeglib/lib/mpgplayer/Makefile.am @@ -0,0 +1,31 @@ +# libsplay - Makefile.am + +INCLUDES = $(all_includes) + + +noinst_LTLIBRARIES = libmpgplayer.la + +mpegutildir = $(includedir)/$(THIS_LIB_NAME)/mpegutil + +mpegutil_HEADERS = mpegStreamPlayer.h + +libmpgplayer_la_SOURCES = mpegStreamPlayer.cpp + + + + + + + + + + + + + + + + + + + diff --git a/mpeglib/lib/mpgplayer/mpegStreamPlayer.cpp b/mpeglib/lib/mpgplayer/mpegStreamPlayer.cpp new file mode 100644 index 00000000..133e6319 --- /dev/null +++ b/mpeglib/lib/mpgplayer/mpegStreamPlayer.cpp @@ -0,0 +1,431 @@ +/* + feeds audio/video streams to the decoders + 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 "mpegStreamPlayer.h" +#include "../mpegplay/mpegSystemHeader.h" +#include "../util/syncClockMPEG.h" + +#define _NUKE_BUFFER_SIZE 1024 + +#define _BUFFER_HIGH_WATER 0.8 +#define _BUFFER_LOW_WATER 0.2 + +#define _BUFFER_CHUNK_SIZE 1500 + +#include <iostream> + +using namespace std; + + +MpegStreamPlayer::MpegStreamPlayer(InputStream* input, + OutputStream* output, + DecoderPlugin* audioDecoder, + DecoderPlugin* videoDecoder) { + this->input=input; + this->output=output; + this->audioDecoder=audioDecoder; + this->videoDecoder=videoDecoder; + + /** + here we set the plugins in autoPlay mode. + because we handle all commands over the loopback buffer. + This is necessary, because on start we send play() + but this does not mean that we already have + build this class (divxplugin for example) + See this switch as an implicit play command + */ + + audioDecoder->config("-y","on",NULL); + videoDecoder->config("-y","on",NULL); + + + audioInput=new BufferInputStream(1024*_BUFFER_CHUNK_SIZE, + 1024*200,"audioInput"); + videoInput=new BufferInputStream(1024*_BUFFER_CHUNK_SIZE, + 1024*200,"videoInput"); + audioInput->open("audio loopback"); + videoInput->open("video loopback"); + + audioDecoder->setOutputPlugin(output); + audioDecoder->setInputPlugin(audioInput); + + videoDecoder->setOutputPlugin(output); + videoDecoder->setInputPlugin(videoInput); + + timeStampVideo=new TimeStamp(); + timeStampAudio=new TimeStamp(); + + packetCnt=0; + audioPacketCnt=0; + videoPacketCnt=0; + seekPos=-1; + nukeBuffer=new char[_NUKE_BUFFER_SIZE]; + + syncClock=new SyncClockMPEG(); + syncClock->setSyncMode(__SYNC_AUDIO); + writeToDisk=false; +} + + +MpegStreamPlayer::~MpegStreamPlayer() { + audioInput->close(); + videoInput->close(); + + // everything is prepared for future shutdown + // restart any waiting decoders + // (they exit immediately) + audioDecoder->close(); + videoDecoder->close(); + audioDecoder->waitForStreamState(_STREAM_STATE_EOF); + videoDecoder->waitForStreamState(_STREAM_STATE_EOF); + + delete videoInput; + delete audioInput; + delete nukeBuffer; + delete timeStampVideo; + delete timeStampAudio; + delete syncClock; +} + +int MpegStreamPlayer::getByteDirect() { + unsigned char byte; + if (input->read((char*)&byte,1) != 1) { + return -1; + } + return (int)byte; +} + +int MpegStreamPlayer::processResyncRequest() { + // here is our protocol for resync over the loopback stream + // if out clients are in sync and we set the resync method on the + // stream he sometimes set a "commit" in the stream + // we check if both stream are committed (== clients are in sync and paused) + // if both are in _STREAM_STATE_RESYNC_COMMIT + // we can safley do a seek + // and restart them + + if (seekPos != -1) { + int audioDecoderState=audioDecoder->getStreamState(); + int videoDecoderState=videoDecoder->getStreamState(); + if (audioDecoderState == _STREAM_STATE_RESYNC_COMMIT) { + if (videoDecoderState == _STREAM_STATE_RESYNC_COMMIT) { + Command restart(_COMMAND_RESYNC_END); + input->seek(seekPos); + seekPos=-1; + audioDecoder->insertSyncCommand(&restart); + videoDecoder->insertSyncCommand(&restart); + Command play(_COMMAND_PLAY); + audioDecoder->insertAsyncCommand(&play); + videoDecoder->insertAsyncCommand(&play); + return true; + } + } + } + return false; +} + +/** + according to the header info we read the packets +*/ +int MpegStreamPlayer::processSystemHeader(MpegSystemHeader* mpegSystemHeader) { + int layer=mpegSystemHeader->getLayer(); + + + if (processResyncRequest() == true) { + return false; + } + + if (layer==_PACKET_NO_SYSLAYER) { + syncClock->setSyncMode(__SYNC_NONE); + return insertVideoData(mpegSystemHeader,8192); + } + if (layer==_PACKET_SYSLAYER) { + int packetID=mpegSystemHeader->getPacketID(); + int packetLength=mpegSystemHeader->getPacketLen(); + int subStreamID=mpegSystemHeader->getSubStreamID(); + + switch(packetID>>4) { + case _PAKET_ID_VIDEO>>4: + if((packetID - _PAKET_ID_VIDEO) != + mpegSystemHeader->getVideoLayerSelect()) { + break; + } + + insertVideoData(mpegSystemHeader,packetLength); + //dumpData(mpegSystemHeader); + return true; + //break; + case _PAKET_ID_AUDIO_1>>4: + case _PAKET_ID_AUDIO_2>>4: + if((packetID - _PAKET_ID_AUDIO_1) != + mpegSystemHeader->getAudioLayerSelect()) { + break; + } + insertAudioData(mpegSystemHeader,packetLength); + return true; + } + switch(packetID) { + case _PRIVATE_STREAM_1_ID: + switch(subStreamID) { + case _SUBSTREAM_AC3_ID: + insertAudioData(mpegSystemHeader,packetLength); + //dumpData(mpegSystemHeader); + return true; + default: + printf("unknown private stream id:%8x\n",subStreamID); + } + } + + // if we got here the packet is not useful + // nuke it + nuke(packetLength); + return true; + + + } + cout << "unknown layer"<<endl; + return false; +} + + +void MpegStreamPlayer::nuke(int packetLength) { + int nukeSize; + while(packetLength > 0) { + nukeSize=packetLength; + if (nukeSize > _NUKE_BUFFER_SIZE) { + nukeSize=_NUKE_BUFFER_SIZE; + } + input->read(nukeBuffer,nukeSize); + packetLength-=nukeSize; + } +} + + + +int MpegStreamPlayer::isInit() { + int audioDecoderState=audioDecoder->getStreamState(); + int videoDecoderState=videoDecoder->getStreamState(); + if ( (audioDecoderState != _STREAM_STATE_FIRST_INIT) && + (videoDecoderState != _STREAM_STATE_FIRST_INIT) ) { + return true; + } + return false; +} + +/** + here we make sure that our plugins make + a clean shutdown for a seek request. +*/ +void MpegStreamPlayer::processThreadCommand(Command* command) { + + int id=command->getID(); + + switch(id) { + case _COMMAND_NONE: + break; + case _COMMAND_PAUSE: + case _COMMAND_PLAY: + audioDecoder->insertAsyncCommand(command); + videoDecoder->insertAsyncCommand(command); + break; + case _COMMAND_CLOSE: + audioDecoder->close(); + videoDecoder->close(); + break; + case _COMMAND_SEEK: { + Command cmd1(_COMMAND_PAUSE); + audioDecoder->insertAsyncCommand(&cmd1); + videoDecoder->insertAsyncCommand(&cmd1); + + Command cmd2(_COMMAND_RESYNC_START); + audioDecoder->insertAsyncCommand(&cmd2); + videoDecoder->insertAsyncCommand(&cmd2); + + seekPos=command->getIntArg(); + break; + } + default: + cout << "unknown command id in Command::print"<<endl; + } +} + + +void MpegStreamPlayer::setWriteToDisk(int lwriteToDisk) { + this->writeToDisk=lwriteToDisk; +} + + +int MpegStreamPlayer::getWriteToDisk() { + return writeToDisk; +} + + +int MpegStreamPlayer::hasEnd() { + audioInput->close(); + videoInput->close(); + TimeWrapper::usleep(100000); + if (audioInput->getFillgrade()>0) { + return false; + } + if (videoInput->getFillgrade()>0) { + return false; + } + return true; +} + + + +int MpegStreamPlayer::insertAudioData(MpegSystemHeader* header,int len) { + + audioPacketCnt++; + packetCnt++; + timeStampAudio->setVideoFrameCounter(0); + + timeStampAudio->setPTSFlag(false); + if (header->getPTSFlag()==true) { + + timeStampAudio->setPTSFlag(true); + + double pts=header->getPTSTimeStamp(); + double scr=header->getSCRTimeStamp(); + + if (pts==timeStampAudio->getPTSTimeStamp()) { + cout << "(audio) old PTS == NEW PTS"<<pts<<endl; + } + + timeStampAudio->setSCRTimeStamp(scr); + timeStampAudio->setPTSTimeStamp(pts); + } + + timeStampAudio->setSyncClock(syncClock); + + + finishAudio(len); + + return true; +} + + +int MpegStreamPlayer::insertVideoData(MpegSystemHeader* header,int len) { + + videoPacketCnt++; + packetCnt++; + timeStampVideo->setVideoFrameCounter(0); + timeStampVideo->setPTSFlag(false); + if (header->getPTSFlag()==true) { + timeStampVideo->setPTSFlag(true); + + double pts=header->getPTSTimeStamp(); + double scr=header->getSCRTimeStamp(); + double dts=header->getDTSTimeStamp(); + + if (pts==timeStampVideo->getPTSTimeStamp()) { + cout << "(video) old PTS == NEW PTS"<<pts<<endl; + } + + timeStampVideo->setSCRTimeStamp(scr); + timeStampVideo->setPTSTimeStamp(pts); + timeStampVideo->setDTSTimeStamp(dts); + } + + + timeStampVideo->setSyncClock(syncClock); + + finishVideo(len); + + return true; +} + +int MpegStreamPlayer::insertAudioDataRaw(unsigned char* input, + int len,TimeStamp* stamp) { + audioInput->write((char*)input,len,stamp); + if (writeToDisk==true) { + FILE* audio=fopen("audio.mpg","a+"); + fwrite(input,1,len,audio); + fclose(audio); + } + return true; +} + + +int MpegStreamPlayer::insertVideoDataRaw(unsigned char* input, + int len,TimeStamp* stamp) { + + videoInput->write((char*)input,len,stamp); + if (writeToDisk==true) { + FILE* video=fopen("video.mpg","a+"); + fwrite(input,1,len,video); + fclose(video); + } + + return true; +} + + +void MpegStreamPlayer::dumpData(MpegSystemHeader* mpegSystemHeader) { + + int packetLength=mpegSystemHeader->getPacketLen(); + + unsigned char* packetBuffer= new unsigned char[packetLength]; + input->read((char*)packetBuffer,packetLength); + int cnt; + for(cnt=0;cnt < packetLength;cnt++) { + printf(" %2x ",packetBuffer[cnt]); + if ((cnt+1)%16 == 0) { + printf("\n"); + } + } + + printf("\n"); + cout << "**************************************** packt Dump"<<endl; +} + + + +int MpegStreamPlayer::finishAudio(int len) { + int resyncState=audioDecoder->getStreamState(); + if (resyncState != _STREAM_STATE_RESYNC_COMMIT) { + if (writeToDisk==true) { + char* buf=new char[len]; + len=input->read(buf,len); + insertAudioDataRaw((unsigned char*) buf,len,timeStampAudio); + delete buf; + } else { + audioInput->write(input,len,timeStampAudio); + } + + } else { + //cout << "throw away audio"<<endl; + } + return true; +} + + +int MpegStreamPlayer::finishVideo(int len) { + int resyncState=videoDecoder->getStreamState(); + if (resyncState != _STREAM_STATE_RESYNC_COMMIT) { + if (writeToDisk==true) { + char* buf=new char[len]; + len=input->read(buf,len); + insertVideoDataRaw((unsigned char*)buf,len,timeStampVideo); + delete buf; + } else { + videoInput->write(input,len,timeStampVideo); + } + + } else { + //cout <<"throw away video"<<endl; + } + return true; +} + diff --git a/mpeglib/lib/mpgplayer/mpegStreamPlayer.h b/mpeglib/lib/mpgplayer/mpegStreamPlayer.h new file mode 100644 index 00000000..584e0a22 --- /dev/null +++ b/mpeglib/lib/mpgplayer/mpegStreamPlayer.h @@ -0,0 +1,90 @@ +/* + feeds audio/video streams to the decoders + 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 __MPEGSTREAMPLAYER_H +#define __MPEGSTREAMPLAYER_H + +#include "../decoder/decoderPlugin.h" +#include "../util/syncClock.h" + +class MpegSystemHeader; + +class MpegStreamPlayer { + + protected: + SyncClock* syncClock; + DecoderPlugin* audioDecoder; + DecoderPlugin* videoDecoder; + BufferInputStream* audioInput; + BufferInputStream* videoInput; + OutputStream* output; + InputStream* input; + TimeStamp* timeStampVideo; + TimeStamp* timeStampAudio; + + int packetCnt; + int audioPacketCnt; + int videoPacketCnt; + int seekPos; + int writeToDisk; + + char* nukeBuffer; + + public: + MpegStreamPlayer(InputStream* input, + OutputStream* output, + DecoderPlugin* audioDecoder, + DecoderPlugin* videoDecoder); + ~MpegStreamPlayer(); + + int isInit(); + void processThreadCommand(Command* command); + + // + // Mpeg special functions [START] + // + + int processSystemHeader(MpegSystemHeader* mpegSystemHeader); + int insertAudioData(MpegSystemHeader* header,int len); + int insertVideoData(MpegSystemHeader* header,int len); + + // + // Mpeg special functions [END] + // + + + + int insertAudioDataRaw(unsigned char* input,int len,TimeStamp* stamp); + int insertVideoDataRaw(unsigned char* input,int len,TimeStamp* stamp); + + void dumpData(MpegSystemHeader* mpegSystemHeader); + + void setWriteToDisk(int lwriteToDisk); + int getWriteToDisk(); + + int hasEnd(); + protected: + int processResyncRequest(); + + int getByteDirect(); + void nuke(int byte); + + // useful methods + int finishAudio(int len); + int finishVideo(int len); + +}; + +#endif diff --git a/mpeglib/lib/oggvorbis/Makefile.am b/mpeglib/lib/oggvorbis/Makefile.am new file mode 100644 index 00000000..2fe00b72 --- /dev/null +++ b/mpeglib/lib/oggvorbis/Makefile.am @@ -0,0 +1,32 @@ +# liboggvorbis - Makefile.am + + +INCLUDES = $(all_includes) + + +noinst_LTLIBRARIES = liboggvorbisbase.la + +kmpgincludedir = $(includedir)/$(THIS_LIB_NAME)/oggvorbis + +kmpginclude_HEADERS = ovFramer.h vorbisDecoder.h oggFrame.h \ + vorbisInfo.h + + +liboggvorbisbase_la_SOURCES = ovFramer.cpp vorbisDecoder.cpp \ + oggFrame.cpp vorbisInfo.cpp + + + + + + + + + + + + + + + + diff --git a/mpeglib/lib/oggvorbis/oggFrame.cpp b/mpeglib/lib/oggvorbis/oggFrame.cpp new file mode 100644 index 00000000..ace7dadc --- /dev/null +++ b/mpeglib/lib/oggvorbis/oggFrame.cpp @@ -0,0 +1,29 @@ +/* + here we have an ogg frame. Its still a raw frame. + Copyright (C) 2001 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 "oggFrame.h" + +#ifdef OGG_VORBIS + + +OGGFrame::OGGFrame() : RawFrame(_FRAME_RAW_OGG,0) { + setRemoteData((unsigned char*) &op,sizeof(op)); + +} + +OGGFrame::~OGGFrame() { +} + + + +#endif diff --git a/mpeglib/lib/oggvorbis/oggFrame.h b/mpeglib/lib/oggvorbis/oggFrame.h new file mode 100644 index 00000000..a069a33e --- /dev/null +++ b/mpeglib/lib/oggvorbis/oggFrame.h @@ -0,0 +1,50 @@ +/* + here we have an ogg frame. Its still a raw frame. + Copyright (C) 2001 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 __OGG_FRAME_H +#define __OGG_FRAME_H + + +/** + One Ogg Paket as frame. We pass the datapointer and the size + to the rawFrame and of course, set the PaktedID to: + _FRAME_RAW_OGG +*/ + +#include "../frame/rawFrame.h" + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef OGG_VORBIS + +#include <vorbis/codec.h> + +class OGGFrame : public RawFrame { + + ogg_packet op; + + public: + OGGFrame(); + ~OGGFrame(); + + +}; + +#endif + +#endif + diff --git a/mpeglib/lib/oggvorbis/ovFramer.cpp b/mpeglib/lib/oggvorbis/ovFramer.cpp new file mode 100644 index 00000000..ca3506af --- /dev/null +++ b/mpeglib/lib/oggvorbis/ovFramer.cpp @@ -0,0 +1,128 @@ +/* + frames raw data into Ogg/Vorbis frames. + Copyright (C) 2001 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 "ovFramer.h" + +#define OGG_SYNC_BUFF_SIZE 4096 + + +#define _OV_SETSERIAL 1 +#define _OV_STREAMIN 2 +#define _OV_STREAMOUT 3 + +#include <iostream> + +using namespace std; + + +#ifdef OGG_VORBIS + +OVFramer::OVFramer(OGGFrame* dest):Framer(1) { + if (dest == NULL) { + cout << "OGGFrame NULL in OVFramer"<<endl; + exit(-1); + } + this->dest=dest; + /********** Decode setup ************/ + ogg_sync_init(&oy); /* Now we can read pages */ + + vorbis_state=_OV_SETSERIAL; +} + + +OVFramer::~OVFramer() { + /* OK, clean up the framer */ + ogg_sync_clear(&oy); +} + + +int OVFramer::find_frame(RawDataBuffer* input,RawDataBuffer* store) { + while(input->eof()==true) { + cout << "input eof"<<endl; + return false; + } + + if (vorbis_state == _OV_STREAMOUT) { + if(ogg_stream_packetout(&os,(ogg_packet*)dest->getData())!=1){ + vorbis_state=_OV_STREAMIN; + return false; + } + return true; + } + + // do we have ogg packets in the ogg framer? + if (ogg_sync_pageout(&oy,&og) == 0) { + // no, ok insert some. + int bytes=input->untilend(); + input->inc(bytes); + store->inc(bytes); + ogg_sync_wrote(&oy,bytes); + // and setup the next buffer + /* submit a 4k block to libvorbis' Ogg layer */ + buffer=ogg_sync_buffer(&oy,OGG_SYNC_BUFF_SIZE); + /* override our own dummy buffer with size 1 */ + setRemoteFrameBuffer((unsigned char*)buffer,OGG_SYNC_BUFF_SIZE); + return false; + } + // we have an ogg page + // now try to build an ogg packet + switch(vorbis_state) { + case _OV_SETSERIAL: + /* Get the serial number and set up the rest of decode. */ + /* serialno first; use it to set up a logical stream */ + ogg_stream_init(&os,ogg_page_serialno(&og)); + vorbis_state=_OV_STREAMIN; + // yes we need to put this into the "pager" + // no break. + case _OV_STREAMIN: + if(ogg_stream_pagein(&os,&og)<0){ + /* error; stream version mismatch perhaps */ + fprintf(stderr,"Error reading first page of Ogg bitstream data.\n"); + exit(1); + } + vorbis_state=_OV_STREAMOUT; + break; + default: + cout << "unknow vorbis_state"<<endl; + exit(-1); + } + + return false; +} + +int OVFramer::read_frame(RawDataBuffer* ,RawDataBuffer* ) { + return true; +} + + + +void OVFramer::unsync(RawDataBuffer* store,int lReset) { + if (lReset) { + store->setpos(0); + ogg_sync_reset(&oy); + /* submit a 4k block to libvorbis' Ogg layer */ + buffer=ogg_sync_buffer(&oy,OGG_SYNC_BUFF_SIZE); + /* override our own dummy buffer with size 1 */ + setRemoteFrameBuffer((unsigned char*)buffer,OGG_SYNC_BUFF_SIZE); + } + +} + + +void OVFramer::printPrivateStates() { + cout << "OVFramer::printPrivateStates"<<endl; +} + + +#endif diff --git a/mpeglib/lib/oggvorbis/ovFramer.h b/mpeglib/lib/oggvorbis/ovFramer.h new file mode 100644 index 00000000..4845fddb --- /dev/null +++ b/mpeglib/lib/oggvorbis/ovFramer.h @@ -0,0 +1,69 @@ +/* + frames raw data into Ogg/Vorbis frames. + Copyright (C) 2001 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 __OVFRAMER_H +#define __OVFRAMER_H + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef OGG_VORBIS + +#include <vorbis/codec.h> +#include "../frame/framer.h" +#include "oggFrame.h" + +/** + + This framer works directly on the raw ogg_packet as output + Note: the internal setup makes sure, that we initialize + the ogg stream to the first found logical bitstream. + (For now this should mean: we found vorbis) + When the frame goes into the "HAS" state, you have the ogg + packet in the in the dest struct from the constructor. +*/ + +class OVFramer : public Framer { + + int vorbis_state; + + ogg_sync_state oy; /* sync and verify incoming physical bitstream */ + ogg_stream_state os; /* take physical pages, weld into a logical + stream of packets */ + ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */ + + char *buffer; /* sync buffer from ogg */ + + OGGFrame* dest; /* one raw packet of data for decode */ + + public: + // IMPORTANT: because we use this ptr internally the + // data to op cannot be on the stack! + OVFramer(OGGFrame* dest); + ~OVFramer(); + + + private: + + int find_frame(RawDataBuffer* input,RawDataBuffer* store); + int read_frame(RawDataBuffer* input,RawDataBuffer* store); + + void unsync(RawDataBuffer* store,int lReset); + void printPrivateStates(); + +}; +#endif + +#endif diff --git a/mpeglib/lib/oggvorbis/vorbisDecoder.cpp b/mpeglib/lib/oggvorbis/vorbisDecoder.cpp new file mode 100644 index 00000000..24e9370d --- /dev/null +++ b/mpeglib/lib/oggvorbis/vorbisDecoder.cpp @@ -0,0 +1,135 @@ +/* + converts ogg frames into audioFrames + Copyright (C) 2001 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 "vorbisDecoder.h" + +#ifdef OGG_VORBIS + +#define _VORBIS_NEED_SYNTHHEADER_1 1 +#define _VORBIS_NEED_SYNTHHEADER_2 2 +#define _VORBIS_NEED_SYNTHHEADER_3 3 + +#define _VORBIS_DECODE_SETUP 4 +#define _VORBIS_DECODE_LOOP 5 + +#include <iostream> + +using namespace std; + + +VorbisDecoder::VorbisDecoder() { + vorbis_info_init(&vi); + vorbis_comment_init(&vc); + reset(); +} + + +VorbisDecoder::~VorbisDecoder() { +} + +int VorbisDecoder::hasHeader() { + return (initState>=_VORBIS_DECODE_LOOP); +} + +int VorbisDecoder::decode(RawFrame* rawFrame,AudioFrame* dest) { + + if ((rawFrame == NULL) || (dest == NULL)) { + cout << "VorbisDecoder::decode NULL pointer!"<<endl; + exit(-1); + } + if (rawFrame->getFrameType() != _FRAME_RAW_OGG) { + cout << "VorbisDecoder::decode not _FRAME_RAW_OGG"<<endl; + exit(-1); + } + + ogg_packet* op=(ogg_packet*) rawFrame->getData(); + switch(initState) { + case _VORBIS_NEED_SYNTHHEADER_1: + case _VORBIS_NEED_SYNTHHEADER_2: + case _VORBIS_NEED_SYNTHHEADER_3: + cout << "_VORBIS_NEED_SYNTHHEADER:"<<initState<<endl; + if(vorbis_synthesis_headerin(&vi,&vc,op)<0){ + /* error case; not a vorbis header */ + fprintf(stderr,"This Ogg bitstream does not contain Vorbis " + "audio data.\n"); + exit(1); + } + initState++; + break; + case _VORBIS_DECODE_SETUP: + cout << "_VORBIS_DECODE_SETUP"<<endl; + vorbis_synthesis_init(&vd,&vi); /* central decode state */ + vorbis_block_init(&vd,&vb); /* local state for most of the decode + so multiple block decodes can + proceed in parallel. We could init + multiple vorbis_block structures + for vd here */ + initState=_VORBIS_DECODE_LOOP; + // yes right, we must decode the packet! + // so there is no break here. + case _VORBIS_DECODE_LOOP: { + if(vorbis_synthesis(&vb,op)==0) {/* test for success! */ + vorbis_synthesis_blockin(&vd,&vb); + } else { + cout << "vorbis_synthesis error"<<endl; + exit(0); + } + float **pcm; + /* + + **pcm is a multichannel float vector. In stereo, for + example, pcm[0] is left, and pcm[1] is right. samples is + the size of each channel. Convert the float values + (-1.<=range<=1.) to whatever PCM format and write it out + + */ + int samples=vorbis_synthesis_pcmout(&vd,&pcm); + if (samples > 0) { + int maxSamples=dest->getSize(); + if (samples > maxSamples) { + cout << "more samples in vorbis than we can store"<<endl; + exit(0); + } + dest->clearrawdata(); + dest->setFrameFormat(vi.channels-1,vi.rate); + + if (vi.channels == 2) { + dest->putFloatData(pcm[0],pcm[1],samples); + } else { + dest->putFloatData(pcm[0],NULL,samples); + } + + vorbis_synthesis_read(&vd,samples); /* tell libvorbis how + many samples we + actually consumed */ + return true; + } + + return false; + } + default: + cout << "unknown state in vorbis decoder"<<endl; + exit(0); + } + return false; +} + +void VorbisDecoder::reset() { + initState=_VORBIS_NEED_SYNTHHEADER_1; +} + +void VorbisDecoder::config(const char* ,const char* ,void* ) { + +} + +#endif diff --git a/mpeglib/lib/oggvorbis/vorbisDecoder.h b/mpeglib/lib/oggvorbis/vorbisDecoder.h new file mode 100644 index 00000000..e67a94bb --- /dev/null +++ b/mpeglib/lib/oggvorbis/vorbisDecoder.h @@ -0,0 +1,53 @@ +/* + converts ogg frames into audioFrames + Copyright (C) 2001 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 __VORBISDECODER_H +#define __VORBISDECODER_H + +#include "../frame/audioFrame.h" +#include <string.h> + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef OGG_VORBIS + +#include <vorbis/codec.h> +#include "oggFrame.h" + +class VorbisDecoder { + + vorbis_info vi; /* struct that stores all the static vorbis bitstream + settings */ + vorbis_comment vc; /* struct that stores all the bitstream user comments */ + vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */ + vorbis_block vb; /* local working space for packet->PCM decode */ + + int initState; + + public: + VorbisDecoder(); + ~VorbisDecoder(); + + void reset(); + int hasHeader(); + + int decode(RawFrame* rawFrame,AudioFrame* dest); + void config(const char* key,const char* val,void* ret); +}; + +#endif + +#endif diff --git a/mpeglib/lib/oggvorbis/vorbisInfo.cpp b/mpeglib/lib/oggvorbis/vorbisInfo.cpp new file mode 100644 index 00000000..b71f99c3 --- /dev/null +++ b/mpeglib/lib/oggvorbis/vorbisInfo.cpp @@ -0,0 +1,150 @@ +/* + info about vorbis files. + Copyright (C) 2001 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 "vorbisInfo.h" + +#include <iostream> + +using namespace std; + +#ifdef OGG_VORBIS +#define CHUNKSIZE 4096 + +#define GETINPUT(stream,input) \ + VorbisInfo* info=(VorbisInfo*) stream; \ + FileAccess* input=info->getInput(); + + +size_t fread_func2(void *ptr, size_t size, size_t nmemb, void *stream) { + GETINPUT(stream,input); + + size_t want=size*nmemb; + size_t back=input->read((char*)ptr,want); + return back; +} + + +int fseek_func2(void *stream, ogg_int64_t offset, int whence) { + int ret; + GETINPUT(stream,input); + + if (whence==SEEK_SET) { + ret=input->seek(offset); + info->setSeekPos(offset); + return ret; + } + if (whence==SEEK_CUR) { + ret=input->seek(input->getBytePosition()+offset); + return ret; + } + if (whence==SEEK_END) { + ret=input->seek(input->getByteLength()); + return ret; + } + cout << "hm, strange call"<<endl; + return -1; +} + + +int fclose_func2 (void * stream) { + cout << "fclose_func"<<endl; + GETINPUT(stream,input); + // its handled different in kmpg + // we close the stream if the decoder signals eof. + return true; + +} + + +long ftell_func2 (void *stream) { + GETINPUT(stream,input); + return input->getBytePosition(); +} + + + + +VorbisInfo::VorbisInfo(FileAccess* input) { + this->input=input; + vf=new OggVorbis_File(); + + ov_callbacks callbacks; + + callbacks.read_func = fread_func2; + callbacks.seek_func = fseek_func2; + callbacks.close_func = fclose_func2; + callbacks.tell_func = ftell_func2; + + if(ov_open_callbacks(this, vf, NULL, 0, callbacks) < 0) { + cout << "error ov_open_callbacks"<<endl; + } + + // now init stream + vi=ov_info(vf,-1); + lastSeekPos=0; +} + + +VorbisInfo::~VorbisInfo() { + delete vf; + if (vi != NULL) { + //? + } +} + + +long VorbisInfo::getSeekPosition(int seconds) { + int back=0; + if (vi != NULL) { + lastSeekPos=0; + ov_time_seek(vf,seconds); + back=lastSeekPos; + } + return back; +} + + +long VorbisInfo::getLength() { + int back=0; + if (vi != NULL) { + back = (int) ov_time_total(vf, -1); + } + return back; +} + + + + +void VorbisInfo::print(const char* msg) { + cout << "VorbisInfo:"<<msg<<endl; + cout << "Length (sec):"<<getLength()<<endl; + +} + + +void VorbisInfo::setSeekPos(long pos) { + this->lastSeekPos=pos; +} + + +long VorbisInfo::getSeekPos() { + return lastSeekPos; +} + +FileAccess* VorbisInfo::getInput() { + return input; +} + + + +#endif diff --git a/mpeglib/lib/oggvorbis/vorbisInfo.h b/mpeglib/lib/oggvorbis/vorbisInfo.h new file mode 100644 index 00000000..70c1dc8a --- /dev/null +++ b/mpeglib/lib/oggvorbis/vorbisInfo.h @@ -0,0 +1,76 @@ +/* + info about vorbis files. + Copyright (C) 2001 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 __VORBISINFO_H +#define __VORBISINFO_H + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef OGG_VORBIS + +#include <vorbis/codec.h> +#include <vorbis/vorbisfile.h> +#include "../util/file/fileAccess.h" + +/** + callbacks from vorbisfile +*/ +extern "C" { + +extern size_t fread_func2 (void *ptr,size_t size,size_t nmemb, void *stream); +extern int fseek_func2 (void *stream, ogg_int64_t offset, int whence); +extern int fclose_func2 (void *stream); +extern long ftell_func2 (void *stream); + +} + + + +class VorbisInfo { + + FileAccess* input; + OggVorbis_File* vf; + vorbis_info *vi; + + long lastSeekPos; + + public: + VorbisInfo(FileAccess* input); + ~VorbisInfo(); + + // returns byte positions + long getSeekPosition(int second); + // returns length in seconds + long getLength(); + + void print(const char* msg); + + void setSeekPos(long pos); + long getSeekPos(); + + FileAccess* getInput(); + + +}; + +#endif + +#endif diff --git a/mpeglib/lib/output/Makefile.am b/mpeglib/lib/output/Makefile.am new file mode 100644 index 00000000..e430550e --- /dev/null +++ b/mpeglib/lib/output/Makefile.am @@ -0,0 +1,52 @@ +# liboutplugin - Makefile.am + +INCLUDES = $(all_includes) + + +noinst_LTLIBRARIES = liboutput.la + +noinst_HEADERS = windowOut.h \ + audioData.h audioDataArray.h \ + performance.h yuvDumper.h + +kmpgincludedir = $(includedir)/$(THIS_LIB_NAME)/output + +kmpginclude_HEADERS = outputStream.h pluginInfo.h \ + outPlugin.h dspX11OutputStream.h \ + artsOutputStream.h audioTime.h \ + avSyncer.h threadSafeOutputStream.h + + +liboutput_la_SOURCES = outPlugin.cpp outputStream.cpp \ + dspX11OutputStream.cpp \ + windowOut.cpp \ + audioTime.cpp \ + audioData.cpp audioDataArray.cpp \ + avSyncer.cpp performance.cpp \ + artsOutputStream.cpp \ + pluginInfo.cpp yuvDumper.cpp \ + threadSafeOutputStream.cpp + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mpeglib/lib/output/artsOutputStream.cpp b/mpeglib/lib/output/artsOutputStream.cpp new file mode 100644 index 00000000..571dd258 --- /dev/null +++ b/mpeglib/lib/output/artsOutputStream.cpp @@ -0,0 +1,205 @@ +/* + output to arts + 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 "artsOutputStream.h" +#include "windowOut.h" +#include "avSyncer.h" +#include "../util/abstract/threadQueue.h" + + +ArtsOutputStream::ArtsOutputStream(void (*streamStateChangeCallback)(void*)) { + + audioTime=new AudioTime(); + x11Window=new WindowOut(); + privateBufferSize=1024*32; + + // we can dynamically change the buffer size, + // over a config switch in avSyncer + // but for now this should be ok + // Arts must pass the total size of the audiobuffer + // from /dev/dsp + connected nodes + // or arts need a video interface + stream=new BufferInputStream(privateBufferSize,1024*64,"artsLoopback"); + avSyncer=new AVSyncer(privateBufferSize); + + // with the ThreadQueue we protect all calls to the + // x11 output. This is necessary, because arts may call + // in the future "config" entries to switch the video + // mode (full,double,desktop) + threadQueue=new ThreadQueue(); + // we set it, but its never used ! + this->streamStateChangeCallback=streamStateChangeCallback; +} + + +ArtsOutputStream::~ArtsOutputStream() { + delete stream; + delete audioTime; + delete x11Window; + delete avSyncer; + delete threadQueue; +} + + + + +int ArtsOutputStream::audioSetup(int freq,int stereo, + int sign,int big,int sampleSize) { + audioTime->setFormat(stereo,sampleSize,freq,sign,big); + avSyncer->audioSetup(freq,stereo,sign,big,sampleSize); + + OutputStream::audioSetup(freq,stereo,sign,big,sampleSize); + + return true; +} + +AudioTime* ArtsOutputStream::getAudioTime() { + return audioTime; +} + + +void ArtsOutputStream::audioClose() { + audioTime->setTime(0.0); + // if we close this stream the thread is kicked out. + stream->close(); + stream->clear(); + avSyncer->audioClose(); +} + +void ArtsOutputStream::audioFlush() { + OutputStream::audioFlush(); + audioClose(); +} + + +void ArtsOutputStream::audioOpen() { + audioTime->setTime(0.0); + // if we close this stream the thread is kicked out. + stream->open("artsLoopback"); +} + + +int ArtsOutputStream::audioPlay(TimeStamp* startStamp, + TimeStamp* endStamp,char *buffer, int size) { + int write=size; + + + // we call this for stream state handling + OutputStream::audioPlay(startStamp,endStamp,buffer,size); + + // store sync information + avSyncer->audioPlay(startStamp,endStamp,buffer,size); + + + // here we simulate our own blocking audio device + if (stream->isOpen()==false) { + audioTime->sleepWrite(size); + } else { + write=stream->write(buffer,size,startStamp); + } + return write; + +} + + +int ArtsOutputStream::read(char** buffer,int bytes) { + int back=stream->readRemote(buffer,bytes); + return back; +} + + +void ArtsOutputStream::forwardReadPtr(int bytes) { + audioTime->forwardTime(bytes); + stream->forwardReadPtr(bytes); + +} + + + + +int ArtsOutputStream::getPreferredDeliverSize() { + return avSyncer->getPreferredDeliverSize(); +} + + +int ArtsOutputStream::openWindow(int width, int height,const char *title) { + threadQueue->waitForExclusiveAccess(); + int back=x11Window->openWindow(width,height,title); + threadQueue->releaseExclusiveAccess(); + + return back; +} + +int ArtsOutputStream::x11WindowId() { + return x11Window->x11WindowId(); +} + +void ArtsOutputStream::closeWindow() { + threadQueue->waitForExclusiveAccess(); + x11Window->closeWindow(); + threadQueue->releaseExclusiveAccess(); +} + +void ArtsOutputStream::flushWindow() { + threadQueue->waitForExclusiveAccess(); + x11Window->flushWindow(); + threadQueue->releaseExclusiveAccess(); +} + + +PictureArray* ArtsOutputStream::lockPictureArray() { + PictureArray* back; + threadQueue->waitForExclusiveAccess(); + back=x11Window->lockPictureArray(); + threadQueue->releaseExclusiveAccess(); + return back; +} + + +void ArtsOutputStream::unlockPictureArray(PictureArray* pictureArray) { + + + YUVPicture* pic=pictureArray->getYUVPictureCallback(); + if (avSyncer->syncPicture(pic)==false) { + return; + } + threadQueue->waitForExclusiveAccess(); + x11Window->unlockPictureArray(pictureArray); + threadQueue->releaseExclusiveAccess(); + +} + +int ArtsOutputStream::getBufferFillgrade() { + return stream->getFillgrade(); +} + +int ArtsOutputStream::getFrameusec() { + return avSyncer->getFrameusec(); +} + + + +void ArtsOutputStream::setAudioBufferSize(int size) { + avSyncer->setAudioBufferSize(privateBufferSize+size); +} + + +void ArtsOutputStream::config(const char* key,const char* value, + void* user_data) { + + threadQueue->waitForExclusiveAccess(); + avSyncer->config(key,value,user_data); + x11Window->config(key,value,user_data); + threadQueue->releaseExclusiveAccess(); +} diff --git a/mpeglib/lib/output/artsOutputStream.h b/mpeglib/lib/output/artsOutputStream.h new file mode 100644 index 00000000..757022fd --- /dev/null +++ b/mpeglib/lib/output/artsOutputStream.h @@ -0,0 +1,123 @@ +/* + output to arts + 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 __ARTSOUTPUTSTREAM_H +#define __ARTSOUTPUTSTREAM_H + +#include "outputStream.h" +#include "../input/bufferInputStream.h" +#include "audioTime.h" + + +class WindowOut; +class AVSyncer; + + + + +/** + a word about synchronisation: Arts currently has not asynchronous + starting of stream, which means, poll if stream is initialized + or set a callbackfunction. + + mpeglib is threaded and would not have much problems + with a "callback" but currently we only support blocking wait + for initilisation. + + I think, if people realize that smooth mixing of streams + is impossible(because of the blocking start behaviour), + this will become a desired feature :-) + +*/ + + +/** + This class offers a blocking device, its behaviour is similar + to /dev/dsp we use a buffer to store the pcm data, if + we open/close the buffer the stored data is removed + and the blocking thread is "kicked" + + Arts must first wait for an init signal. it has its own + method to check for eof. during seek we close this + device, after seek we reopen it. + + close and open have the same functionality, they simply + clear the buffer. +*/ + + + +class ArtsOutputStream : public OutputStream { + + BufferInputStream* stream; + AudioTime* audioTime; + + void (*streamStateChangeCallback)(void*); + + WindowOut* x11Window; + AVSyncer* avSyncer; + int privateBufferSize; + class ThreadQueue* threadQueue; + + public: + ArtsOutputStream(void (*streamStateChangeCallback)(void*)); + ~ArtsOutputStream(); + + // Audio part + + int audioSetup(int freq,int stereo,int sign,int big,int sampleSize); + void audioClose(); + void audioOpen(); + void audioFlush(); + + int audioPlay(TimeStamp* startStamp, + TimeStamp* endStamp,char *buffer, int size); + + + AudioTime* getAudioTime(); + + int getPreferredDeliverSize(); + + // Video part + + int openWindow(int width, int height,const char *title); + int x11WindowId(); + void closeWindow(); + void flushWindow(); + + PictureArray* lockPictureArray(); + void unlockPictureArray(PictureArray* pictureArray); + + int getFrameusec(); + + void config(const char* key,const char* value,void* user_data); + + // Remote read extension + + int read(char** buffer,int bytes); + void forwardReadPtr(int bytes); + + // buffer control + int getBufferFillgrade(); + + // sync control + void setAudioBufferSize(int size); + + private: + void sendSignal(int state,int value); + void initStream(); + +}; +#endif diff --git a/mpeglib/lib/output/audioData.cpp b/mpeglib/lib/output/audioData.cpp new file mode 100644 index 00000000..d28e74cf --- /dev/null +++ b/mpeglib/lib/output/audioData.cpp @@ -0,0 +1,100 @@ +/* + describes a paket oriented audioData, because Im fed up + 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 "audioData.h" + +#include <iostream> + +using namespace std; + +AudioData::AudioData() { + pcmLen=0; + audioTime=new AudioTime(); + start=new TimeStamp(); + end=new TimeStamp(); + writeStamp=new TimeStamp(); +} + + +AudioData::~AudioData() { + delete audioTime; + delete start; + delete end; + delete writeStamp; +} + + +void AudioData::copyTo(AudioData* dest) { + dest->setAudioTime(getAudioTime()); + dest->setStart(getStart()); + dest->setEnd(getEnd()); + dest->setWrite(getWrite()); + dest->setPCMLen(getPCMLen()); +} + + +int AudioData::getPCMLen(){ + return pcmLen; +} + +void AudioData::setPCMLen(int pcmLen) { + this->pcmLen=pcmLen; +} + +void AudioData::setAudioTime(AudioTime* aTime) { + aTime->copyTo(audioTime); +} + +AudioTime* AudioData::getAudioTime() { + return audioTime; +} + + +void AudioData::setStart(TimeStamp* s) { + s->copyTo(start); +} + + +TimeStamp* AudioData::getStart() { + return start; +} + +void AudioData::setEnd(TimeStamp* e) { + e->copyTo(end); +} + + +TimeStamp* AudioData::getEnd() { + return end; +} + +void AudioData::setWrite(TimeStamp* e) { + e->copyTo(writeStamp); +} + + +TimeStamp* AudioData::getWrite() { + return writeStamp; +} + + + +void AudioData::print() { + cout << "AudioData::print [START]"<<endl; + start->print("audioData start"); + end->print("audioData end"); + cout << "pcmlen:"<<pcmLen<<endl; + cout << "AudioData::print [END]"<<endl; +} diff --git a/mpeglib/lib/output/audioData.h b/mpeglib/lib/output/audioData.h new file mode 100644 index 00000000..ff6c8242 --- /dev/null +++ b/mpeglib/lib/output/audioData.h @@ -0,0 +1,71 @@ +/* + describes a paket oriented audioData, because Im fed up + 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 __AUDIODATA_H +#define __AUDIODATA_H + +#include "../util/timeStamp.h" +#include "audioTime.h" + + +#define _AUDIODATA_MAX_SIZE 8192 + + +/** + My attempt to encapsulate all this stupid things which deals + with timing, synchronisation, length, stamps and everything + unimaginable else. +*/ + + + +class AudioData { + + + AudioTime* audioTime; + TimeStamp* start; + TimeStamp* end; + TimeStamp* writeStamp; + + int pcmLen; + + public: + AudioData(); + ~AudioData(); + + void copyTo(AudioData* dest); + + + int getPCMLen(); + void setPCMLen(int pcmLen); + + void setAudioTime(AudioTime* audioTime); + AudioTime* getAudioTime(); + + void setStart(TimeStamp* start); + TimeStamp* getStart(); + + void setWrite(TimeStamp* writeStamp); + TimeStamp* getWrite(); + + + void setEnd(TimeStamp* end); + TimeStamp* getEnd(); + + void print(); +}; +#endif + + + diff --git a/mpeglib/lib/output/audioDataArray.cpp b/mpeglib/lib/output/audioDataArray.cpp new file mode 100644 index 00000000..a0b91ec1 --- /dev/null +++ b/mpeglib/lib/output/audioDataArray.cpp @@ -0,0 +1,138 @@ +/* + fifo for audioData + 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 "audioDataArray.h" + +#include <iostream> + +using namespace std; + + +AudioDataArray::AudioDataArray(int entries) { + + this->entries=entries; + fillgrade=0; + readPos=0; + writePos=0; + pcmSum=0; + abs_thread_mutex_init(&writeInMut); + abs_thread_mutex_init(&changeMut); + + audioDataArray=new AudioData*[entries]; + + int i; + for(i=0;i<entries;i++) { + audioDataArray[i]=new AudioData(); + } + + abs_thread_mutex_init(&writeInMut); + abs_thread_mutex_init(&changeMut); + +} + +AudioDataArray::~AudioDataArray() { + + int i; + for(i=0;i<entries;i++) { + delete audioDataArray[i]; + } + + delete audioDataArray; + + abs_thread_mutex_destroy(&writeInMut); + abs_thread_mutex_destroy(&changeMut); + +} + + + + +void AudioDataArray::lockStampArray() { + + abs_thread_mutex_lock(&changeMut); + abs_thread_mutex_lock(&writeInMut); + abs_thread_mutex_unlock(&changeMut); + +} + + +void AudioDataArray::unlockStampArray() { + abs_thread_mutex_unlock(&writeInMut); +} + + +void AudioDataArray::internalForward() { + pcmSum=pcmSum-readAudioData()->getPCMLen(); + readPos++; + fillgrade--; + if (readPos == entries-1) { + readPos=0; + } +} + +int AudioDataArray::getPCMSum() { + return pcmSum; +} + + + +int AudioDataArray::insertAudioData(AudioData* src) { + lockStampArray(); + + int back=true; + src->copyTo(audioDataArray[writePos]); + pcmSum+=src->getPCMLen(); + + writePos++; + fillgrade++; + if (writePos == entries-1) { + writePos=0; + } + if (fillgrade == entries) { + cout <<" Audiodata::array overfull forward"<<endl; + internalForward(); + back=false; + } + unlockStampArray(); + return back; +} + + +AudioData* AudioDataArray::readAudioData() { + return audioDataArray[readPos]; +} + + +int AudioDataArray::getFillgrade() { + return fillgrade; +} + + +void AudioDataArray::forward() { + lockStampArray(); + internalForward(); + unlockStampArray(); +} + + +void AudioDataArray::clear() { + lockStampArray(); + fillgrade=0; + readPos=0; + writePos=0; + pcmSum=0; + unlockStampArray(); +} + + diff --git a/mpeglib/lib/output/audioDataArray.h b/mpeglib/lib/output/audioDataArray.h new file mode 100644 index 00000000..81cebfee --- /dev/null +++ b/mpeglib/lib/output/audioDataArray.h @@ -0,0 +1,55 @@ +/* + fifo for audioData + 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 __AUDIODATAARRAY_H +#define __AUDIODATAARRAY_H + +#include "../util/abstract/abs_thread.h" +#include "audioData.h" + + +class AudioDataArray { + + AudioData** audioDataArray; + int fillgrade; + int entries; + + int writePos; + int readPos; + int pcmSum; + + public: + AudioDataArray(int entries); + ~AudioDataArray(); + + int insertAudioData(AudioData* src); + AudioData* readAudioData(); + + int getFillgrade(); + int getPCMSum(); + void forward(); + void clear(); + + private: + void lockStampArray(); + void unlockStampArray(); + void internalForward(); + + abs_thread_mutex_t writeInMut; + abs_thread_mutex_t changeMut; + + + +}; +#endif diff --git a/mpeglib/lib/output/audioTime.cpp b/mpeglib/lib/output/audioTime.cpp new file mode 100644 index 00000000..f4ed2e9c --- /dev/null +++ b/mpeglib/lib/output/audioTime.cpp @@ -0,0 +1,154 @@ +/* + defines the format of an audio stream + 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 "audioTime.h" + +#include <iostream> + +using namespace std; + + +AudioTime::AudioTime(){ + time=0.0; +} + + +AudioTime::~AudioTime() { +} + + +void AudioTime::setFormat(int stereo,int samplesize,int speed,int sign, int bigendian) { + setStereo(stereo); + setSampleSize(samplesize); + setSpeed(speed); + setSign(sign); + setBigendian(bigendian); +} + + +int AudioTime::getStereo() { + return stereo; +} + + +int AudioTime::getSampleSize() { + return samplesize; +} + + +int AudioTime::getSpeed() { + return speed; +} + +int AudioTime::getSign() { + return _sign; +} + +int AudioTime::getBigendian() { + return _bigendian; +} + +void AudioTime::setStereo(int stereo) { + this->stereo=stereo; +} + + +void AudioTime::setSampleSize(int samplesize) { + this->samplesize=samplesize; +} + + +void AudioTime::setSpeed(int speed) { + this->speed=speed; +} + +void AudioTime::setSign(int sign) { + this->_sign=sign; +} + +void AudioTime::setBigendian(int bigendian) { + this->_bigendian = bigendian; +} + +float AudioTime::getTime() { + return time; +} + + +void AudioTime::setTime(float time) { + this->time=time; +} + + +void AudioTime::forwardTime(int bytes){ + time+=calculateTime(bytes); +} + + +float AudioTime::calculateTime(int bytes) { + float back=0; + + bytes=bytes/(samplesize/8); + if (stereo==1) { + bytes=bytes/2; + } + if (speed != 0) { + back=(float)bytes/(float)speed; + } + return back; +} + + +/** + How much byte we need for time usecs? +*/ +int AudioTime::calculateBytes(float time) { + float back=time; + + if (speed != 0) { + back=back*(float)speed; + } + back=back*(float)(samplesize/8); + if (stereo==1) { + back=back*2.0; + } + return (int)back; +} + + + +void AudioTime::sleepWrite(int size) { + timeval_t time; + float timeLength=calculateTime(size); + time.tv_sec=(long)timeLength; + time.tv_usec=(long)(1000000*(timeLength-time.tv_sec)); + TimeWrapper::usleep(&time); +} + + +void AudioTime::print() { + cout << "AudioTime-begin-"<<endl; + cout << "stereo:"<<getStereo()<<" sampleSize:"<<getSampleSize() + << " speed: "<<getSpeed()<<endl; + + cout << "AudioTime-end-"<<endl; + +} + + +void AudioTime::copyTo(AudioTime* dest) { + dest->setStereo(getStereo()); + dest->setSampleSize(getSampleSize()); + dest->setSpeed(getSpeed()); +} + diff --git a/mpeglib/lib/output/audioTime.h b/mpeglib/lib/output/audioTime.h new file mode 100644 index 00000000..3b16bb02 --- /dev/null +++ b/mpeglib/lib/output/audioTime.h @@ -0,0 +1,68 @@ +/* + defines the format of an audio stream + 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 __AUDIOTIME_H +#define __AUDIOTIME_H + +#include "../util/timeWrapper.h" + +class AudioTime { + + int stereo; + int samplesize; + int speed; + int _sign; + int _bigendian; + float time; + + public: + AudioTime(); + ~AudioTime(); + + //cd-quality:true,16,44100 + void setFormat(int stereo,int samplesize,int speed,int sign=true, int bigendian=false); + + int getStereo(); + int getSampleSize(); + int getSpeed(); + int getSign(); + int getBigendian(); + + void setStereo(int stereo); + void setSampleSize(int samplesize); + void setSpeed(int speed); + void setSign(int sign); + void setBigendian(int bigendian); + + + float getTime(); + void setTime(float time); + void forwardTime(int bytes); + + // do not modify the internal time + float calculateTime(int bytes); + int calculateBytes(float time); + + void sleepWrite(int size); + + + void copyTo(AudioTime* audioTime); + void print(); + +}; + + + +#endif diff --git a/mpeglib/lib/output/avSyncer.cpp b/mpeglib/lib/output/avSyncer.cpp new file mode 100644 index 00000000..ca12a21e --- /dev/null +++ b/mpeglib/lib/output/avSyncer.cpp @@ -0,0 +1,386 @@ +/* + encapsulates the syncing methods, to use it in other classes + 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 "avSyncer.h" + +#include "audioDataArray.h" +#include "performance.h" + +#include <iostream> + +using namespace std; + +AVSyncer::AVSyncer(int bufferSize) { + oneFrameTime=0; + onePicFrameInAudioBytes=8192; + this->bufferSize=bufferSize; + + abs_thread_mutex_init(&writeInMut); + abs_thread_mutex_init(&changeMut); + + + audioDataInsert=new AudioData(); + audioDataArray=new AudioDataArray(400); + audioDataCurrent=audioDataArray->readAudioData(); + + startAudio=new TimeStamp(); + endAudio=new TimeStamp(); + audioTime=new AudioTime(); + lAudioRunning=false; + performance=new Performance(); + + waitTime=new TimeStamp(); + diffTime=new TimeStamp(); + videoTimeStamp=new TimeStamp(); + + lPerformance=false; + lavSync=true; + + +} + + +AVSyncer::~AVSyncer() { + delete audioDataArray; + delete audioDataInsert; + delete audioTime; + delete startAudio; + delete endAudio; + abs_thread_mutex_destroy(&writeInMut); + abs_thread_mutex_destroy(&changeMut); + delete waitTime; + delete diffTime; + delete performance; + delete videoTimeStamp; +} + + + +int AVSyncer::audioSetup(int frequency,int stereo,int sign, + int big,int sixteen) { + audioTime->setFormat(stereo,sixteen,frequency,sign,big); + setAudioRunning(true); + return true; +} + + +int AVSyncer::audioPlay(TimeStamp* startStamp, + TimeStamp* endStamp,char* , int size) { + + + + + audioDataInsert->setStart(startStamp); + audioDataInsert->setEnd(endStamp); + audioDataInsert->setAudioTime(audioTime); + audioDataInsert->setPCMLen(size); + + setAudioSync(audioDataInsert); + return size; +} + + + +void AVSyncer::audioClose(void) { + lockSyncData(); + setAudioRunning(false); + audioDataArray->clear(); + unlockSyncData(); +} + + + + + +int AVSyncer::getPreferredDeliverSize() { + return onePicFrameInAudioBytes; +} + + + +int AVSyncer::getFrameusec() { + lockSyncData(); + int back=oneFrameTime; + unlockSyncData(); + return back; +} + +void AVSyncer::setAudioBufferSize(int size) { + bufferSize=size; +} + + +void AVSyncer::config(const char* key,const char* value,void*) { + if (strcmp(key,"-s")==0) { + if (strcmp(value,"on")==0) { + lavSync=true; + cout << "******** lavSync on"<<endl; + } else { + lavSync=false; + cout << "******** lavSync off"<<endl; + } + } + if (strcmp(key,"-p")==0) { + cout << "setting perfomance test true"<<endl; + lPerformance=true; + } + +} + + + +void AVSyncer::setAudioSync(AudioData* audioData) { + + lockSyncData(); + + if (onePicFrameInAudioBytes <= 0) { + // no video present, we cannot calculate audio + // pcm length + //cout << "no video present, we cannot calculate audio pcm length"<<endl; + unlockSyncData(); + return; + } + // buffersize is the simulated size of /dev/dsp + + + + // we implement a fifo hopefully + // we check the right audio pts time out + // when /dev/dsp acutally plays it. + audioDataArray->insertAudioData(audioData); + int pcmSum=audioDataArray->getPCMSum(); + if (pcmSum >= bufferSize) { + audioDataCurrent=audioDataArray->readAudioData(); + setAudioRunning(true); + audioDataArray->forward(); + } + TimeStamp* startAudio=audioDataCurrent->getStart(); + int lpts=startAudio->getPTSFlag(); + + if (lpts==true) { + SyncClock* syncClock=startAudio->getSyncClock(); + if (syncClock != NULL) { + double pts=startAudio->getPTSTimeStamp(); + double scr=startAudio->getSCRTimeStamp(); + + syncClock->syncAudio(pts,scr); + + } else { + cout <<"syncClock == NULL (audio)"<<endl; + } + } else { + //cout << "lpts is false"<<endl; + } + unlockSyncData(); + +} + + + +int AVSyncer::syncPicture(YUVPicture* syncPic) { + if (syncPic == NULL) { + cout << "syncPic == NULL"<<endl; + return false; + } + + float picPerSec=syncPic->getPicturePerSecond(); + int oneFrameTime=0; + + if (picPerSec > 0.0) { + oneFrameTime=(int) (1000000.0/picPerSec); + } else { + syncPic->print("picPersec is 0"); + return true; + } + + if (lPerformance==true) { + waitTime->set(0,0); + syncPic->setWaitTime(waitTime); + performance->incPictureCount(); + return true; + } + + int lpacketSync=true; + + videoTimeStamp->gettimeofday(); + diffTime->minus(videoTimeStamp,videoTimeStamp); + + + if (lavSync==false) { + if (videoTimeStamp->isNegative()) { + diffTime->gettimeofday(); + diffTime->addOffset(0,oneFrameTime); + cout << "skip time based"<<endl; + return false; + } + } + + + + videoTimeStamp->copyTo(waitTime); + + TimeStamp* earlyTime=syncPic->getEarlyTime(); + earlyTime->set(0,0); + + + if (lavSync) { + + lpacketSync=avSync(syncPic->getStartTimeStamp(), + waitTime, + earlyTime, + syncPic->getPicturePerSecond()); + + } + + + + + if (lpacketSync == false) { + //cout << "skip"<<endl; + diffTime->gettimeofday(); + diffTime->addOffset(0,oneFrameTime); + return false; + } + + syncPic->setWaitTime(waitTime); + + if (lavSync) { + waitTime->minus(videoTimeStamp,waitTime); + if (waitTime->isPositive()) { + diffTime->addOffset(waitTime); + } + } + diffTime->addOffset(0,oneFrameTime); + return true; + + +} + + + +/** + Heart of the sync routine is here! + + Currently its more in a state of "try/test" + + +*/ +int AVSyncer::avSync(TimeStamp* startVideo, + TimeStamp* waitTime, + TimeStamp* earlyTime, + float picPerSec ) { + + + double videoStartPTSTime=startVideo->getPTSTimeStamp(); + double videoStartSCRTime=startVideo->getSCRTimeStamp(); + int videoFrameCounter=startVideo->getVideoFrameCounter(); + double frameTime=0.0; + + + + lockSyncData(); + if (picPerSec > 0) { + oneFrameTime=(long)(1000000.0/picPerSec); + frameTime=1.0/picPerSec; + onePicFrameInAudioBytes=audioTime->calculateBytes(1.0/picPerSec); + + } + if (lAudioRunning==false) { + waitTime->set(0,oneFrameTime); + + unlockSyncData(); + return true; + } + + + /* + startAudio->print("audio"); + startVideo->print("video"); + */ + + + + + + + /* + cout << "audioStartAudioPacketNrMinor:"<<audioStartAudioPacketNrMinor<<endl; + cout << "audioStartPTSTime:"<<audioStartPTSTime<<endl; + cout << "audioStartEndPTSTime:"<<audioStartEndPTSTime<<endl; + cout << "videoStartPTSTime:"<<videoStartPTSTime<<endl; + */ + + + /** + Here we make sure that we sync over an audio packet only one + time. + */ + + waitTime->set(0,0); + SyncClock* syncClock=startVideo->getSyncClock(); + int back=false; + double addPts=videoFrameCounter*frameTime; + double pts=videoStartPTSTime+addPts; + + if (syncClock != NULL) { + + back=syncClock->syncVideo(pts, + videoStartSCRTime,earlyTime,waitTime); + } else { + cout << "syncClock == NULL (video)"<<endl; + } + unlockSyncData(); + + if (back==true) { + //earlyTime->print("earlyTime"); + earlyTime->waitForIt(); + /* + double tmp; + double time=syncClock->getPTSTime(&tmp); + cout << "time after wait:"<<time<<endl; + */ + } + /* + if (back == false) { + cout <<"real pts:"<<videoStartPTSTime + <<" calc pts"<<pts + <<" frameNo:"<<videoFrameCounter + <<" frameTime:"<<frameTime<<endl; + } + */ + + + + return back; + +} + +int AVSyncer::getAudioRunning() { + return lAudioRunning; +} + + +void AVSyncer::setAudioRunning(int lAudioRunning) { + this->lAudioRunning=lAudioRunning; +} + + +void AVSyncer::lockSyncData() { + abs_thread_mutex_lock(&changeMut); + abs_thread_mutex_lock(&writeInMut); + abs_thread_mutex_unlock(&changeMut); +} + +void AVSyncer::unlockSyncData() { + abs_thread_mutex_unlock(&writeInMut); +} diff --git a/mpeglib/lib/output/avSyncer.h b/mpeglib/lib/output/avSyncer.h new file mode 100644 index 00000000..b5a7ae7d --- /dev/null +++ b/mpeglib/lib/output/avSyncer.h @@ -0,0 +1,96 @@ +/* + encapsulates the syncing methods, to use it in other classes + 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 __AVSYNCER_H +#define __AVSYNCER_H + +#include <stdlib.h> + +#include "../util/render/yuvPicture.h" +#include "../util/syncClock.h" +#include "audioTime.h" + +class Performance; +class AudioDataArray; +class AudioData; + +class AVSyncer { + + AudioData* audioDataInsert; + AudioData* audioDataCurrent; + AudioDataArray* audioDataArray; + Performance* performance; + + AudioTime* audioTime; + int onePicFrameInAudioBytes; + int oneFrameTime; + + int lAudioRunning; + + abs_thread_mutex_t writeInMut; + abs_thread_mutex_t changeMut; + + + int bufferSize; + + TimeStamp* startAudio; + TimeStamp* endAudio; + + TimeStamp* videoTimeStamp; + TimeStamp* diffTime; + TimeStamp* waitTime; + + int lPerformance; + int lavSync; + int lastAudioPacket; + double pts_jitter; + + + public: + AVSyncer(int bufferSize); + ~AVSyncer(); + + // audio + int audioSetup(int frequency,int stereo,int sign,int big,int sixteen); + int audioPlay(TimeStamp* startStamp, + TimeStamp* endStamp,char *buffer, int size); + void audioClose(void); + void setAudioBufferSize(int size); + + int getPreferredDeliverSize(); + + // video + int getFrameusec(); + int syncPicture(YUVPicture* syncPic); + + void config(const char* key,const char* value,void* user_data); + + + + private: + int getAudioRunning(); + void setAudioRunning(int lAudioRunning); + + void lockSyncData(); + void unlockSyncData(); + void setAudioSync(AudioData* audioData); + + // methods which belong not to the OutputStream interface + int avSync(TimeStamp* startVideoStamp, + TimeStamp* waitTime, + TimeStamp* earlyTime, + float picPerSec); + +}; +#endif diff --git a/mpeglib/lib/output/dspX11OutputStream.cpp b/mpeglib/lib/output/dspX11OutputStream.cpp new file mode 100644 index 00000000..05503ffa --- /dev/null +++ b/mpeglib/lib/output/dspX11OutputStream.cpp @@ -0,0 +1,236 @@ +/* + concret OutputClass + 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 "dspX11OutputStream.h" +#include "../util/audio/dspWrapper.h" +#include "windowOut.h" +#include "avSyncer.h" +#include "yuvDumper.h" + +#include <iostream> + +using namespace std; + +DspX11OutputStream::DspX11OutputStream(int bufferSize) { + dspWrapper=new DSPWrapper(); + x11Window=new WindowOut(); + avSyncer=new AVSyncer(bufferSize); + yuvDumper=new YUVDumper(); + + audioTime=new AudioTime(); + + lPerformance=false; + lneedInit=false; + lVideoInit=false; + lBufferSet=false; + lYUVDump=false; +} + + +DspX11OutputStream::~DspX11OutputStream() { + delete dspWrapper; + delete x11Window; + + delete avSyncer; + delete audioTime; + delete yuvDumper; +} + + + +int DspX11OutputStream::audioSetup(int frequency,int stereo, + int sign,int big,int sixteen) { + + dspWrapper->audioSetup(stereo,sixteen,sign,big,frequency); + audioTime->setFormat(stereo,sixteen,frequency,sign,big); + avSyncer->audioSetup(frequency,stereo,sign,big,sixteen); + if (dspWrapper->isOpenDevice() == true) { + if (lBufferSet==false) { + int size=dspWrapper->getAudioBufferSize(); + avSyncer->setAudioBufferSize(size); + } + } + return true; +} + + +void DspX11OutputStream::audioClose(void) { + avSyncer->audioClose(); + dspWrapper->closeDevice(); +} + + +void DspX11OutputStream::audioOpen() { + if (dspWrapper->isOpenDevice() == false) { + dspWrapper->openDevice(); + if (lBufferSet==false) { + int size=dspWrapper->getAudioBufferSize(); + avSyncer->setAudioBufferSize(size); + } + } +} + + + + +int DspX11OutputStream::audioPlay(TimeStamp* startStamp, + TimeStamp* endStamp,char *buffer, int size) { + + if (lneedInit) { + cout << "FIXME. work on audioFrames!!"<<endl; + lneedInit=false; + } + + if (lPerformance==false) { + // + // Now feed data smoothly into the dsp/avSyncer + // + int pos=0; + int rest=size; + int inc=getPreferredDeliverSize(); + int len; + + while (rest > 0) { + len=rest; + if (len>inc) { + len=inc; + } + if (dspWrapper->isOpenDevice()) { + if (dspWrapper->audioPlay(buffer,len) != len) { + cout << "write error to dsp"<<endl; + lneedInit=true; + return size-rest; + } + } + + avSyncer->audioPlay(startStamp,endStamp,buffer,len); + buffer+=len; + rest-=len; + } + return size; + } else { + return size; + } +} + + +int DspX11OutputStream::getPreferredDeliverSize() { + if (avSyncer->getPreferredDeliverSize() <= 500) { + return 500; + } + return avSyncer->getPreferredDeliverSize(); +} + + +int DspX11OutputStream::openWindow(int width, int height,const char *title) { + int back=x11Window->openWindow(width,height,title); + setOutputInit(true); + if (lYUVDump) { + yuvDumper->openWindow(width,height,title); + } + return back; +} + +int DspX11OutputStream::x11WindowId() { + return x11Window->x11WindowId(); +} + + +void DspX11OutputStream::closeWindow() { + x11Window->closeWindow(); +} + +void DspX11OutputStream::flushWindow() { + x11Window->flushWindow(); +} + + +PictureArray* DspX11OutputStream::lockPictureArray() { + return x11Window->lockPictureArray(); +} + + +void DspX11OutputStream::unlockPictureArray(PictureArray* pictureArray) { + + + + YUVPicture* pic=pictureArray->getYUVPictureCallback(); + + if (lYUVDump) { + yuvDumper->unlockPictureArray(pictureArray); + } + if (avSyncer->syncPicture(pic)==false) { + return; + } + + x11Window->unlockPictureArray(pictureArray); + + +} + +int DspX11OutputStream::getFrameusec() { + return avSyncer->getFrameusec(); +} + + + +int DspX11OutputStream::getOutputInit() { + return lVideoInit; +} + + +void DspX11OutputStream::setOutputInit(int lInit) { + this->lVideoInit=lInit; +} + + + +void DspX11OutputStream::config(const char* key, + const char* value,void* user_data) { + + cout << "key:"<<key<<endl; + if (strcmp(key,"-s")==0) { + avSyncer->config(key,value,user_data); + } + if (strcmp(key,"-b")==0) { + lBufferSet=true; + int size=strtol(value,(char **)NULL,10); + cout << "simulated audio buffersize:"<<size<<" bytes"<<endl; + avSyncer->setAudioBufferSize(size); + } + if (strcmp(key,"-p")==0) { + lPerformance=true; + avSyncer->config(key,value,user_data); + } + if (strcmp(key,"yufDump")==0) { + int method=atoi(value); + switch(method) { + case 2: + yuvDumper->setMethod(_DUMP_YUV_AS_STREAM); + break; + default: + cout << "unknown dump method"<<endl; + } + lYUVDump=true; + } + x11Window->config(key,value,user_data); +} + + +AVSyncer* DspX11OutputStream::getAVSyncer() { + return avSyncer; +} + + + diff --git a/mpeglib/lib/output/dspX11OutputStream.h b/mpeglib/lib/output/dspX11OutputStream.h new file mode 100644 index 00000000..9b3eb859 --- /dev/null +++ b/mpeglib/lib/output/dspX11OutputStream.h @@ -0,0 +1,89 @@ +/* + concret OutputClass + 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 __DSPX11OUTPUTSTREAM_H +#define __DSPX11OUTPUTSTREAM_H + +#include "outputStream.h" + + + +class DSPWrapper; +class WindowOut; +class AVSyncer; +class AudioTime; +class Performance; +class YUVDumper; + +class DspX11OutputStream : public OutputStream { + + DSPWrapper* dspWrapper; + WindowOut* x11Window; + AVSyncer* avSyncer; + + + int lBufferSet; + int lVideoInit; + int lavSync; + int lneedInit; + int lPerformance; + int lYUVDump; + + AudioTime* audioTime; + YUVDumper* yuvDumper; + + public: + DspX11OutputStream(int bufferSize); + ~DspX11OutputStream(); + + // Audio Output + + int audioSetup(int frequency,int stereo,int sign,int big,int sixteen); + void audioClose(); + void audioOpen(); + int audioPlay(TimeStamp* startStamp, + TimeStamp* endStamp,char *buffer, int size); + + + int getPreferredDeliverSize(); + + + // Video Output + + int openWindow(int width, int height,const char *title); + int x11WindowId(); + void closeWindow(); + void flushWindow(); + + PictureArray* lockPictureArray(); + void unlockPictureArray(PictureArray* pictureArray); + + int getFrameusec(); + + int getDepth(); + int getOutputInit(); + void setOutputInit(int lInit); + + void config(const char* key,const char* value,void* user_data); + + // methods which do not belong to the outputStream intferface; + AVSyncer* getAVSyncer(); + + +}; + + + +#endif diff --git a/mpeglib/lib/output/outPlugin.cpp b/mpeglib/lib/output/outPlugin.cpp new file mode 100644 index 00000000..cbae10ec --- /dev/null +++ b/mpeglib/lib/output/outPlugin.cpp @@ -0,0 +1,71 @@ +/* + generic output 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 "outPlugin.h" + +#include <iostream> + +using namespace std; + + +OutPlugin::OutPlugin() { +} + + +OutPlugin::~OutPlugin() { +} + + + +OutputStream* OutPlugin::createOutputStream(int outputType) { + + // make checks which input routine to use + OutputStream* outputStream; + int method; + + outputStream=NULL; + method=outputType; + + switch(method) { + case _OUTPUT_LOCAL: { + outputStream=new DspX11OutputStream(1024*64); + break; + } + case _OUTPUT_ARTS: { + outputStream=new ArtsOutputStream(NULL); + break; + } + case _OUTPUT_EMPTY: { + outputStream=new OutputStream(); + break; + } + default: + cout << "error cannot create default output stream"<<endl; + exit(0); + } + + return outputStream; + + +} + +OutputStream* OutPlugin::createOutputStream(int outputType,int lThreadSafe) { + OutputStream* output=OutPlugin::createOutputStream(outputType); + if (lThreadSafe==false) { + return output; + } + OutputStream* tsOutput=new ThreadSafeOutputStream(output); + return tsOutput; +} + diff --git a/mpeglib/lib/output/outPlugin.h b/mpeglib/lib/output/outPlugin.h new file mode 100644 index 00000000..b70620a6 --- /dev/null +++ b/mpeglib/lib/output/outPlugin.h @@ -0,0 +1,44 @@ +/* + generic output 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 __OUTPLUGIN_H +#define __OUTPLUGIN_H + + +#include "dspX11OutputStream.h" +#include "artsOutputStream.h" +#include "threadSafeOutputStream.h" +#include <kdemacros.h> + +#define _OUTPUT_LOCAL 1 +#define _OUTPUT_EMPTY 2 +#define _OUTPUT_YAF 3 +#define _OUTPUT_ARTS 4 + +#define _OUTPUT_THREADSAFE 1 + +class KDE_EXPORT OutPlugin { + + public: + OutPlugin(); + ~OutPlugin(); + + static OutputStream* createOutputStream(int outputType); + static OutputStream* createOutputStream(int outputType,int lThreadSafe); + +}; +#endif + + + + diff --git a/mpeglib/lib/output/outputStream.cpp b/mpeglib/lib/output/outputStream.cpp new file mode 100644 index 00000000..ef209cbc --- /dev/null +++ b/mpeglib/lib/output/outputStream.cpp @@ -0,0 +1,238 @@ +/* + generic output class + 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 "outputStream.h" +#include "../util/mmx/mmx.h" + +#include <iostream> + +using namespace std; + +OutputStream::OutputStream() { + // we call mm_support() here because it is the only position + // where we gurantee that not threads are + // running (the call is not thread safe) + // afer the call we never execute the asm part again + // and everything is fine + mm_support(); + abs_thread_mutex_init(&stateChangeMut); + abs_thread_cond_init(&stateChangeCond); + + audioState=0; + videoState=0; + audioInit(); + videoInit(); +} + + +OutputStream::~OutputStream() { + audioInit(); + videoInit(); + abs_thread_cond_destroy(&stateChangeCond); + abs_thread_mutex_destroy(&stateChangeMut); +} + + +int OutputStream::audioInit() { + sendSignal(_STREAM_MASK_IS_INIT,false,_STREAMTYPE_AUDIO); + sendSignal(_STREAM_MASK_IS_EOF,false,_STREAMTYPE_AUDIO); + sendSignal(_STREAM_MASK_IS_DATA,false,_STREAMTYPE_AUDIO); + return true; +} + + +int OutputStream::audioSetup(int ,int , + int ,int ,int ) { + sendSignal(_STREAM_MASK_IS_INIT,true,_STREAMTYPE_AUDIO); + return true; +} + + +int OutputStream::audioPlay(TimeStamp* , + TimeStamp* ,char* , int len) { + sendSignal(_STREAM_MASK_IS_DATA,true,_STREAMTYPE_AUDIO); + return len; +} + +void OutputStream::audioFlush() { + sendSignal(_STREAM_MASK_IS_EOF,true,_STREAMTYPE_AUDIO); +} + + +void OutputStream::audioClose() { + cerr << "direct virtual call OutputStream::audioClose"<<endl; + exit(0); +} + +void OutputStream::audioOpen() { + cerr << "direct virtual call OutputStream::audioOpen"<<endl; + exit(0); +} + + + +void OutputStream::sendSignal(int signal,int value,int streamType) { + abs_thread_mutex_lock(&stateChangeMut); + int* modifyState=NULL; + switch(streamType) { + case _STREAMTYPE_AUDIO: + modifyState=&audioState; + break; + case _STREAMTYPE_VIDEO: + modifyState=&videoState; + break; + default: + cout << "unknown streamType:"<<streamType + <<" in OutputStream::sendSignal"<<endl; + exit(0); + } + // should we set the bit? + if (value==true) { + // set it with "or" + *modifyState|=signal; + } else { + // we should remove the bit + // is it currently set? + if (*modifyState & signal) { + // remove it + *modifyState-=signal; + } + } + + + abs_thread_cond_signal(&stateChangeCond); + abs_thread_mutex_unlock(&stateChangeMut); + +} + + +int OutputStream::getPreferredDeliverSize() { + cerr << "direct virtual call OutputStream::getPreferredDeliverSize()"<<endl; + return 4096; +} + +int OutputStream::videoInit() { + sendSignal(_STREAM_MASK_IS_INIT,false,_STREAMTYPE_VIDEO); + sendSignal(_STREAM_MASK_IS_EOF,false,_STREAMTYPE_VIDEO); + sendSignal(_STREAM_MASK_IS_DATA,false,_STREAMTYPE_VIDEO); + return true; +} + +int OutputStream::openWindow(int , int ,const char* ) { + sendSignal(_STREAM_MASK_IS_INIT,true,_STREAMTYPE_VIDEO); + return true; +} + +int OutputStream::x11WindowId() { + cout << "direct virtual call OutputStream::x11WindowId()" << endl; + return -1; +} + +void OutputStream::closeWindow() { + cerr << "direct virtual call OutputStream::closeWindow"<<endl; + exit(0); +} + +void OutputStream::flushWindow() { + sendSignal(_STREAM_MASK_IS_EOF,true,_STREAMTYPE_VIDEO); +} + + +PictureArray* OutputStream::lockPictureArray() { + cerr << "direct virtual call OutputStream::lockPictureArray"<<endl; + exit(0); + return NULL; +} + + +void OutputStream::unlockPictureArray(PictureArray* ) { + sendSignal(_STREAM_MASK_IS_DATA,true,_STREAMTYPE_VIDEO); +} + + + + + +int OutputStream::getOutputInit() { + cerr << "direct virtual call OutputStream::getOutputInit"<<endl; + exit(0); + return false; +} + + +void OutputStream::setOutputInit(int lInit) { + cerr << "direct virtual call OutputStream::setOutputInit:"<<lInit<<endl; + exit(0); +} + + + +void OutputStream::writeInfo(PluginInfo* ) { + +} + + +void OutputStream::config(const char* key, + const char* value,void* user_data) { + cerr << "direct virtual call OutputStream::config"<<endl; + printf("key:%s\n",key); + printf("value:%s\n",value); + printf("user_data:%p\n",user_data); + exit(0); +} + +int OutputStream::getFrameusec() { + cerr << "direct virtual call OutputStream::getFrameusec"<<endl; + return 0; +} + + + +int OutputStream::waitStreamState(int method,int mask,int streamType) { + + int* waitState=NULL; + switch(streamType) { + case _STREAMTYPE_AUDIO: + waitState=&audioState; + break; + case _STREAMTYPE_VIDEO: + waitState=&videoState; + break; + default: + cout << "unknown streamType:"<<streamType + <<" in OutputStream::waitStreamState"<<endl; + exit(0); + } + + if (method == _OUTPUT_WAIT_METHOD_BLOCK) { + abs_thread_mutex_lock(&stateChangeMut); + while ((*waitState &= mask)==0) { + cout << "waitStreamState:"<<waitState<<endl; + cout << "mask:"<<mask<<endl; + abs_thread_cond_wait(&stateChangeCond,&stateChangeMut); + } + abs_thread_mutex_unlock(&stateChangeMut); + return true; + } + + int back=false; + if (method == _OUTPUT_WAIT_METHOD_POLL) { + abs_thread_mutex_lock(&stateChangeMut); + back=*waitState; + abs_thread_mutex_unlock(&stateChangeMut); + return back; + } + cout << " OutputStream::waitStreamState method not implemented"<<endl; + exit(0); + return 0; +} diff --git a/mpeglib/lib/output/outputStream.h b/mpeglib/lib/output/outputStream.h new file mode 100644 index 00000000..9ef538fd --- /dev/null +++ b/mpeglib/lib/output/outputStream.h @@ -0,0 +1,151 @@ +/* + generic output class + 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 __OUTPUTSTREAM_H +#define __OUTPUTSTREAM_H + +#include "../util/timeStamp.h" +#include "pluginInfo.h" +#include "../util/render/pictureArray.h" +#include "../util/abstract/abs_thread.h" +#include <kdemacros.h> + +#define _OUTPUT_WAIT_METHOD_BLOCK 1 +#define _OUTPUT_WAIT_METHOD_POLL 2 +#define _OUTPUT_WAIT_METHOD_CALLBACK 3 + + +#define _STREAM_MASK_IS_INIT 1 +#define _STREAM_MASK_IS_EOF 2 +#define _STREAM_MASK_IS_DATA 4 + +#define _STREAM_MASK_ALL 1+2+4 + +#define _STREAMTYPE_AUDIO 1 +#define _STREAMTYPE_VIDEO 2 + + +/** + Outputstream. A nice base class. Mostly obvious methods, + except PictureArray. + write your picture into this structure + and then put it on the surface with the unlock call. + +*/ + + +/** + life of stream states: + -------------- + method flag additional calls + construct audioInit() + + + + destruct audioInit() + + audioInit isInit=false + isEof=false + isData=false + + audioSetup isInit=true + audioFlush isEof=true + audioPlay isData=true + + + Note: after a call of streamInit we have an "invalid" state + obviously there is no stream where eof==false but + and has not been initialised. + + another invalid state is audioInit->audioPlay + +*/ + + + + +class KDE_EXPORT OutputStream { + + int audioState; + int videoState; + abs_thread_mutex_t stateChangeMut; + abs_thread_cond_t stateChangeCond; + + public: + OutputStream(); + + virtual ~OutputStream(); + + // Audio Stream handling + virtual int audioInit(); + virtual int audioSetup(int freq,int stereo,int sign,int big,int sampleSize); + virtual int audioPlay(TimeStamp* startStamp, + TimeStamp* endStamp,char *buffer, int size); + virtual void audioFlush(); + + // Audio device "/dev/dsp" handling + virtual void audioClose(); + virtual void audioOpen(); + + // hack: FIX it + virtual int getPreferredDeliverSize(); + + + // stream State handling + + // we return the mask which triggerd (by "AND") + // or the current polled mask when method is POLL + // Note: you can only wait for "true" signals + virtual int waitStreamState(int method,int mask,int streamType); + + + + + // Video Output + virtual int videoInit(); + virtual int openWindow(int width, int height,const char *title); + virtual int x11WindowId(); + virtual void closeWindow(); + virtual void flushWindow(); + + + // get the current surfaces to draw into + virtual PictureArray* lockPictureArray(); + virtual void unlockPictureArray(PictureArray* pictureArray); + + + + // maybe not needed: + virtual int getFrameusec(); + virtual int getOutputInit(); + virtual void setOutputInit(int lInit); + + // Info Output + virtual void writeInfo(class PluginInfo* pluginInfo); + + + // config Output + virtual void config(const char* key, + const char* value,void* user_data); + + private: + void initStream(); + + protected: + // sometimes useful, but use with care + void sendSignal(int signal,int value,int streamType); + +}; +#endif diff --git a/mpeglib/lib/output/performance.cpp b/mpeglib/lib/output/performance.cpp new file mode 100644 index 00000000..9e2b7f92 --- /dev/null +++ b/mpeglib/lib/output/performance.cpp @@ -0,0 +1,50 @@ +/* + measures picture/second + 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 "performance.h" + +#include <iostream> + +using namespace std; + + +Performance::Performance() { + picCnt=0; + startTime=new TimeStamp(); + endTime=new TimeStamp(); + +} + + +Performance::~Performance() { + delete startTime; + delete endTime; +} + + +void Performance::incPictureCount() { + if (picCnt==0) { + startTime->gettimeofday(); + } + picCnt++; + if (picCnt==200) { + endTime->gettimeofday(); + TimeStamp diffTime; + endTime->minus(startTime,&diffTime); + double secs=(double)diffTime.getAsSeconds(); + + double picSec=(double)picCnt/secs; + cout << "picPerSec:"<<picSec<<" secs:"<<secs<<endl; + picCnt=0; + } +} diff --git a/mpeglib/lib/output/performance.h b/mpeglib/lib/output/performance.h new file mode 100644 index 00000000..d7d54572 --- /dev/null +++ b/mpeglib/lib/output/performance.h @@ -0,0 +1,34 @@ +/* + measures picture/second + 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 __PERFORMANCE_H +#define __PERFORMANCE_H + +#include "../util/timeStamp.h" + +class Performance { + + int picCnt; + TimeStamp* startTime; + TimeStamp* endTime; + + + public: + + Performance(); + ~Performance(); + void incPictureCount(); + +}; +#endif diff --git a/mpeglib/lib/output/pluginInfo.cpp b/mpeglib/lib/output/pluginInfo.cpp new file mode 100644 index 00000000..c741852c --- /dev/null +++ b/mpeglib/lib/output/pluginInfo.cpp @@ -0,0 +1,65 @@ +/* + add on information about 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 "pluginInfo.h" + +#include <iostream> + +using namespace std; + + +PluginInfo::PluginInfo() { + musicName=new DynBuffer(20); + + reset(); + +} + + +PluginInfo::~PluginInfo() { + delete musicName; +} + +void PluginInfo::setLength(int sec) { + this->sec=sec; +} + + +int PluginInfo::getLength() { + return sec; +} + + +void PluginInfo::reset(){ + sec=0; + musicName->clear(); + musicName->append("none"); +} + +void PluginInfo::print() { + cerr << "length in sec:"<<sec<<endl; + cerr << "url:"<<getUrl()<<endl; +} + + +void PluginInfo::setUrl(char* name) { + musicName->clear(); + if (name != NULL) { + musicName->append(name); + } +} + + +char* PluginInfo::getUrl() { + return musicName->getData(); +} diff --git a/mpeglib/lib/output/pluginInfo.h b/mpeglib/lib/output/pluginInfo.h new file mode 100644 index 00000000..7026fce9 --- /dev/null +++ b/mpeglib/lib/output/pluginInfo.h @@ -0,0 +1,48 @@ +/* + add on information about 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 __PLUGININFO_H +#define __PLUGININFO_H + +#include "../util/dynBuffer.h" +#include <kdemacros.h> + +/** + Here we have the base class for all additional information + about a plugin. + The len in time of the current song belongs here, as + well as the author, version number etc.. +*/ + + +class KDE_EXPORT PluginInfo { + + int sec; + DynBuffer* musicName; + + + public: + PluginInfo(); + ~PluginInfo(); + + void setLength(int sec); + int getLength(); + + void setUrl(char* name); + char* getUrl(); + + void reset(); + void print(); +}; +#endif diff --git a/mpeglib/lib/output/threadSafeOutputStream.cpp b/mpeglib/lib/output/threadSafeOutputStream.cpp new file mode 100644 index 00000000..ec7ab510 --- /dev/null +++ b/mpeglib/lib/output/threadSafeOutputStream.cpp @@ -0,0 +1,153 @@ +/* + thread safe wrapper for output Stream + 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 "threadSafeOutputStream.h" + + +ThreadSafeOutputStream::ThreadSafeOutputStream(OutputStream* output) { + threadQueueAudio=new ThreadQueue(); + threadQueueVideo=new ThreadQueue(); + this->output=output; +} + + +ThreadSafeOutputStream::~ThreadSafeOutputStream() { + delete threadQueueAudio; + delete threadQueueVideo; + delete output; +} + +int ThreadSafeOutputStream::audioInit() { + int back; + threadQueueAudio->waitForExclusiveAccess(); + back=output->audioInit(); + threadQueueAudio->releaseExclusiveAccess(); + return back; +} + + +int ThreadSafeOutputStream::audioSetup(int freq,int stereo, + int sign,int big,int sampleSize) { + int back; + threadQueueAudio->waitForExclusiveAccess(); + back=output->audioSetup(freq,stereo,sign,big,sampleSize); + threadQueueAudio->releaseExclusiveAccess(); + return back; +} + + +int ThreadSafeOutputStream::audioPlay(TimeStamp* start, + TimeStamp* end,char* buf, int len) { + int back; + threadQueueAudio->waitForExclusiveAccess(); + back=output->audioPlay(start,end,buf,len); + threadQueueAudio->releaseExclusiveAccess(); + return back; +} + +void ThreadSafeOutputStream::audioFlush() { + threadQueueAudio->waitForExclusiveAccess(); + output->audioFlush(); + threadQueueAudio->releaseExclusiveAccess(); +} + + +void ThreadSafeOutputStream::audioClose() { + threadQueueAudio->waitForExclusiveAccess(); + output->audioClose(); + threadQueueAudio->releaseExclusiveAccess(); +} + +void ThreadSafeOutputStream::audioOpen() { + threadQueueAudio->waitForExclusiveAccess(); + output->audioOpen(); + threadQueueAudio->releaseExclusiveAccess(); +} + + + +int ThreadSafeOutputStream::getPreferredDeliverSize() { + int back; + threadQueueAudio->waitForExclusiveAccess(); + back=output->getPreferredDeliverSize(); + threadQueueAudio->releaseExclusiveAccess(); + return back; +} + +int ThreadSafeOutputStream::videoInit() { + int back; + threadQueueVideo->waitForExclusiveAccess(); + back=output->videoInit(); + threadQueueVideo->releaseExclusiveAccess(); + return back; +} + +int ThreadSafeOutputStream::openWindow(int w, int h,const char* title) { + int back; + threadQueueVideo->waitForExclusiveAccess(); + back=output->openWindow(w,h,title); + threadQueueVideo->releaseExclusiveAccess(); + return back; +} + + +void ThreadSafeOutputStream::closeWindow() { + threadQueueVideo->waitForExclusiveAccess(); + output->closeWindow(); + threadQueueVideo->releaseExclusiveAccess(); +} + +void ThreadSafeOutputStream::flushWindow() { + threadQueueVideo->waitForExclusiveAccess(); + output->flushWindow(); + threadQueueVideo->releaseExclusiveAccess(); +} + + +PictureArray* ThreadSafeOutputStream::lockPictureArray() { + PictureArray* back; + threadQueueVideo->waitForExclusiveAccess(); + back=output->lockPictureArray(); + threadQueueVideo->releaseExclusiveAccess(); + return back; +} + + +void ThreadSafeOutputStream::unlockPictureArray(PictureArray* array) { + threadQueueVideo->waitForExclusiveAccess(); + output->unlockPictureArray(array); + threadQueueVideo->releaseExclusiveAccess(); +} + + +int ThreadSafeOutputStream::getFrameusec() { + int back; + threadQueueVideo->waitForExclusiveAccess(); + back=output->getFrameusec(); + threadQueueVideo->releaseExclusiveAccess(); + return back; +} + +void ThreadSafeOutputStream::config(const char* key, + const char* value,void* user_data) { + + threadQueueVideo->waitForExclusiveAccess(); + threadQueueAudio->waitForExclusiveAccess(); + output->config(key,value,user_data); + threadQueueVideo->releaseExclusiveAccess(); + threadQueueAudio->releaseExclusiveAccess(); + +} + + + diff --git a/mpeglib/lib/output/threadSafeOutputStream.h b/mpeglib/lib/output/threadSafeOutputStream.h new file mode 100644 index 00000000..c9852a37 --- /dev/null +++ b/mpeglib/lib/output/threadSafeOutputStream.h @@ -0,0 +1,67 @@ +/* + thread safe wrapper for output Stream + 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 __THREADSAFEOUTPUTSTREAM_H +#define __THREADSAFEOUTPUTSTREAM_H + +// read INTRO in threadQueue.h +// This class makes the outputStream (given in constructor) +// threadsafe by wrapping each call with a threadqueue. +// +// Important NOTE: the output pointer is the owned by this class !!! +// which means: we call delete on it! +// More Important NOTES: +// +// We make the audio and video calls seperate threadsafe +// and ONLY the config call threadsafe to both! + +#include "../util/abstract/threadQueue.h" +#include "outputStream.h" + + +class ThreadSafeOutputStream : public OutputStream { + + ThreadQueue* threadQueueAudio; + ThreadQueue* threadQueueVideo; + OutputStream* output; + + public: + ThreadSafeOutputStream(OutputStream* output); + ~ThreadSafeOutputStream(); + + // Thread safe Audio Stream handling + int audioInit(); + int audioSetup(int freq,int stereo,int sign,int big,int sampleSize); + int audioPlay(TimeStamp* startStamp, + TimeStamp* endStamp,char *buffer, int size); + void audioFlush(); + void audioClose(); + void audioOpen(); + int getPreferredDeliverSize(); + + + // Video Output + int videoInit(); + int openWindow(int width, int height,const char *title); + void closeWindow(); + void flushWindow(); + PictureArray* lockPictureArray(); + void unlockPictureArray(PictureArray* pictureArray); + int getFrameusec(); + + // config Output + void config(const char* key, + const char* value,void* user_data); + + +}; +#endif diff --git a/mpeglib/lib/output/windowOut.cpp b/mpeglib/lib/output/windowOut.cpp new file mode 100644 index 00000000..3e199095 --- /dev/null +++ b/mpeglib/lib/output/windowOut.cpp @@ -0,0 +1,64 @@ +/* + wrapper for X11 Window + 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 "windowOut.h" + + + + + + + +WindowOut::WindowOut() { + + renderMachine=new RenderMachine(); + +} + + +WindowOut::~WindowOut() { + delete renderMachine; +} + +int WindowOut::openWindow(int width, int height,const char *title){ + return renderMachine->openWindow(width,height,title); +} + +int WindowOut::x11WindowId() { + return renderMachine->x11WindowId(); +} + +void WindowOut::flushWindow() { + renderMachine->flushWindow(); +} + + +void WindowOut::closeWindow() { + renderMachine->closeWindow(); +} + + +PictureArray* WindowOut::lockPictureArray() { + return renderMachine->lockPictureArray(); +} + + +void WindowOut::unlockPictureArray(PictureArray* pictureArray) { + renderMachine->unlockPictureArray(pictureArray); +} + + + +void WindowOut::config(const char* key, const char* value,void* user_data) { + renderMachine->config(key,value,user_data); +} diff --git a/mpeglib/lib/output/windowOut.h b/mpeglib/lib/output/windowOut.h new file mode 100644 index 00000000..648d1dc4 --- /dev/null +++ b/mpeglib/lib/output/windowOut.h @@ -0,0 +1,53 @@ +/* + wrapper for X11 Window + 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 __WINDOWOUT_H +#define __WINDOWOUT_H + + +#include "../util/abstract/abs_thread.h" +#include "../util/timeStamp.h" +#include "../util/render/renderMachine.h" + +/** + Stupid class. survivor of ancient days. +*/ + + +class WindowOut { + + + RenderMachine* renderMachine; + + public: + WindowOut(); + ~WindowOut(); + + int openWindow(int width, int height,const char *title); + int x11WindowId(); + void closeWindow(); + void flushWindow(); + + // get the current surfaces to draw into + PictureArray* lockPictureArray(); + void unlockPictureArray(PictureArray* pictureArray); + + void config(const char* key, const char* value,void* user_data); + + + private: + + +}; +#endif diff --git a/mpeglib/lib/output/yuvDumper.cpp b/mpeglib/lib/output/yuvDumper.cpp new file mode 100644 index 00000000..1962b151 --- /dev/null +++ b/mpeglib/lib/output/yuvDumper.cpp @@ -0,0 +1,81 @@ +/* + writes yuv images on HD + 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 "yuvDumper.h" + +YUVDumper::YUVDumper() { + picCnt=1; + method=_DUMP_YUV_AS_STREAM; +} + +YUVDumper::~YUVDumper() { +} + + +int YUVDumper::openWindow(int w, int h,const char*) { + + FILE* formatFile=fopen("stream.yuv.format","w+"); + fprintf(formatFile,"Version 0.1\nw:%dh:%d\n",w,h); + fclose(formatFile); + + + + if (method == _DUMP_YUV_AS_STREAM) { + FILE* outFile=fopen("stream.yuv","w+"); + fclose(outFile); + } + return true; +} + +void YUVDumper::closeWindow() { +} + + +void YUVDumper::flushWindow() { +} + + +int YUVDumper::getMethod() { + return method; +} + + +void YUVDumper::setMethod(int method) { + this->method=method; +} + +void YUVDumper::unlockPictureArray(PictureArray* pictureArray) { + YUVPicture* pic=pictureArray->getYUVPictureCallback(); + if (pic == NULL) { + return; + } + + FILE* outFile=NULL; + + if (method == _DUMP_YUV_AS_STREAM) { + outFile=fopen("stream.yuv","a+"); + } + + if (outFile == NULL) { + perror("fopen"); + return; + } + + int lumSize=pic->getLumLength(); + int colorSize=pic->getColorLength(); + fwrite(pic->getLuminancePtr(),1,lumSize,outFile); + fwrite(pic->getCrPtr(),1,colorSize,outFile); + fwrite(pic->getCbPtr(),1,colorSize,outFile); + fclose(outFile); + +} diff --git a/mpeglib/lib/output/yuvDumper.h b/mpeglib/lib/output/yuvDumper.h new file mode 100644 index 00000000..2e4880b0 --- /dev/null +++ b/mpeglib/lib/output/yuvDumper.h @@ -0,0 +1,51 @@ +/* + writes yuv images on HD + 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 __YUVDUMPER_H +#define __YUVDUMPER_H + +#include "outputStream.h" + +#include <sys/stat.h> +#include <sys/types.h> +#include <fcntl.h> +#include <stdio.h> + + +#define _DUMP_YUV_AS_STREAM 2 + + +class YUVDumper : public OutputStream { + + + int picCnt; + int method; + + public: + YUVDumper(); + ~YUVDumper(); + + // Video Output + + int openWindow(int width, int height,const char *title); + void closeWindow(); + void flushWindow(); + + void unlockPictureArray(PictureArray* pictureArray); + int getMethod(); + void setMethod(int method); + + +}; + +#endif diff --git a/mpeglib/lib/splay/Makefile.am b/mpeglib/lib/splay/Makefile.am new file mode 100644 index 00000000..70fdc105 --- /dev/null +++ b/mpeglib/lib/splay/Makefile.am @@ -0,0 +1,53 @@ +# libsplay - Makefile.am + + +INCLUDES = $(all_includes) + + +EXTRA_DIST = dct64.cpp dct64_down.cpp dct36_12.cpp \ + window.cpp dct.h + + +noinst_LTLIBRARIES = libsplay.la + +noinst_HEADERS = mpegAudioHeader.h mpegAudioStream.h \ + mpegsound.h op.h \ + sigsev.c dump.h \ + dxHead.h mpeg2tables.h \ + mpegAudioBitWindow.h huffmanlookup.h \ + common.h attribute.h synthesis.h + +kmpgincludedir = $(includedir)/$(THIS_LIB_NAME)/splay + +kmpginclude_HEADERS = splayDecoder.h mpegAudioInfo.h \ + mpegAudioFrame.h + + +libsplay_la_SOURCES = mpegAudioHeader.cpp mpegAudioStream.cpp \ + huffmantable.cpp \ + mpeglayer1.cpp \ + mpeglayer2.cpp \ + mpeglayer3.cpp \ + mpegtable.cpp \ + mpegtoraw.cpp \ + dxHead.cpp \ + mpegAudioBitWindow.cpp huffmanlookup.cpp \ + splayDecoder.cpp \ + dump.cpp synth_filter.cpp \ + synthesis.cpp synth_Std.cpp synth_Down.cpp \ + mpegAudioFrame.cpp \ + mpegAudioInfo.cpp + + + +#CXXFLAGS += -fno-strength-reduce +# -funroll-all-loops -finline-functions -ffast-math -m486 + + + + + + + + + diff --git a/mpeglib/lib/splay/attribute.h b/mpeglib/lib/splay/attribute.h new file mode 100644 index 00000000..9e6bf0e6 --- /dev/null +++ b/mpeglib/lib/splay/attribute.h @@ -0,0 +1,33 @@ +/* + align attribut definition (g++) + Copyright (C) 2001 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 __ATTRIBUTE_H +#define __ATTRIBUTE_H + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* use gcc attribs to align critical data structures */ + +#ifdef ATTRIBUTE_ALIGNED_MAX +#define ATTR_ALIGN(align) __attribute__ \ + ((__aligned__ ((ATTRIBUTE_ALIGNED_MAX <align) ? \ + ATTRIBUTE_ALIGNED_MAX : align))) +#else +#define ATTR_ALIGN(align) +#endif + + +#endif diff --git a/mpeglib/lib/splay/common.h b/mpeglib/lib/splay/common.h new file mode 100644 index 00000000..df0945b8 --- /dev/null +++ b/mpeglib/lib/splay/common.h @@ -0,0 +1,60 @@ +/* + include header for dcts/windows + Copyright (C) 2001 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 __COMMON_H +#define __COMMON_H + +#include "attribute.h" +#include <stdio.h> + +#define SSLIMIT 18 +#define SBLIMIT 32 + + +#define LS 0 +#define RS 1 + + +typedef float REAL; + +// The inline code works on intel only with egcs >= 1.1 +#ifdef __GNUC__ +#if (__GNUC__ < 2 || ( __GNUC__ == 2 && __GNUC_MINOR__ < 91 ) ) +#ifndef _AIX +#warning "inline code disabled! (buggy egcs version)" +#undef __NO_MATH_INLINES +#define __NO_MATH_INLINES 1 +#endif +#endif +#endif +#include <math.h> +#include <stdlib.h> + +#ifndef M_PI +#define MY_PI 3.14159265358979323846 +#else +#define MY_PI M_PI +#endif + +#ifdef PI +#undef PI +#endif +#define PI MY_PI +#define PI_12 (PI/12.0) +#define PI_18 (PI/18.0) +#define PI_24 (PI/24.0) +#define PI_36 (PI/36.0) +#define PI_72 (PI/72.0) + + +#endif diff --git a/mpeglib/lib/splay/dct.h b/mpeglib/lib/splay/dct.h new file mode 100644 index 00000000..ad707a19 --- /dev/null +++ b/mpeglib/lib/splay/dct.h @@ -0,0 +1,33 @@ +/* + wrapper for dcts + Copyright (C) 2001 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 __DCT_HEADER_H +#define __DCT_HEADER_H + +// one source: +extern void initialize_dct64(); + +//extern void dct64(REAL* out1,REAL* out2,REAL *fraction); + +// one source: +extern void initialize_dct64_downsample(); +//extern void dct64_downsample(REAL* out1,REAL* out2,REAL *fraction); + +// one source file: +extern void initialize_dct12_dct36(); + +//extern void dct12(REAL *in,REAL *prevblk1,REAL *prevblk2,REAL *wi,REAL *out); +//extern void dct36(REAL *inbuf,REAL *prevblk1,REAL *prevblk2,REAL *wi,REAL *out); + +extern void initialize_win(); +#endif diff --git a/mpeglib/lib/splay/dct36_12.cpp b/mpeglib/lib/splay/dct36_12.cpp new file mode 100644 index 00000000..b9978d7d --- /dev/null +++ b/mpeglib/lib/splay/dct36_12.cpp @@ -0,0 +1,288 @@ +/* + wrapper for dcts + Copyright (C) 2001 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 "dct.h" +#include "common.h" + + + +ATTR_ALIGN(64) static REAL hsec_12[3]; +ATTR_ALIGN(64) static REAL cos2_6=cos(PI/6.0*2.0); +ATTR_ALIGN(64) static REAL cos1_6=cos(PI/6.0*1.0); +ATTR_ALIGN(64) static REAL hsec_36[9]; +ATTR_ALIGN(64) static REAL cos_18[9]; + + +/** + This was some time ago a standalone dct class, + but to get more speed I made it an inline dct + int the filter classes +*/ + +static int dct36_12Init=false; + +void initialize_dct12_dct36() { + if (dct36_12Init==true) { + return; + } + dct36_12Init=true; + + + int i; + + for(i=0;i<3;i++) + hsec_12[i]=0.5/cos(double(i*2+1)* PI_12); + + for(i=0;i<9;i++) + hsec_36[i]=0.5/cos(double(i*2+1)* PI_36); + + for(i=0;i<9;i++) + cos_18[i]=cos(PI_18*double(i)); + +} + + +inline void dct36(REAL *inbuf,REAL *prevblk1, + REAL *prevblk2,REAL *wi,REAL *out){ + +#define MACRO0(v) { \ + REAL tmp; \ + out2[9+(v)]=(tmp=sum0+sum1)*wi[27+(v)]; \ + out2[8-(v)]=tmp * wi[26-(v)]; } \ + sum0-=sum1; \ + ts[SBLIMIT*(8-(v))]=out1[8-(v)]+sum0*wi[8-(v)]; \ + ts[SBLIMIT*(9+(v))]=out1[9+(v)]+sum0*wi[9+(v)]; +#define MACRO1(v) { \ + REAL sum0,sum1; \ + sum0=tmp1a+tmp2a; \ + sum1=(tmp1b+tmp2b)*hsec_36[(v)]; \ + MACRO0(v); } +#define MACRO2(v) { \ + REAL sum0,sum1; \ + sum0=tmp2a-tmp1a; \ + sum1=(tmp2b-tmp1b) * hsec_36[(v)]; \ + MACRO0(v); } + + { + REAL *in = inbuf; + + in[17]+=in[16];in[16]+=in[15];in[15]+=in[14];in[14]+=in[13]; + in[13]+=in[12];in[12]+=in[11];in[11]+=in[10];in[10]+=in[ 9]; + in[ 9]+=in[ 8];in[ 8]+=in[ 7];in[ 7]+=in[ 6];in[ 6]+=in[ 5]; + in[ 5]+=in[ 4];in[ 4]+=in[ 3];in[ 3]+=in[ 2];in[ 2]+=in[ 1]; + in[ 1]+=in[ 0]; + + + in[17]+=in[15];in[15]+=in[13];in[13]+=in[11];in[11]+=in[ 9]; + in[ 9]+=in[ 7];in[7] +=in[ 5];in[ 5]+=in[ 3];in[ 3]+=in[ 1]; + + { + REAL *c = cos_18; + REAL *out2 = prevblk2; + REAL *out1 = prevblk1; + REAL *ts = out; + + REAL ta33,ta66,tb33,tb66; + + ta33=in[2*3+0]*c[3]; + ta66=in[2*6+0]*c[6]; + tb33=in[2*3+1]*c[3]; + tb66=in[2*6+1]*c[6]; + + { + REAL tmp1a,tmp2a,tmp1b,tmp2b; + tmp1a= in[2*1+0]*c[1]+ta33 +in[2*5+0]*c[5]+in[2*7+0]*c[7]; + tmp1b= in[2*1+1]*c[1]+tb33 +in[2*5+1]*c[5]+in[2*7+1]*c[7]; + tmp2a=in[2*0+0]+in[2*2+0]*c[2]+in[2*4+0]*c[4]+ta66 +in[2*8+0]*c[8]; + tmp2b=in[2*0+1]+in[2*2+1]*c[2]+in[2*4+1]*c[4]+tb66 +in[2*8+1]*c[8]; + MACRO1(0); + MACRO2(8); + } + + { + REAL tmp1a,tmp2a,tmp1b,tmp2b; + tmp1a=(in[2*1+0]-in[2*5+0]-in[2*7+0])*c[3]; + tmp1b=(in[2*1+1]-in[2*5+1]-in[2*7+1])*c[3]; + tmp2a=(in[2*2+0]-in[2*4+0]-in[2*8+0])*c[6]-in[2*6+0]+in[2*0+0]; + tmp2b=(in[2*2+1]-in[2*4+1]-in[2*8+1])*c[6]-in[2*6+1]+in[2*0+1]; + MACRO1(1); + MACRO2(7); + } + + { + REAL tmp1a,tmp2a,tmp1b,tmp2b; + tmp1a= in[2*1+0]*c[5]-ta33 -in[2*5+0]*c[7]+in[2*7+0]*c[1]; + tmp1b= in[2*1+1]*c[5]-tb33 -in[2*5+1]*c[7]+in[2*7+1]*c[1]; + tmp2a=in[2*0+0]-in[2*2+0]*c[8]-in[2*4+0]*c[2]+ta66 +in[2*8+0]*c[4]; + tmp2b=in[2*0+1]-in[2*2+1]*c[8]-in[2*4+1]*c[2]+tb66 +in[2*8+1]*c[4]; + MACRO1(2); + MACRO2(6); + } + + { + REAL tmp1a,tmp2a,tmp1b,tmp2b; + tmp1a= in[2*1+0]*c[7]-ta33 +in[2*5+0]*c[1]-in[2*7+0]*c[5]; + tmp1b= in[2*1+1]*c[7]-tb33 +in[2*5+1]*c[1]-in[2*7+1]*c[5]; + tmp2a=in[2*0+0]-in[2*2+0]*c[4]+in[2*4+0]*c[8]+ta66 -in[2*8+0]*c[2]; + tmp2b=in[2*0+1]-in[2*2+1]*c[4]+in[2*4+1]*c[8]+tb66 -in[2*8+1]*c[2]; + MACRO1(3); + MACRO2(5); + } + + { + REAL sum0,sum1; + sum0= in[2*0+0]-in[2*2+0]+in[2*4+0]-in[2*6+0]+in[2*8+0]; + sum1=(in[2*0+1]-in[2*2+1]+in[2*4+1]-in[2*6+1]+in[2*8+1])*hsec_36[4]; + MACRO0(4); + } + } + } + + +} + + +inline void dct12(REAL *in,REAL *prevblk1,REAL *prevblk2,REAL *wi,REAL *out) { + +#define DCT12_PART1 \ + in5=in[5*3]; \ + in5+=(in4=in[4*3]); \ + in4+=(in3=in[3*3]); \ + in3+=(in2=in[2*3]); \ + in2+=(in1=in[1*3]); \ + in1+=(in0=in[0*3]); \ + \ + in5+=in3;in3+=in1; \ + \ + in2*=cos1_6; \ + in3*=cos1_6; + +#define DCT12_PART2 \ + in0+=in4*cos2_6; \ + \ + in4=in0+in2; \ + in0-=in2; \ + \ + in1+=in5*cos2_6; \ + \ + in5=(in1+in3)*hsec_12[0]; \ + in1=(in1-in3)*hsec_12[2]; \ + \ + in3=in4+in5; \ + in4-=in5; \ + \ + in2=in0+in1; \ + in0-=in1; + + { + REAL in0,in1,in2,in3,in4,in5; + register REAL *pb1=prevblk1; + out[SBLIMIT*0]=pb1[0];out[SBLIMIT*1]=pb1[1];out[SBLIMIT*2]=pb1[2]; + out[SBLIMIT*3]=pb1[3];out[SBLIMIT*4]=pb1[4];out[SBLIMIT*5]=pb1[5]; + + DCT12_PART1; + + { + REAL tmp0,tmp1=(in0-in4); + { + register REAL tmp2=(in1-in5)*hsec_12[1]; + tmp0=tmp1+tmp2; + tmp1-=tmp2; + } + out[(17-1)*SBLIMIT]=pb1[17-1]+tmp0*wi[11-1]; + out[(12+1)*SBLIMIT]=pb1[12+1]+tmp0*wi[ 6+1]; + out[(6 +1)*SBLIMIT]=pb1[6 +1]+tmp1*wi[ 1 ]; + out[(11-1)*SBLIMIT]=pb1[11-1]+tmp1*wi[ 5-1]; + } + + DCT12_PART2; + out[(17-0)*SBLIMIT]=pb1[17-0]+in2*wi[11-0]; + out[(12+0)*SBLIMIT]=pb1[12+0]+in2*wi[ 6+0]; + out[(12+2)*SBLIMIT]=pb1[12+2]+in3*wi[ 6+2]; + out[(17-2)*SBLIMIT]=pb1[17-2]+in3*wi[11-2]; + + out[( 6+0)*SBLIMIT]=pb1[ 6+0]+in0*wi[0]; + out[(11-0)*SBLIMIT]=pb1[11-0]+in0*wi[5-0]; + out[( 6+2)*SBLIMIT]=pb1[ 6+2]+in4*wi[2]; + out[(11-2)*SBLIMIT]=pb1[11-2]+in4*wi[5-2]; + } + + in++; + { + REAL in0,in1,in2,in3,in4,in5; + register REAL *pb2 = prevblk2; + + DCT12_PART1; + + { + REAL tmp0,tmp1=(in0-in4); + { + REAL tmp2=(in1-in5)*hsec_12[1]; + tmp0=tmp1+tmp2; + tmp1-=tmp2; + } + pb2[5-1]=tmp0*wi[11-1]; + pb2[0+1]=tmp0*wi[6+1]; + out[(12+1)*SBLIMIT]+=tmp1*wi[1]; + out[(17-1)*SBLIMIT]+=tmp1*wi[5-1]; + } + + DCT12_PART2; + + pb2[5-0]=in2*wi[11-0]; + pb2[0+0]=in2*wi[6+0]; + pb2[0+2]=in3*wi[6+2]; + pb2[5-2]=in3*wi[11-2]; + + out[(12+0)*SBLIMIT]+=in0*wi[0]; + out[(17-0)*SBLIMIT]+=in0*wi[5-0]; + out[(12+2)*SBLIMIT]+=in4*wi[2]; + out[(17-2)*SBLIMIT]+=in4*wi[5-2]; + } + + in++; + { + REAL in0,in1,in2,in3,in4,in5; + register REAL *pb2 = prevblk2; + pb2[12]=pb2[13]=pb2[14]=pb2[15]=pb2[16]=pb2[17]=0.0; + + DCT12_PART1; + + { + REAL tmp0,tmp1=(in0-in4); + { + REAL tmp2=(in1-in5)*hsec_12[1]; + tmp0=tmp1+tmp2; + tmp1-=tmp2; + } + pb2[11-1]=tmp0*wi[11-1]; + pb2[ 6+1]=tmp0*wi[6+1]; + pb2[ 0+1]+=tmp1*wi[1]; + pb2[ 5-1]+=tmp1*wi[5-1]; + } + + DCT12_PART2; + pb2[11-0]=in2*wi[11-0]; + pb2[ 6+0]=in2*wi[ 6+0]; + pb2[ 6+2]=in3*wi[ 6+2]; + pb2[11-2]=in3*wi[11-2]; + + pb2[ 0+0]+=in0*wi[0 ]; + pb2[ 5-0]+=in0*wi[5-0]; + pb2[ 0+2]+=in4*wi[2 ]; + pb2[ 5-2]+=in4*wi[5-2]; + } + + +} + + diff --git a/mpeglib/lib/splay/dct64.cpp b/mpeglib/lib/splay/dct64.cpp new file mode 100644 index 00000000..14241651 --- /dev/null +++ b/mpeglib/lib/splay/dct64.cpp @@ -0,0 +1,202 @@ +/* + wrapper for dcts + Copyright (C) 2001 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 "dct.h" +#include "common.h" + +ATTR_ALIGN(64) static REAL hcos_64[16]; +ATTR_ALIGN(64) static REAL hcos_32[8]; +ATTR_ALIGN(64) static REAL hcos_16[4]; +ATTR_ALIGN(64) static REAL hcos_8[2]; +ATTR_ALIGN(64) static REAL hcos_4; + +/** + This was some time ago a standalone dct class, + but to get more speed I made it an inline dct + int the filter classes +*/ + +static int dct64Init=false; + +void initialize_dct64() { + if (dct64Init==true) { + return; + } + dct64Init=true; + + int i; + + for(i=0;i<16;i++) { + hcos_64[i]=1.0/(2.0*cos(MY_PI*double(i*2+1)/64.0)); + } + for(i=0;i< 8;i++) { + hcos_32[i]=1.0/(2.0*cos(MY_PI*double(i*2+1)/32.0)); + } + for(i=0;i< 4;i++) { + hcos_16[i]=1.0/(2.0*cos(MY_PI*double(i*2+1)/16.0)); + } + for(i=0;i< 2;i++) { + hcos_8[i]=1.0/(2.0*cos(MY_PI*double(i*2+1)/ 8.0)); + } + hcos_4=1.0/(2.0*cos(MY_PI*1.0/4.0)); + +} + + + + +// +// splay dct64 , faster than mpeg123 dct. (from decode.c) +// +inline void dct64(REAL* out1,REAL* out2,REAL *fraction) { + ATTR_ALIGN(64) REAL p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,pa,pb,pc,pd,pe,pf; + ATTR_ALIGN(64) REAL q0,q1,q2,q3,q4,q5,q6,q7,q8,q9,qa,qb,qc,qd,qe,qf; + +#define OUT1(v,t) out1[(32-(v))*16] =(-(out1[(v)*16]=t)) +#define OUT2(v) out2[(96-(v)-32)*16]=out2[((v)-32)*16] + + // compute new values via a fast cosine transform: + { + // put to buffer 0..15 + register REAL* x=fraction; + + p0=x[ 0]+x[31];p1=x[ 1]+x[30];p2=x[ 2]+x[29];p3=x[ 3]+x[28]; + p4=x[ 4]+x[27];p5=x[ 5]+x[26];p6=x[ 6]+x[25];p7=x[ 7]+x[24]; + p8=x[ 8]+x[23];p9=x[ 9]+x[22];pa=x[10]+x[21];pb=x[11]+x[20]; + pc=x[12]+x[19];pd=x[13]+x[18];pe=x[14]+x[17];pf=x[15]+x[16]; + } + + // put to buffer 32..39 + q0=p0+pf;q1=p1+pe;q2=p2+pd;q3=p3+pc; + q4=p4+pb;q5=p5+pa;q6=p6+p9;q7=p7+p8; + // put to buffer 40..47 + q8=hcos_32[0]*(p0-pf);q9=hcos_32[1]*(p1-pe); + qa=hcos_32[2]*(p2-pd);qb=hcos_32[3]*(p3-pc); + qc=hcos_32[4]*(p4-pb);qd=hcos_32[5]*(p5-pa); + qe=hcos_32[6]*(p6-p9);qf=hcos_32[7]*(p7-p8); + + p0=q0+q7;p1=q1+q6;p2=q2+q5;p3=q3+q4; + p4=hcos_16[0]*(q0-q7);p5=hcos_16[1]*(q1-q6); + p6=hcos_16[2]*(q2-q5);p7=hcos_16[3]*(q3-q4); + p8=q8+qf;p9=q9+qe;pa=qa+qd;pb=qb+qc; + pc=hcos_16[0]*(q8-qf);pd=hcos_16[1]*(q9-qe); + pe=hcos_16[2]*(qa-qd);pf=hcos_16[3]*(qb-qc); + + q0=p0+p3;q1=p1+p2;q2=hcos_8[0]*(p0-p3);q3=hcos_8[1]*(p1-p2); + q4=p4+p7;q5=p5+p6;q6=hcos_8[0]*(p4-p7);q7=hcos_8[1]*(p5-p6); + q8=p8+pb;q9=p9+pa;qa=hcos_8[0]*(p8-pb);qb=hcos_8[1]*(p9-pa); + qc=pc+pf;qd=pd+pe;qe=hcos_8[0]*(pc-pf);qf=hcos_8[1]*(pd-pe); + + p0=q0+q1;p1=hcos_4*(q0-q1);p2=q2+q3;p3=hcos_4*(q2-q3); + p4=q4+q5;p5=hcos_4*(q4-q5);p6=q6+q7;p7=hcos_4*(q6-q7); + p8=q8+q9;p9=hcos_4*(q8-q9);pa=qa+qb;pb=hcos_4*(qa-qb); + pc=qc+qd;pd=hcos_4*(qc-qd);pe=qe+qf;pf=hcos_4*(qe-qf); + + { + register REAL tmp; + + tmp=p6+p7; + OUT2(36)=-(p5+tmp); + OUT2(44)=-(p4+tmp); + tmp=pb+pf; + OUT1(10,tmp); + OUT1(6,pd+tmp); + tmp=pe+pf; + OUT2(46)=-(p8+pc+tmp); + OUT2(34)=-(p9+pd+tmp); + tmp+=pa+pb; + OUT2(38)=-(pd+tmp); + OUT2(42)=-(pc+tmp); + OUT1(2,p9+pd+pf); + OUT1(4,p5+p7); + OUT2(48)=-p0; + out2[0]=-(out1[0]=p1); + OUT1( 8,p3); + OUT1(12,p7); + OUT1(14,pf); + OUT2(40)=-(p2+p3); + } + + { + // put to buffer 16..31 + register REAL *x=fraction; + + p0=hcos_64[ 0]*(x[ 0]-x[31]);p1=hcos_64[ 1]*(x[ 1]-x[30]); + p2=hcos_64[ 2]*(x[ 2]-x[29]);p3=hcos_64[ 3]*(x[ 3]-x[28]); + p4=hcos_64[ 4]*(x[ 4]-x[27]);p5=hcos_64[ 5]*(x[ 5]-x[26]); + p6=hcos_64[ 6]*(x[ 6]-x[25]);p7=hcos_64[ 7]*(x[ 7]-x[24]); + p8=hcos_64[ 8]*(x[ 8]-x[23]);p9=hcos_64[ 9]*(x[ 9]-x[22]); + pa=hcos_64[10]*(x[10]-x[21]);pb=hcos_64[11]*(x[11]-x[20]); + pc=hcos_64[12]*(x[12]-x[19]);pd=hcos_64[13]*(x[13]-x[18]); + pe=hcos_64[14]*(x[14]-x[17]);pf=hcos_64[15]*(x[15]-x[16]); + } + + // put to 48..63 + q0=p0+pf;q1=p1+pe;q2=p2+pd;q3=p3+pc; + q4=p4+pb;q5=p5+pa;q6=p6+p9;q7=p7+p8; + q8=hcos_32[0]*(p0-pf);q9=hcos_32[1]*(p1-pe); + qa=hcos_32[2]*(p2-pd);qb=hcos_32[3]*(p3-pc); + qc=hcos_32[4]*(p4-pb);qd=hcos_32[5]*(p5-pa); + qe=hcos_32[6]*(p6-p9);qf=hcos_32[7]*(p7-p8); + + p0=q0+q7;p1=q1+q6;p2=q2+q5;p3=q3+q4; + p4=hcos_16[0]*(q0-q7);p5=hcos_16[1]*(q1-q6); + p6=hcos_16[2]*(q2-q5);p7=hcos_16[3]*(q3-q4); + p8=q8+qf;p9=q9+qe;pa=qa+qd;pb=qb+qc; + pc=hcos_16[0]*(q8-qf);pd=hcos_16[1]*(q9-qe); + pe=hcos_16[2]*(qa-qd);pf=hcos_16[3]*(qb-qc); + + q0=p0+p3;q1=p1+p2;q2=hcos_8[0]*(p0-p3);q3=hcos_8[1]*(p1-p2); + q4=p4+p7;q5=p5+p6;q6=hcos_8[0]*(p4-p7);q7=hcos_8[1]*(p5-p6); + q8=p8+pb;q9=p9+pa;qa=hcos_8[0]*(p8-pb);qb=hcos_8[1]*(p9-pa); + qc=pc+pf;qd=pd+pe;qe=hcos_8[0]*(pc-pf);qf=hcos_8[1]*(pd-pe); + + p0=q0+q1;p1=hcos_4*(q0-q1); + p2=q2+q3;p3=hcos_4*(q2-q3); + p4=q4+q5;p5=hcos_4*(q4-q5); + p6=q6+q7;p7=hcos_4*(q6-q7); + p8=q8+q9;p9=hcos_4*(q8-q9); + pa=qa+qb;pb=hcos_4*(qa-qb); + pc=qc+qd;pd=hcos_4*(qc-qd); + pe=qe+qf;pf=hcos_4*(qe-qf); + + { + REAL tmp; + + tmp=pd+pf; + OUT1(5,p5+p7+pb+tmp); + tmp+=p9; + OUT1(1,p1+tmp); + OUT2(33)=-(p1+pe+tmp); + tmp+=p5+p7; + OUT1(3,tmp); + OUT2(35)=-(p6+pe+tmp); + tmp=pa+pb+pc+pd+pe+pf; + OUT2(39)=-(p2+p3+tmp-pc); + OUT2(43)=-(p4+p6+p7+tmp-pd); + OUT2(37)=-(p5+p6+p7+tmp-pc); + OUT2(41)=-(p2+p3+tmp-pd); + tmp=p8+pc+pe+pf; + OUT2(47)=-(p0+tmp); + OUT2(45)=-(p4+p6+p7+tmp); + tmp=pb+pf; + OUT1(11,p7+tmp); + tmp+=p3; + OUT1( 9,tmp); + OUT1( 7,pd+tmp); + OUT1(13,p7+pf); + OUT1(15,pf); + } + +} + + diff --git a/mpeglib/lib/splay/dct64_down.cpp b/mpeglib/lib/splay/dct64_down.cpp new file mode 100644 index 00000000..7137664c --- /dev/null +++ b/mpeglib/lib/splay/dct64_down.cpp @@ -0,0 +1,215 @@ +/* + wrapper for dcts + Copyright (C) 2001 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 "dct.h" +#include "common.h" + +#include <iostream> + +using namespace std; + +ATTR_ALIGN(64) static REAL hcos_64_down[16]; +ATTR_ALIGN(64) static REAL hcos_32_down[8]; +ATTR_ALIGN(64) static REAL hcos_16_down[4]; +ATTR_ALIGN(64) static REAL hcos_8_down[2]; +ATTR_ALIGN(64) static REAL hcos_4_down; + +/** + This was some time ago a standalone dct class, + but to get more speed I made it an inline dct + int the filter classes +*/ + +static int dctInit=false; + +void initialize_dct64_downsample() { + if (dctInit==true) { + return; + } + dctInit=true; + + int i; + + for(i=0;i<16;i++) { + hcos_64_down[i]=1.0/(2.0*cos(MY_PI*double(i*2+1)/64.0)); + } + for(i=0;i< 8;i++) { + hcos_32_down[i]=1.0/(2.0*cos(MY_PI*double(i*2+1)/32.0)); + } + for(i=0;i< 4;i++) { + hcos_16_down[i]=1.0/(2.0*cos(MY_PI*double(i*2+1)/16.0)); + } + for(i=0;i< 2;i++) { + hcos_8_down[i]=1.0/(2.0*cos(MY_PI*double(i*2+1)/ 8.0)); + } + hcos_4_down=1.0/(2.0*cos(MY_PI*1.0/4.0)); + +} + +inline void dct64_downsample(REAL* out1,REAL* out2,REAL *fraction) { + REAL p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,pa,pb,pc,pd,pe,pf; + REAL q0,q1,q2,q3,q4,q5,q6,q7,q8,q9,qa,qb,qc,qd,qe,qf; + +#define OUT1(v,t) out1[(32-(v))*16] =(-(out1[(v)*16]=t)) +#define OUT2(v) out2[(96-(v)-32)*16]=out2[((v)-32)*16] + + // compute new values via a fast cosine transform: + /* { + register REAL *x=fraction; + + p0=x[ 0]+x[31];p1=x[ 1]+x[30];p2=x[ 2]+x[29];p3=x[ 3]+x[28]; + p4=x[ 4]+x[27];p5=x[ 5]+x[26];p6=x[ 6]+x[25];p7=x[ 7]+x[24]; + p8=x[ 8]+x[23];p9=x[ 9]+x[22];pa=x[10]+x[21];pb=x[11]+x[20]; + pc=x[12]+x[19];pd=x[13]+x[18];pe=x[14]+x[17];pf=x[15]+x[16]; + } + + q0=p0+pf;q1=p1+pe;q2=p2+pd;q3=p3+pc; + q4=p4+pb;q5=p5+pa;q6=p6+p9;q7=p7+p8; + q8=hcos_32_down[0]*(p0-pf);q9=hcos_32_down[1]*(p1-pe); + qa=hcos_32_down[2]*(p2-pd);qb=hcos_32_down[3]*(p3-pc); + qc=hcos_32_down[4]*(p4-pb);qd=hcos_32_down[5]*(p5-pa); + qe=hcos_32_down[6]*(p6-p9);qf=hcos_32_down[7]*(p7-p8); */ + + { + + register REAL *x=fraction; + + q0=x[ 0]+x[15];q1=x[ 1]+x[14];q2=x[ 2]+x[13];q3=x[ 3]+x[12]; + q4=x[ 4]+x[11];q5=x[ 5]+x[10];q6=x[ 6]+x[ 9];q7=x[ 7]+x[ 8]; + + q8=hcos_32_down[0]*(x[ 0]-x[15]);q9=hcos_32_down[1]*(x[ 1]-x[14]); + qa=hcos_32_down[2]*(x[ 2]-x[13]);qb=hcos_32_down[3]*(x[ 3]-x[12]); + qc=hcos_32_down[4]*(x[ 4]-x[11]);qd=hcos_32_down[5]*(x[ 5]-x[10]); + qe=hcos_32_down[6]*(x[ 6]-x[ 9]);qf=hcos_32_down[7]*(x[ 7]-x[ 8]); + } + + p0=q0+q7;p1=q1+q6;p2=q2+q5;p3=q3+q4; + p4=hcos_16_down[0]*(q0-q7);p5=hcos_16_down[1]*(q1-q6); + p6=hcos_16_down[2]*(q2-q5);p7=hcos_16_down[3]*(q3-q4); + p8=q8+qf;p9=q9+qe;pa=qa+qd;pb=qb+qc; + pc=hcos_16_down[0]*(q8-qf);pd=hcos_16_down[1]*(q9-qe); + pe=hcos_16_down[2]*(qa-qd);pf=hcos_16_down[3]*(qb-qc); + + q0=p0+p3;q1=p1+p2;q2=hcos_8_down[0]*(p0-p3);q3=hcos_8_down[1]*(p1-p2); + q4=p4+p7;q5=p5+p6;q6=hcos_8_down[0]*(p4-p7);q7=hcos_8_down[1]*(p5-p6); + q8=p8+pb;q9=p9+pa;qa=hcos_8_down[0]*(p8-pb);qb=hcos_8_down[1]*(p9-pa); + qc=pc+pf;qd=pd+pe;qe=hcos_8_down[0]*(pc-pf);qf=hcos_8_down[1]*(pd-pe); + + p0=q0+q1;p1=hcos_4_down*(q0-q1);p2=q2+q3;p3=hcos_4_down*(q2-q3); + p4=q4+q5;p5=hcos_4_down*(q4-q5);p6=q6+q7;p7=hcos_4_down*(q6-q7); + p8=q8+q9;p9=hcos_4_down*(q8-q9);pa=qa+qb;pb=hcos_4_down*(qa-qb); + pc=qc+qd;pd=hcos_4_down*(qc-qd);pe=qe+qf;pf=hcos_4_down*(qe-qf); + + { + register REAL tmp; + + tmp=p6+p7; + OUT2(36)=-(p5+tmp); + OUT2(44)=-(p4+tmp); + tmp=pb+pf; + OUT1(10,tmp); + OUT1(6,pd+tmp); + tmp=pe+pf; + OUT2(46)=-(p8+pc+tmp); + OUT2(34)=-(p9+pd+tmp); + tmp+=pa+pb; + OUT2(38)=-(pd+tmp); + OUT2(42)=-(pc+tmp); + OUT1(2,p9+pd+pf); + OUT1(4,p5+p7); + OUT2(48)=-p0; + out2[0]=-(out1[0]=p1); + OUT1( 8,p3); + OUT1(12,p7); + OUT1(14,pf); + OUT2(40)=-(p2+p3); + } + + { + register REAL *x=fraction; + + /* p0=hcos_64_down[ 0]*(x[ 0]-x[31]);p1=hcos_64_down[ 1]*(x[ 1]-x[30]); + p2=hcos_64_down[ 2]*(x[ 2]-x[29]);p3=hcos_64_down[ 3]*(x[ 3]-x[28]); + p4=hcos_64_down[ 4]*(x[ 4]-x[27]);p5=hcos_64_down[ 5]*(x[ 5]-x[26]); + p6=hcos_64_down[ 6]*(x[ 6]-x[25]);p7=hcos_64_down[ 7]*(x[ 7]-x[24]); + p8=hcos_64_down[ 8]*(x[ 8]-x[23]);p9=hcos_64_down[ 9]*(x[ 9]-x[22]); + pa=hcos_64_down[10]*(x[10]-x[21]);pb=hcos_64_down[11]*(x[11]-x[20]); + pc=hcos_64_down[12]*(x[12]-x[19]);pd=hcos_64_down[13]*(x[13]-x[18]); + pe=hcos_64_down[14]*(x[14]-x[17]);pf=hcos_64_down[15]*(x[15]-x[16]); */ + + p0=hcos_64_down[ 0]*x[ 0];p1=hcos_64_down[ 1]*x[ 1]; + p2=hcos_64_down[ 2]*x[ 2];p3=hcos_64_down[ 3]*x[ 3]; + p4=hcos_64_down[ 4]*x[ 4];p5=hcos_64_down[ 5]*x[ 5]; + p6=hcos_64_down[ 6]*x[ 6];p7=hcos_64_down[ 7]*x[ 7]; + p8=hcos_64_down[ 8]*x[ 8];p9=hcos_64_down[ 9]*x[ 9]; + pa=hcos_64_down[10]*x[10];pb=hcos_64_down[11]*x[11]; + pc=hcos_64_down[12]*x[12];pd=hcos_64_down[13]*x[13]; + pe=hcos_64_down[14]*x[14];pf=hcos_64_down[15]*x[15]; + } + + q0=p0+pf;q1=p1+pe;q2=p2+pd;q3=p3+pc; + q4=p4+pb;q5=p5+pa;q6=p6+p9;q7=p7+p8; + q8=hcos_32_down[0]*(p0-pf);q9=hcos_32_down[1]*(p1-pe); + qa=hcos_32_down[2]*(p2-pd);qb=hcos_32_down[3]*(p3-pc); + qc=hcos_32_down[4]*(p4-pb);qd=hcos_32_down[5]*(p5-pa); + qe=hcos_32_down[6]*(p6-p9);qf=hcos_32_down[7]*(p7-p8); + + p0=q0+q7;p1=q1+q6;p2=q2+q5;p3=q3+q4; + p4=hcos_16_down[0]*(q0-q7);p5=hcos_16_down[1]*(q1-q6); + p6=hcos_16_down[2]*(q2-q5);p7=hcos_16_down[3]*(q3-q4); + p8=q8+qf;p9=q9+qe;pa=qa+qd;pb=qb+qc; + pc=hcos_16_down[0]*(q8-qf);pd=hcos_16_down[1]*(q9-qe); + pe=hcos_16_down[2]*(qa-qd);pf=hcos_16_down[3]*(qb-qc); + + q0=p0+p3;q1=p1+p2;q2=hcos_8_down[0]*(p0-p3);q3=hcos_8_down[1]*(p1-p2); + q4=p4+p7;q5=p5+p6;q6=hcos_8_down[0]*(p4-p7);q7=hcos_8_down[1]*(p5-p6); + q8=p8+pb;q9=p9+pa;qa=hcos_8_down[0]*(p8-pb);qb=hcos_8_down[1]*(p9-pa); + qc=pc+pf;qd=pd+pe;qe=hcos_8_down[0]*(pc-pf);qf=hcos_8_down[1]*(pd-pe); + + p0=q0+q1;p1=hcos_4_down*(q0-q1); + p2=q2+q3;p3=hcos_4_down*(q2-q3); + p4=q4+q5;p5=hcos_4_down*(q4-q5); + p6=q6+q7;p7=hcos_4_down*(q6-q7); + p8=q8+q9;p9=hcos_4_down*(q8-q9); + pa=qa+qb;pb=hcos_4_down*(qa-qb); + pc=qc+qd;pd=hcos_4_down*(qc-qd); + pe=qe+qf;pf=hcos_4_down*(qe-qf); + + { + REAL tmp; + + tmp=pd+pf; + OUT1(5,p5+p7+pb+tmp); + tmp+=p9; + OUT1(1,p1+tmp); + OUT2(33)=-(p1+pe+tmp); + tmp+=p5+p7; + OUT1(3,tmp); + OUT2(35)=-(p6+pe+tmp); + tmp=pa+pb+pc+pd+pe+pf; + OUT2(39)=-(p2+p3+tmp-pc); + OUT2(43)=-(p4+p6+p7+tmp-pd); + OUT2(37)=-(p5+p6+p7+tmp-pc); + OUT2(41)=-(p2+p3+tmp-pd); + tmp=p8+pc+pe+pf; + OUT2(47)=-(p0+tmp); + OUT2(45)=-(p4+p6+p7+tmp); + tmp=pb+pf; + OUT1(11,p7+tmp); + tmp+=p3; + OUT1( 9,tmp); + OUT1( 7,pd+tmp); + OUT1(13,p7+pf); + OUT1(15,pf); + } +} + diff --git a/mpeglib/lib/splay/dump.cpp b/mpeglib/lib/splay/dump.cpp new file mode 100644 index 00000000..62551194 --- /dev/null +++ b/mpeglib/lib/splay/dump.cpp @@ -0,0 +1,157 @@ +/* + frame dumper + Copyright (C) 2001 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 + + */ + + +typedef float REAL; + +#define SSLIMIT 18 +#define SBLIMIT 32 + + + +#include "dump.h" +#include <stdio.h> + + +Dump::Dump() { + +} + + +Dump::~Dump() { +} + + +void Dump::dump(REAL out[SBLIMIT][SSLIMIT]) { + FILE* f=fopen("dump.raw","a+"); + int i; + int j; + for(i=0;i<SBLIMIT;i++) { + fprintf(f,"Line:%d\n",i); + for(j=0;j<SSLIMIT;j++) { + fprintf(f,"%.25f\n",out[i][j]); + } + } + fclose(f); +} + +void Dump::dump(REAL out[SBLIMIT*SSLIMIT]) { + FILE* f=fopen("dump.raw","a+"); + int i; + int line=0; + for(i=0;i<SBLIMIT*SSLIMIT;i++) { + if ( (i % SSLIMIT) == 0) { + fprintf(f,"Line:%d\n",line++); + } + fprintf(f,"%.25f\n",out[i]); + } + fclose(f); +} + +void Dump::dump2(REAL out[SSLIMIT*SBLIMIT]) { + FILE* f=fopen("dump.raw","a+"); + int i; + int j; + int line=0; + for(i=0;i<SSLIMIT;i++) { + fprintf(f,"Line:%d\n",line++); + for(j=0;j<SBLIMIT;j++) { + fprintf(f,"%.25f\n",out[i*SBLIMIT+j]); + } + } + fclose(f); +} + +void Dump::dump(REAL out[SSLIMIT][SBLIMIT]) { + FILE* f=fopen("dump.raw","a+"); + int i; + int j; + for(i=0;i<SBLIMIT;i++) { + fprintf(f,"Line:%d\n",i); + for(j=0;j<SSLIMIT;j++) { + fprintf(f,"%.25f\n",out[j][i]); + } + } + fclose(f); +} + +void Dump::dump(int out[SBLIMIT][SSLIMIT]) { + FILE* f=fopen("dump.raw","a+"); + int i; + int j; + for(i=0;i<SBLIMIT;i++) { + fprintf(f,"Line:%d\n",i); + for(j=0;j<SSLIMIT;j++) { + if (out[i][j] == 0) { + fprintf(f," %d ",out[i][j]); + continue; + } + if (out[i][j] < 0) { + fprintf(f," -x"); + continue; + } + fprintf(f," +x"); + + } + fprintf(f," \n"); + + } + fclose(f); +} + +void Dump::dump(char* ptr,int len,int ldelete) { + FILE* f; + if (ldelete) { + f=fopen("/tmp/dump.raw","w+"); + } else { + f=fopen("/tmp/dump.raw","a+"); + } + fwrite(ptr,len,1,f); + fclose(f); +} + + +void Dump::scale_zero(layer3scalefactor* out) { + + int i; + int j; + + for(i=0;i<23;i++) { + out->l[i]=0; + } + + for(i=0;i<3;i++) { + for(j=0;j<13;j++) { + out->s[i][j]=0; + } + } +} + + +void Dump::dump(layer3scalefactor* out) { + FILE* f=fopen("dump.raw","a+"); + int i; + int j; + + for(i=0;i<23;i++) { + fprintf(f,"l[%d]=%d\n",i,out->l[i]); + } + + for(i=0;i<3;i++) { + for(j=0;j<13;j++) { + fprintf(f,"s[%d][%d]=%d\n",i,j,out->s[i][j]); + } + } + fprintf(f,"---------\n"); + + fclose(f); +} diff --git a/mpeglib/lib/splay/dump.h b/mpeglib/lib/splay/dump.h new file mode 100644 index 00000000..47ef4d48 --- /dev/null +++ b/mpeglib/lib/splay/dump.h @@ -0,0 +1,36 @@ +/* + frame dumper + Copyright (C) 2001 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 __DUMP_H +#define __DUMP_H + +#include "mpegsound.h" + +class Dump { + + public: + Dump(); + ~Dump(); + + void dump(REAL out[SBLIMIT][SSLIMIT]); + void dump(REAL out[SBLIMIT*SSLIMIT]); + void dump2(REAL out[SSLIMIT*SBLIMIT]); + void dump(REAL out[SSLIMIT][SBLIMIT]); + void dump(int out[SBLIMIT][SSLIMIT]); + void dump(layer3scalefactor* out); + void dump(char* prt,int len,int ldelete=false); + void scale_zero(layer3scalefactor* out); + + +}; +#endif diff --git a/mpeglib/lib/splay/dxHead.cpp b/mpeglib/lib/splay/dxHead.cpp new file mode 100644 index 00000000..a96bb553 --- /dev/null +++ b/mpeglib/lib/splay/dxHead.cpp @@ -0,0 +1,129 @@ +/*---- DXhead.c -------------------------------------------- + +decoder MPEG Layer III +handle Xing header +mod 12/7/98 add vbr scale + +Copyright 1998 Xing Technology Corp. +-----------------------------------------------------------*/ +#include <stdlib.h> +#include <stdio.h> +#include <float.h> +#include <math.h> +#include "dxHead.h" + +// 4 Xing +// 4 flags +// 4 frames +// 4 bytes +// 100 toc + +/*-------------------------------------------------------------*/ +static int ExtractI4(unsigned char *buf) +{ +int x; +// big endian extract + +x = buf[0]; +x <<= 8; +x |= buf[1]; +x <<= 8; +x |= buf[2]; +x <<= 8; +x |= buf[3]; + +return x; +} +/*-------------------------------------------------------------*/ +int GetXingHeader(XHEADDATA *X, unsigned char *buf) +{ +int i, head_flags; +int h_id, h_mode, h_sr_index; +static const int sr_table[4] = { 44100, 48000, 32000, 99999 }; + +// get Xing header data + + +X->flags = 0; // clear to null incase fail + + +// get selected MPEG header data +h_id = (buf[1] >> 3) & 1; +h_sr_index = (buf[2] >> 2) & 3; +h_mode = (buf[3] >> 6) & 3; + + +// determine offset of header +if( h_id ) { // mpeg1 + if( h_mode != 3 ) buf+=(32+4); + else buf+=(17+4); +} +else { // mpeg2 + if( h_mode != 3 ) buf+=(17+4); + else buf+=(9+4); +} + +if( buf[0] != 'X' ) return 0; // fail +if( buf[1] != 'i' ) return 0; // header not found +if( buf[2] != 'n' ) return 0; +if( buf[3] != 'g' ) return 0; +buf+=4; + +X->h_id = h_id; +X->samprate = sr_table[h_sr_index]; +if( h_id == 0 ) X->samprate >>= 1; + +head_flags = X->flags = ExtractI4(buf); buf+=4; // get flags + +if( head_flags & FRAMES_FLAG ) {X->frames = ExtractI4(buf); buf+=4;} +if( head_flags & BYTES_FLAG ) {X->bytes = ExtractI4(buf); buf+=4;} + +if( head_flags & TOC_FLAG ) { + if( X->toc != NULL ) { + for(i=0;i<100;i++) X->toc[i] = buf[i]; + } + buf+=100; +} + +X->vbr_scale = -1; +if( head_flags & VBR_SCALE_FLAG ) {X->vbr_scale = ExtractI4(buf); buf+=4;} + +//if( X->toc != NULL ) { +//for(i=0;i<100;i++) { +// if( (i%10) == 0 ) printf("\n"); +// printf(" %3d", (int)(X->toc[i])); +//} +//} + +return 1; // success +} +/*-------------------------------------------------------------*/ +int SeekPoint(unsigned char TOC[100], int file_bytes, float percent) +{ +// interpolate in TOC to get file seek point in bytes +int a, seekpoint; +float fa, fb, fx; + + +if( percent < 0.0f ) percent = 0.0f; +if( percent > 100.0f ) percent = 100.0f; + +a = (int)percent; +if( a > 99 ) a = 99; +fa = TOC[a]; +if( a < 99 ) { + fb = TOC[a+1]; +} +else { + fb = 256.0f; +} + +fx = fa + (fb-fa)*(percent-a); +//printf("%f ....... %f ...... %f\n",fa,fb,fx); + +seekpoint = (int)((1.0f/256.0f)*fx*file_bytes); + + +return seekpoint; +} +/*-------------------------------------------------------------*/ diff --git a/mpeglib/lib/splay/dxHead.h b/mpeglib/lib/splay/dxHead.h new file mode 100644 index 00000000..da0f2eff --- /dev/null +++ b/mpeglib/lib/splay/dxHead.h @@ -0,0 +1,66 @@ +/*---- DXhead.h ------------------------------------------- + + +decoder MPEG Layer III + +handle Xing header + + +Copyright 1998 Xing Technology Corp. +-----------------------------------------------------------*/ +// A Xing header may be present in the ancillary +// data field of the first frame of an mp3 bitstream +// The Xing header (optionally) contains +// frames total number of audio frames in the bitstream +// bytes total number of bytes in the bitstream +// toc table of contents + +// toc (table of contents^) gives seek points +// for random access +// the ith entry determines the seek point for +// i-percent duration +// seek point in bytes = (toc[i]/256.0) * total_bitstream_bytes +// e.g. half duration seek point = (toc[50]/256.0) * total_bitstream_bytes + +#ifndef __DXHEAD_H +#define __DXHEAD_H + +#define FRAMES_FLAG 0x0001 +#define BYTES_FLAG 0x0002 +#define TOC_FLAG 0x0004 +#define VBR_SCALE_FLAG 0x0008 + +#define FRAMES_AND_BYTES (FRAMES_FLAG | BYTES_FLAG) + +// structure to receive extracted header +// toc may be NULL + +typedef struct XHEADDATA_s { + int h_id; // from MPEG header, 0=MPEG2, 1=MPEG1 + int samprate; // determined from MPEG header + int flags; // from Xing header data + int frames; // total bit stream frames from Xing header data + int bytes; // total bit stream bytes from Xing header data + int vbr_scale; // encoded vbr scale from Xing header data + unsigned char *toc; // pointer to unsigned char toc_buffer[100] + // may be NULL if toc not desired +} XHEADDATA; + +int GetXingHeader(XHEADDATA *X, unsigned char *buf); + +// return 0=fail, 1=success +// X structure to receive header data (output) +// buf bitstream input + + +int SeekPoint(unsigned char TOC[100], int file_bytes, float percent); +// return seekpoint in bytes (may be at eof if percent=100.0) +// TOC = table of contents from Xing header +// file_bytes = number of bytes in mp3 file +// percent = play time percentage of total playtime. May be +// fractional (e.g. 87.245) + + +#endif + + diff --git a/mpeglib/lib/splay/huffmanlookup.cpp b/mpeglib/lib/splay/huffmanlookup.cpp new file mode 100644 index 00000000..e4b37453 --- /dev/null +++ b/mpeglib/lib/splay/huffmanlookup.cpp @@ -0,0 +1,120 @@ + /* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + + This library 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; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include "huffmanlookup.h" +#include <assert.h> + + + + +struct HuffmanLookup::decodeData HuffmanLookup::qdecode[32][256]; +/* for initialization */ +static HuffmanLookup l; + +HuffmanLookup::HuffmanLookup() +{ + int table,p,x,y; + + for(table = 0; table < 32; table++) + { + // 8 bits pattern + for(p = 0; p < 256; p++) + { + bits = 24; + pattern = (p << 16); + + huffmandecoder_1(&Mpegtoraw::ht[table], &x,&y); + + int used = 24 - bits; + qdecode[table][p].skip = (used <= 8)?used:0; + qdecode[table][p].x = x; + qdecode[table][p].y = y; + } + } +} + +int HuffmanLookup::wgetbit() +{ + return (pattern >> --bits) & 1; +} + +int HuffmanLookup::wgetbits (int b) +{ + bits -= b; + return (pattern >> bits) & ((1 << b) - 1); +} + +void HuffmanLookup::huffmandecoder_1(const HUFFMANCODETABLE *h, int *x, int *y) +{ + typedef unsigned int HUFFBITS; + + HUFFBITS level=(1<<(sizeof(HUFFBITS)*8-1)); + int point=0; + /* Lookup in Huffman table. */ + for(;;) + { + if(h->val[point][0]==0) + { /*end of tree*/ + int xx,yy; + + xx=h->val[point][1]>>4; + yy=h->val[point][1]&0xf; + + if(h->linbits) + { + if((h->xlen)==(unsigned)xx)xx+=wgetbits(h->linbits); + if(xx)if(wgetbit())xx=-xx; + if((h->ylen)==(unsigned)yy)yy+=wgetbits(h->linbits); + if(yy)if(wgetbit())yy=-yy; + } + else + { + if(xx)if(wgetbit())xx=-xx; + if(yy)if(wgetbit())yy=-yy; + } + *x=xx;*y=yy; + break; + } + + point+=h->val[point][wgetbit()]; + + level>>=1; + if(!(level || ((unsigned)point<Mpegtoraw::ht->treelen))) + { + register int xx,yy; + + xx=(h->xlen<<1);// set x and y to a medium value as a simple concealment + yy=(h->ylen<<1); + + // h->xlen and h->ylen can't be 1 under tablename 32 + // if(xx) + if(wgetbit())xx=-xx; + // if(yy) + if(wgetbit())yy=-yy; + + *x=xx;*y=yy; + break; + } + } +} + + diff --git a/mpeglib/lib/splay/huffmanlookup.h b/mpeglib/lib/splay/huffmanlookup.h new file mode 100644 index 00000000..a5bdb26c --- /dev/null +++ b/mpeglib/lib/splay/huffmanlookup.h @@ -0,0 +1,57 @@ + /* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + + This library 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; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#ifndef __HUFFMANLOOKUP_H +#define __HUFFMANLOOKUP_H +#include "mpegsound.h" + +/* + * This class speeds up the huffman table decoding by largely replacing it + * by a table lookup. It uses the fact that the huffman tables don't change, + * and that given a byte of the bitstream, we can predict what the result + * will be (without reading it bit by bit). + */ + +class HuffmanLookup { +private: + long pattern, bits; + int wgetbit(); + int wgetbits (int b); + void huffmandecoder_1(const HUFFMANCODETABLE *h,int *x, int *y); + + ATTR_ALIGN(64) static struct decodeData { + int x : 8; + int y : 8; + int skip : 16; + } qdecode[32][256]; +public: + HuffmanLookup(); + + static int decode(int table, int pattern, int* x, int* y) + { + *x = qdecode[table][pattern].x; + *y = qdecode[table][pattern].y; + return qdecode[table][pattern].skip; + } +}; + +#endif diff --git a/mpeglib/lib/splay/huffmantable.cpp b/mpeglib/lib/splay/huffmantable.cpp new file mode 100644 index 00000000..a1fe20e5 --- /dev/null +++ b/mpeglib/lib/splay/huffmantable.cpp @@ -0,0 +1,584 @@ +/* MPEG/WAVE Sound library + + (C) 1997 by Jung woo-jae */ + +// Huffmantable.cc +// It contains initialized huffman table for MPEG layer 3 + + +#include "mpegsound.h" + +static const unsigned int +htd01[ 7][2]={{ 2, 1},{ 0, 0},{ 2, 1},{ 0, 16},{ 2, 1},{ 0, 1}, + { 0, 17}}, + +htd02[ 17][2]={{ 2, 1},{ 0, 0},{ 4, 1},{ 2, 1},{ 0, 16},{ 0, 1}, + { 2, 1},{ 0, 17},{ 4, 1},{ 2, 1},{ 0, 32},{ 0, 33}, + { 2, 1},{ 0, 18},{ 2, 1},{ 0, 2},{ 0, 34}}, + +htd03[ 17][2]={{ 4, 1},{ 2, 1},{ 0, 0},{ 0, 1},{ 2, 1},{ 0, 17}, + { 2, 1},{ 0, 16},{ 4, 1},{ 2, 1},{ 0, 32},{ 0, 33}, + { 2, 1},{ 0, 18},{ 2, 1},{ 0, 2},{ 0, 34}}, + +htd05[ 31][2]={{ 2, 1},{ 0, 0},{ 4, 1},{ 2, 1},{ 0, 16},{ 0, 1}, + { 2, 1},{ 0, 17},{ 8, 1},{ 4, 1},{ 2, 1},{ 0, 32}, + { 0, 2},{ 2, 1},{ 0, 33},{ 0, 18},{ 8, 1},{ 4, 1}, + { 2, 1},{ 0, 34},{ 0, 48},{ 2, 1},{ 0, 3},{ 0, 19}, + { 2, 1},{ 0, 49},{ 2, 1},{ 0, 50},{ 2, 1},{ 0, 35}, + { 0, 51}}, + +htd06[ 31][2]={{ 6, 1},{ 4, 1},{ 2, 1},{ 0, 0},{ 0, 16},{ 0, 17}, + { 6, 1},{ 2, 1},{ 0, 1},{ 2, 1},{ 0, 32},{ 0, 33}, + { 6, 1},{ 2, 1},{ 0, 18},{ 2, 1},{ 0, 2},{ 0, 34}, + { 4, 1},{ 2, 1},{ 0, 49},{ 0, 19},{ 4, 1},{ 2, 1}, + { 0, 48},{ 0, 50},{ 2, 1},{ 0, 35},{ 2, 1},{ 0, 3}, + { 0, 51}}, + +htd07[ 71][2]={{ 2, 1},{ 0, 0},{ 4, 1},{ 2, 1},{ 0, 16},{ 0, 1}, + { 8, 1},{ 2, 1},{ 0, 17},{ 4, 1},{ 2, 1},{ 0, 32}, + { 0, 2},{ 0, 33},{ 18, 1},{ 6, 1},{ 2, 1},{ 0, 18}, + { 2, 1},{ 0, 34},{ 0, 48},{ 4, 1},{ 2, 1},{ 0, 49}, + { 0, 19},{ 4, 1},{ 2, 1},{ 0, 3},{ 0, 50},{ 2, 1}, + { 0, 35},{ 0, 4},{ 10, 1},{ 4, 1},{ 2, 1},{ 0, 64}, + { 0, 65},{ 2, 1},{ 0, 20},{ 2, 1},{ 0, 66},{ 0, 36}, + { 12, 1},{ 6, 1},{ 4, 1},{ 2, 1},{ 0, 51},{ 0, 67}, + { 0, 80},{ 4, 1},{ 2, 1},{ 0, 52},{ 0, 5},{ 0, 81}, + { 6, 1},{ 2, 1},{ 0, 21},{ 2, 1},{ 0, 82},{ 0, 37}, + + { 4, 1},{ 2, 1},{ 0, 68},{ 0, 53},{ 4, 1},{ 2, 1}, + { 0, 83},{ 0, 84},{ 2, 1},{ 0, 69},{ 0, 85}}, + +htd08[ 71][2]={{ 6, 1},{ 2, 1},{ 0, 0},{ 2, 1},{ 0, 16},{ 0, 1}, + { 2, 1},{ 0, 17},{ 4, 1},{ 2, 1},{ 0, 33},{ 0, 18}, + { 14, 1},{ 4, 1},{ 2, 1},{ 0, 32},{ 0, 2},{ 2, 1}, + { 0, 34},{ 4, 1},{ 2, 1},{ 0, 48},{ 0, 3},{ 2, 1}, + { 0, 49},{ 0, 19},{ 14, 1},{ 8, 1},{ 4, 1},{ 2, 1}, + { 0, 50},{ 0, 35},{ 2, 1},{ 0, 64},{ 0, 4},{ 2, 1}, + { 0, 65},{ 2, 1},{ 0, 20},{ 0, 66},{ 12, 1},{ 6, 1}, + { 2, 1},{ 0, 36},{ 2, 1},{ 0, 51},{ 0, 80},{ 4, 1}, + { 2, 1},{ 0, 67},{ 0, 52},{ 0, 81},{ 6, 1},{ 2, 1}, + { 0, 21},{ 2, 1},{ 0, 5},{ 0, 82},{ 6, 1},{ 2, 1}, + + { 0, 37},{ 2, 1},{ 0, 68},{ 0, 53},{ 2, 1},{ 0, 83}, + { 2, 1},{ 0, 69},{ 2, 1},{ 0, 84},{ 0, 85}}, + +htd09[ 71][2]={{ 8, 1},{ 4, 1},{ 2, 1},{ 0, 0},{ 0, 16},{ 2, 1}, + { 0, 1},{ 0, 17},{ 10, 1},{ 4, 1},{ 2, 1},{ 0, 32}, + { 0, 33},{ 2, 1},{ 0, 18},{ 2, 1},{ 0, 2},{ 0, 34}, + { 12, 1},{ 6, 1},{ 4, 1},{ 2, 1},{ 0, 48},{ 0, 3}, + { 0, 49},{ 2, 1},{ 0, 19},{ 2, 1},{ 0, 50},{ 0, 35}, + { 12, 1},{ 4, 1},{ 2, 1},{ 0, 65},{ 0, 20},{ 4, 1}, + { 2, 1},{ 0, 64},{ 0, 51},{ 2, 1},{ 0, 66},{ 0, 36}, + { 10, 1},{ 6, 1},{ 4, 1},{ 2, 1},{ 0, 4},{ 0, 80}, + { 0, 67},{ 2, 1},{ 0, 52},{ 0, 81},{ 8, 1},{ 4, 1}, + { 2, 1},{ 0, 21},{ 0, 82},{ 2, 1},{ 0, 37},{ 0, 68}, + + { 6, 1},{ 4, 1},{ 2, 1},{ 0, 5},{ 0, 84},{ 0, 83}, + { 2, 1},{ 0, 53},{ 2, 1},{ 0, 69},{ 0, 85}}, + +htd10[127][2]={{ 2, 1},{ 0, 0},{ 4, 1},{ 2, 1},{ 0, 16},{ 0, 1}, + { 10, 1},{ 2, 1},{ 0, 17},{ 4, 1},{ 2, 1},{ 0, 32}, + { 0, 2},{ 2, 1},{ 0, 33},{ 0, 18},{ 28, 1},{ 8, 1}, + { 4, 1},{ 2, 1},{ 0, 34},{ 0, 48},{ 2, 1},{ 0, 49}, + { 0, 19},{ 8, 1},{ 4, 1},{ 2, 1},{ 0, 3},{ 0, 50}, + { 2, 1},{ 0, 35},{ 0, 64},{ 4, 1},{ 2, 1},{ 0, 65}, + { 0, 20},{ 4, 1},{ 2, 1},{ 0, 4},{ 0, 51},{ 2, 1}, + { 0, 66},{ 0, 36},{ 28, 1},{ 10, 1},{ 6, 1},{ 4, 1}, + { 2, 1},{ 0, 80},{ 0, 5},{ 0, 96},{ 2, 1},{ 0, 97}, + { 0, 22},{ 12, 1},{ 6, 1},{ 4, 1},{ 2, 1},{ 0, 67}, + + { 0, 52},{ 0, 81},{ 2, 1},{ 0, 21},{ 2, 1},{ 0, 82}, + { 0, 37},{ 4, 1},{ 2, 1},{ 0, 38},{ 0, 54},{ 0,113}, + { 20, 1},{ 8, 1},{ 2, 1},{ 0, 23},{ 4, 1},{ 2, 1}, + { 0, 68},{ 0, 83},{ 0, 6},{ 6, 1},{ 4, 1},{ 2, 1}, + { 0, 53},{ 0, 69},{ 0, 98},{ 2, 1},{ 0,112},{ 2, 1}, + { 0, 7},{ 0,100},{ 14, 1},{ 4, 1},{ 2, 1},{ 0,114}, + { 0, 39},{ 6, 1},{ 2, 1},{ 0, 99},{ 2, 1},{ 0, 84}, + { 0, 85},{ 2, 1},{ 0, 70},{ 0,115},{ 8, 1},{ 4, 1}, + { 2, 1},{ 0, 55},{ 0,101},{ 2, 1},{ 0, 86},{ 0,116}, + { 6, 1},{ 2, 1},{ 0, 71},{ 2, 1},{ 0,102},{ 0,117}, + + { 4, 1},{ 2, 1},{ 0, 87},{ 0,118},{ 2, 1},{ 0,103}, + { 0,119}}, + +htd11[127][2]={{ 6, 1},{ 2, 1},{ 0, 0},{ 2, 1},{ 0, 16},{ 0, 1}, + { 8, 1},{ 2, 1},{ 0, 17},{ 4, 1},{ 2, 1},{ 0, 32}, + { 0, 2},{ 0, 18},{ 24, 1},{ 8, 1},{ 2, 1},{ 0, 33}, + { 2, 1},{ 0, 34},{ 2, 1},{ 0, 48},{ 0, 3},{ 4, 1}, + { 2, 1},{ 0, 49},{ 0, 19},{ 4, 1},{ 2, 1},{ 0, 50}, + { 0, 35},{ 4, 1},{ 2, 1},{ 0, 64},{ 0, 4},{ 2, 1}, + { 0, 65},{ 0, 20},{ 30, 1},{ 16, 1},{ 10, 1},{ 4, 1}, + { 2, 1},{ 0, 66},{ 0, 36},{ 4, 1},{ 2, 1},{ 0, 51}, + { 0, 67},{ 0, 80},{ 4, 1},{ 2, 1},{ 0, 52},{ 0, 81}, + { 0, 97},{ 6, 1},{ 2, 1},{ 0, 22},{ 2, 1},{ 0, 6}, + + { 0, 38},{ 2, 1},{ 0, 98},{ 2, 1},{ 0, 21},{ 2, 1}, + { 0, 5},{ 0, 82},{ 16, 1},{ 10, 1},{ 6, 1},{ 4, 1}, + { 2, 1},{ 0, 37},{ 0, 68},{ 0, 96},{ 2, 1},{ 0, 99}, + { 0, 54},{ 4, 1},{ 2, 1},{ 0,112},{ 0, 23},{ 0,113}, + { 16, 1},{ 6, 1},{ 4, 1},{ 2, 1},{ 0, 7},{ 0,100}, + { 0,114},{ 2, 1},{ 0, 39},{ 4, 1},{ 2, 1},{ 0, 83}, + { 0, 53},{ 2, 1},{ 0, 84},{ 0, 69},{ 10, 1},{ 4, 1}, + { 2, 1},{ 0, 70},{ 0,115},{ 2, 1},{ 0, 55},{ 2, 1}, + { 0,101},{ 0, 86},{ 10, 1},{ 6, 1},{ 4, 1},{ 2, 1}, + { 0, 85},{ 0, 87},{ 0,116},{ 2, 1},{ 0, 71},{ 0,102}, + + { 4, 1},{ 2, 1},{ 0,117},{ 0,118},{ 2, 1},{ 0,103}, + { 0,119}}, + +htd12[127][2]={{ 12, 1},{ 4, 1},{ 2, 1},{ 0, 16},{ 0, 1},{ 2, 1}, + { 0, 17},{ 2, 1},{ 0, 0},{ 2, 1},{ 0, 32},{ 0, 2}, + { 16, 1},{ 4, 1},{ 2, 1},{ 0, 33},{ 0, 18},{ 4, 1}, + { 2, 1},{ 0, 34},{ 0, 49},{ 2, 1},{ 0, 19},{ 2, 1}, + { 0, 48},{ 2, 1},{ 0, 3},{ 0, 64},{ 26, 1},{ 8, 1}, + { 4, 1},{ 2, 1},{ 0, 50},{ 0, 35},{ 2, 1},{ 0, 65}, + { 0, 51},{ 10, 1},{ 4, 1},{ 2, 1},{ 0, 20},{ 0, 66}, + { 2, 1},{ 0, 36},{ 2, 1},{ 0, 4},{ 0, 80},{ 4, 1}, + { 2, 1},{ 0, 67},{ 0, 52},{ 2, 1},{ 0, 81},{ 0, 21}, + { 28, 1},{ 14, 1},{ 8, 1},{ 4, 1},{ 2, 1},{ 0, 82}, + + { 0, 37},{ 2, 1},{ 0, 83},{ 0, 53},{ 4, 1},{ 2, 1}, + { 0, 96},{ 0, 22},{ 0, 97},{ 4, 1},{ 2, 1},{ 0, 98}, + { 0, 38},{ 6, 1},{ 4, 1},{ 2, 1},{ 0, 5},{ 0, 6}, + { 0, 68},{ 2, 1},{ 0, 84},{ 0, 69},{ 18, 1},{ 10, 1}, + { 4, 1},{ 2, 1},{ 0, 99},{ 0, 54},{ 4, 1},{ 2, 1}, + { 0,112},{ 0, 7},{ 0,113},{ 4, 1},{ 2, 1},{ 0, 23}, + { 0,100},{ 2, 1},{ 0, 70},{ 0,114},{ 10, 1},{ 6, 1}, + { 2, 1},{ 0, 39},{ 2, 1},{ 0, 85},{ 0,115},{ 2, 1}, + { 0, 55},{ 0, 86},{ 8, 1},{ 4, 1},{ 2, 1},{ 0,101}, + { 0,116},{ 2, 1},{ 0, 71},{ 0,102},{ 4, 1},{ 2, 1}, + + { 0,117},{ 0, 87},{ 2, 1},{ 0,118},{ 2, 1},{ 0,103}, + { 0,119}}, + +htd13[511][2]={{ 2, 1},{ 0, 0},{ 6, 1},{ 2, 1},{ 0, 16},{ 2, 1}, + { 0, 1},{ 0, 17},{ 28, 1},{ 8, 1},{ 4, 1},{ 2, 1}, + { 0, 32},{ 0, 2},{ 2, 1},{ 0, 33},{ 0, 18},{ 8, 1}, + { 4, 1},{ 2, 1},{ 0, 34},{ 0, 48},{ 2, 1},{ 0, 3}, + { 0, 49},{ 6, 1},{ 2, 1},{ 0, 19},{ 2, 1},{ 0, 50}, + { 0, 35},{ 4, 1},{ 2, 1},{ 0, 64},{ 0, 4},{ 0, 65}, + { 70, 1},{ 28, 1},{ 14, 1},{ 6, 1},{ 2, 1},{ 0, 20}, + { 2, 1},{ 0, 51},{ 0, 66},{ 4, 1},{ 2, 1},{ 0, 36}, + { 0, 80},{ 2, 1},{ 0, 67},{ 0, 52},{ 4, 1},{ 2, 1}, + { 0, 81},{ 0, 21},{ 4, 1},{ 2, 1},{ 0, 5},{ 0, 82}, // 60 + + { 2, 1},{ 0, 37},{ 2, 1},{ 0, 68},{ 0, 83},{ 14, 1}, + { 8, 1},{ 4, 1},{ 2, 1},{ 0, 96},{ 0, 6},{ 2, 1}, + { 0, 97},{ 0, 22},{ 4, 1},{ 2, 1},{ 0,128},{ 0, 8}, + { 0,129},{ 16, 1},{ 8, 1},{ 4, 1},{ 2, 1},{ 0, 53}, + { 0, 98},{ 2, 1},{ 0, 38},{ 0, 84},{ 4, 1},{ 2, 1}, + { 0, 69},{ 0, 99},{ 2, 1},{ 0, 54},{ 0,112},{ 6, 1}, + { 4, 1},{ 2, 1},{ 0, 7},{ 0, 85},{ 0,113},{ 2, 1}, + { 0, 23},{ 2, 1},{ 0, 39},{ 0, 55},{ 72, 1},{ 24, 1}, + { 12, 1},{ 4, 1},{ 2, 1},{ 0, 24},{ 0,130},{ 2, 1}, + { 0, 40},{ 4, 1},{ 2, 1},{ 0,100},{ 0, 70},{ 0,114}, // 120 + + { 8, 1},{ 4, 1},{ 2, 1},{ 0,132},{ 0, 72},{ 2, 1}, + { 0,144},{ 0, 9},{ 2, 1},{ 0,145},{ 0, 25},{ 24, 1}, + { 14, 1},{ 8, 1},{ 4, 1},{ 2, 1},{ 0,115},{ 0,101}, + { 2, 1},{ 0, 86},{ 0,116},{ 4, 1},{ 2, 1},{ 0, 71}, + { 0,102},{ 0,131},{ 6, 1},{ 2, 1},{ 0, 56},{ 2, 1}, + { 0,117},{ 0, 87},{ 2, 1},{ 0,146},{ 0, 41},{ 14, 1}, + { 8, 1},{ 4, 1},{ 2, 1},{ 0,103},{ 0,133},{ 2, 1}, + { 0, 88},{ 0, 57},{ 2, 1},{ 0,147},{ 2, 1},{ 0, 73}, + { 0,134},{ 6, 1},{ 2, 1},{ 0,160},{ 2, 1},{ 0,104}, + { 0, 10},{ 2, 1},{ 0,161},{ 0, 26},{ 68, 1},{ 24, 1}, // 180 + + { 12, 1},{ 4, 1},{ 2, 1},{ 0,162},{ 0, 42},{ 4, 1}, + { 2, 1},{ 0,149},{ 0, 89},{ 2, 1},{ 0,163},{ 0, 58}, + { 8, 1},{ 4, 1},{ 2, 1},{ 0, 74},{ 0,150},{ 2, 1}, + { 0,176},{ 0, 11},{ 2, 1},{ 0,177},{ 0, 27},{ 20, 1}, + { 8, 1},{ 2, 1},{ 0,178},{ 4, 1},{ 2, 1},{ 0,118}, + { 0,119},{ 0,148},{ 6, 1},{ 4, 1},{ 2, 1},{ 0,135}, + { 0,120},{ 0,164},{ 4, 1},{ 2, 1},{ 0,105},{ 0,165}, + { 0, 43},{ 12, 1},{ 6, 1},{ 4, 1},{ 2, 1},{ 0, 90}, + { 0,136},{ 0,179},{ 2, 1},{ 0, 59},{ 2, 1},{ 0,121}, + { 0,166},{ 6, 1},{ 4, 1},{ 2, 1},{ 0,106},{ 0,180}, // 240 + + { 0,192},{ 4, 1},{ 2, 1},{ 0, 12},{ 0,152},{ 0,193}, + { 60, 1},{ 22, 1},{ 10, 1},{ 6, 1},{ 2, 1},{ 0, 28}, + { 2, 1},{ 0,137},{ 0,181},{ 2, 1},{ 0, 91},{ 0,194}, + { 4, 1},{ 2, 1},{ 0, 44},{ 0, 60},{ 4, 1},{ 2, 1}, + { 0,182},{ 0,107},{ 2, 1},{ 0,196},{ 0, 76},{ 16, 1}, + { 8, 1},{ 4, 1},{ 2, 1},{ 0,168},{ 0,138},{ 2, 1}, + { 0,208},{ 0, 13},{ 2, 1},{ 0,209},{ 2, 1},{ 0, 75}, + { 2, 1},{ 0,151},{ 0,167},{ 12, 1},{ 6, 1},{ 2, 1}, + { 0,195},{ 2, 1},{ 0,122},{ 0,153},{ 4, 1},{ 2, 1}, + { 0,197},{ 0, 92},{ 0,183},{ 4, 1},{ 2, 1},{ 0, 29}, // 300 + + { 0,210},{ 2, 1},{ 0, 45},{ 2, 1},{ 0,123},{ 0,211}, + { 52, 1},{ 28, 1},{ 12, 1},{ 4, 1},{ 2, 1},{ 0, 61}, + { 0,198},{ 4, 1},{ 2, 1},{ 0,108},{ 0,169},{ 2, 1}, + { 0,154},{ 0,212},{ 8, 1},{ 4, 1},{ 2, 1},{ 0,184}, + { 0,139},{ 2, 1},{ 0, 77},{ 0,199},{ 4, 1},{ 2, 1}, + { 0,124},{ 0,213},{ 2, 1},{ 0, 93},{ 0,224},{ 10, 1}, + { 4, 1},{ 2, 1},{ 0,225},{ 0, 30},{ 4, 1},{ 2, 1}, + { 0, 14},{ 0, 46},{ 0,226},{ 8, 1},{ 4, 1},{ 2, 1}, + { 0,227},{ 0,109},{ 2, 1},{ 0,140},{ 0,228},{ 4, 1}, + { 2, 1},{ 0,229},{ 0,186},{ 0,240},{ 38, 1},{ 16, 1}, // 360 + + { 4, 1},{ 2, 1},{ 0,241},{ 0, 31},{ 6, 1},{ 4, 1}, + { 2, 1},{ 0,170},{ 0,155},{ 0,185},{ 2, 1},{ 0, 62}, + { 2, 1},{ 0,214},{ 0,200},{ 12, 1},{ 6, 1},{ 2, 1}, + { 0, 78},{ 2, 1},{ 0,215},{ 0,125},{ 2, 1},{ 0,171}, + { 2, 1},{ 0, 94},{ 0,201},{ 6, 1},{ 2, 1},{ 0, 15}, + { 2, 1},{ 0,156},{ 0,110},{ 2, 1},{ 0,242},{ 0, 47}, + { 32, 1},{ 16, 1},{ 6, 1},{ 4, 1},{ 2, 1},{ 0,216}, + { 0,141},{ 0, 63},{ 6, 1},{ 2, 1},{ 0,243},{ 2, 1}, + { 0,230},{ 0,202},{ 2, 1},{ 0,244},{ 0, 79},{ 8, 1}, + { 4, 1},{ 2, 1},{ 0,187},{ 0,172},{ 2, 1},{ 0,231}, // 420 + + { 0,245},{ 4, 1},{ 2, 1},{ 0,217},{ 0,157},{ 2, 1}, + { 0, 95},{ 0,232},{ 30, 1},{ 12, 1},{ 6, 1},{ 2, 1}, + { 0,111},{ 2, 1},{ 0,246},{ 0,203},{ 4, 1},{ 2, 1}, + { 0,188},{ 0,173},{ 0,218},{ 8, 1},{ 2, 1},{ 0,247}, + { 4, 1},{ 2, 1},{ 0,126},{ 0,127},{ 0,142},{ 6, 1}, + { 4, 1},{ 2, 1},{ 0,158},{ 0,174},{ 0,204},{ 2, 1}, + { 0,248},{ 0,143},{ 18, 1},{ 8, 1},{ 4, 1},{ 2, 1}, + { 0,219},{ 0,189},{ 2, 1},{ 0,234},{ 0,249},{ 4, 1}, + { 2, 1},{ 0,159},{ 0,235},{ 2, 1},{ 0,190},{ 2, 1}, + { 0,205},{ 0,250},{ 14, 1},{ 4, 1},{ 2, 1},{ 0,221}, // 480 + + { 0,236},{ 6, 1},{ 4, 1},{ 2, 1},{ 0,233},{ 0,175}, + { 0,220},{ 2, 1},{ 0,206},{ 0,251},{ 8, 1},{ 4, 1}, + { 2, 1},{ 0,191},{ 0,222},{ 2, 1},{ 0,207},{ 0,238}, + { 4, 1},{ 2, 1},{ 0,223},{ 0,239},{ 2, 1},{ 0,255}, + { 2, 1},{ 0,237},{ 2, 1},{ 0,253},{ 2, 1},{ 0,252}, + { 0,254}}, + +htd15[511][2]={{ 16, 1},{ 6, 1},{ 2, 1},{ 0, 0},{ 2, 1},{ 0, 16}, + { 0, 1},{ 2, 1},{ 0, 17},{ 4, 1},{ 2, 1},{ 0, 32}, + { 0, 2},{ 2, 1},{ 0, 33},{ 0, 18},{ 50, 1},{ 16, 1}, + { 6, 1},{ 2, 1},{ 0, 34},{ 2, 1},{ 0, 48},{ 0, 49}, + { 6, 1},{ 2, 1},{ 0, 19},{ 2, 1},{ 0, 3},{ 0, 64}, + { 2, 1},{ 0, 50},{ 0, 35},{ 14, 1},{ 6, 1},{ 4, 1}, + { 2, 1},{ 0, 4},{ 0, 20},{ 0, 65},{ 4, 1},{ 2, 1}, + { 0, 51},{ 0, 66},{ 2, 1},{ 0, 36},{ 0, 67},{ 10, 1}, + { 6, 1},{ 2, 1},{ 0, 52},{ 2, 1},{ 0, 80},{ 0, 5}, + { 2, 1},{ 0, 81},{ 0, 21},{ 4, 1},{ 2, 1},{ 0, 82}, // 60 + + { 0, 37},{ 4, 1},{ 2, 1},{ 0, 68},{ 0, 83},{ 0, 97}, + { 90, 1},{ 36, 1},{ 18, 1},{ 10, 1},{ 6, 1},{ 2, 1}, + { 0, 53},{ 2, 1},{ 0, 96},{ 0, 6},{ 2, 1},{ 0, 22}, + { 0, 98},{ 4, 1},{ 2, 1},{ 0, 38},{ 0, 84},{ 2, 1}, + { 0, 69},{ 0, 99},{ 10, 1},{ 6, 1},{ 2, 1},{ 0, 54}, + { 2, 1},{ 0,112},{ 0, 7},{ 2, 1},{ 0,113},{ 0, 85}, + { 4, 1},{ 2, 1},{ 0, 23},{ 0,100},{ 2, 1},{ 0,114}, + { 0, 39},{ 24, 1},{ 16, 1},{ 8, 1},{ 4, 1},{ 2, 1}, + { 0, 70},{ 0,115},{ 2, 1},{ 0, 55},{ 0,101},{ 4, 1}, + { 2, 1},{ 0, 86},{ 0,128},{ 2, 1},{ 0, 8},{ 0,116}, // 120 + + { 4, 1},{ 2, 1},{ 0,129},{ 0, 24},{ 2, 1},{ 0,130}, + { 0, 40},{ 16, 1},{ 8, 1},{ 4, 1},{ 2, 1},{ 0, 71}, + { 0,102},{ 2, 1},{ 0,131},{ 0, 56},{ 4, 1},{ 2, 1}, + { 0,117},{ 0, 87},{ 2, 1},{ 0,132},{ 0, 72},{ 6, 1}, + { 4, 1},{ 2, 1},{ 0,144},{ 0, 25},{ 0,145},{ 4, 1}, + { 2, 1},{ 0,146},{ 0,118},{ 2, 1},{ 0,103},{ 0, 41}, + { 92, 1},{ 36, 1},{ 18, 1},{ 10, 1},{ 4, 1},{ 2, 1}, + { 0,133},{ 0, 88},{ 4, 1},{ 2, 1},{ 0, 9},{ 0,119}, + { 0,147},{ 4, 1},{ 2, 1},{ 0, 57},{ 0,148},{ 2, 1}, + { 0, 73},{ 0,134},{ 10, 1},{ 6, 1},{ 2, 1},{ 0,104}, // 180 + + { 2, 1},{ 0,160},{ 0, 10},{ 2, 1},{ 0,161},{ 0, 26}, + { 4, 1},{ 2, 1},{ 0,162},{ 0, 42},{ 2, 1},{ 0,149}, + { 0, 89},{ 26, 1},{ 14, 1},{ 6, 1},{ 2, 1},{ 0,163}, + { 2, 1},{ 0, 58},{ 0,135},{ 4, 1},{ 2, 1},{ 0,120}, + { 0,164},{ 2, 1},{ 0, 74},{ 0,150},{ 6, 1},{ 4, 1}, + { 2, 1},{ 0,105},{ 0,176},{ 0,177},{ 4, 1},{ 2, 1}, + { 0, 27},{ 0,165},{ 0,178},{ 14, 1},{ 8, 1},{ 4, 1}, + { 2, 1},{ 0, 90},{ 0, 43},{ 2, 1},{ 0,136},{ 0,151}, + { 2, 1},{ 0,179},{ 2, 1},{ 0,121},{ 0, 59},{ 8, 1}, + { 4, 1},{ 2, 1},{ 0,106},{ 0,180},{ 2, 1},{ 0, 75}, // 240 + + { 0,193},{ 4, 1},{ 2, 1},{ 0,152},{ 0,137},{ 2, 1}, + { 0, 28},{ 0,181},{ 80, 1},{ 34, 1},{ 16, 1},{ 6, 1}, + { 4, 1},{ 2, 1},{ 0, 91},{ 0, 44},{ 0,194},{ 6, 1}, + { 4, 1},{ 2, 1},{ 0, 11},{ 0,192},{ 0,166},{ 2, 1}, + { 0,167},{ 0,122},{ 10, 1},{ 4, 1},{ 2, 1},{ 0,195}, + { 0, 60},{ 4, 1},{ 2, 1},{ 0, 12},{ 0,153},{ 0,182}, + { 4, 1},{ 2, 1},{ 0,107},{ 0,196},{ 2, 1},{ 0, 76}, + { 0,168},{ 20, 1},{ 10, 1},{ 4, 1},{ 2, 1},{ 0,138}, + { 0,197},{ 4, 1},{ 2, 1},{ 0,208},{ 0, 92},{ 0,209}, + { 4, 1},{ 2, 1},{ 0,183},{ 0,123},{ 2, 1},{ 0, 29}, // 300 + + { 2, 1},{ 0, 13},{ 0, 45},{ 12, 1},{ 4, 1},{ 2, 1}, + { 0,210},{ 0,211},{ 4, 1},{ 2, 1},{ 0, 61},{ 0,198}, + { 2, 1},{ 0,108},{ 0,169},{ 6, 1},{ 4, 1},{ 2, 1}, + { 0,154},{ 0,184},{ 0,212},{ 4, 1},{ 2, 1},{ 0,139}, + { 0, 77},{ 2, 1},{ 0,199},{ 0,124},{ 68, 1},{ 34, 1}, + { 18, 1},{ 10, 1},{ 4, 1},{ 2, 1},{ 0,213},{ 0, 93}, + { 4, 1},{ 2, 1},{ 0,224},{ 0, 14},{ 0,225},{ 4, 1}, + { 2, 1},{ 0, 30},{ 0,226},{ 2, 1},{ 0,170},{ 0, 46}, + { 8, 1},{ 4, 1},{ 2, 1},{ 0,185},{ 0,155},{ 2, 1}, + { 0,227},{ 0,214},{ 4, 1},{ 2, 1},{ 0,109},{ 0, 62}, // 360 + + { 2, 1},{ 0,200},{ 0,140},{ 16, 1},{ 8, 1},{ 4, 1}, + { 2, 1},{ 0,228},{ 0, 78},{ 2, 1},{ 0,215},{ 0,125}, + { 4, 1},{ 2, 1},{ 0,229},{ 0,186},{ 2, 1},{ 0,171}, + { 0, 94},{ 8, 1},{ 4, 1},{ 2, 1},{ 0,201},{ 0,156}, + { 2, 1},{ 0,241},{ 0, 31},{ 6, 1},{ 4, 1},{ 2, 1}, + { 0,240},{ 0,110},{ 0,242},{ 2, 1},{ 0, 47},{ 0,230}, + { 38, 1},{ 18, 1},{ 8, 1},{ 4, 1},{ 2, 1},{ 0,216}, + { 0,243},{ 2, 1},{ 0, 63},{ 0,244},{ 6, 1},{ 2, 1}, + { 0, 79},{ 2, 1},{ 0,141},{ 0,217},{ 2, 1},{ 0,187}, + { 0,202},{ 8, 1},{ 4, 1},{ 2, 1},{ 0,172},{ 0,231}, // 420 + + { 2, 1},{ 0,126},{ 0,245},{ 8, 1},{ 4, 1},{ 2, 1}, + { 0,157},{ 0, 95},{ 2, 1},{ 0,232},{ 0,142},{ 2, 1}, + { 0,246},{ 0,203},{ 34, 1},{ 18, 1},{ 10, 1},{ 6, 1}, + { 4, 1},{ 2, 1},{ 0, 15},{ 0,174},{ 0,111},{ 2, 1}, + { 0,188},{ 0,218},{ 4, 1},{ 2, 1},{ 0,173},{ 0,247}, + { 2, 1},{ 0,127},{ 0,233},{ 8, 1},{ 4, 1},{ 2, 1}, + { 0,158},{ 0,204},{ 2, 1},{ 0,248},{ 0,143},{ 4, 1}, + { 2, 1},{ 0,219},{ 0,189},{ 2, 1},{ 0,234},{ 0,249}, + { 16, 1},{ 8, 1},{ 4, 1},{ 2, 1},{ 0,159},{ 0,220}, + { 2, 1},{ 0,205},{ 0,235},{ 4, 1},{ 2, 1},{ 0,190}, // 480 + + { 0,250},{ 2, 1},{ 0,175},{ 0,221},{ 14, 1},{ 6, 1}, + { 4, 1},{ 2, 1},{ 0,236},{ 0,206},{ 0,251},{ 4, 1}, + { 2, 1},{ 0,191},{ 0,237},{ 2, 1},{ 0,222},{ 0,252}, + { 6, 1},{ 4, 1},{ 2, 1},{ 0,207},{ 0,253},{ 0,238}, + { 4, 1},{ 2, 1},{ 0,223},{ 0,254},{ 2, 1},{ 0,239}, + { 0,255}}, + +htd16[511][2]={{ 2, 1},{ 0, 0},{ 6, 1},{ 2, 1},{ 0, 16},{ 2, 1}, + { 0, 1},{ 0, 17},{ 42, 1},{ 8, 1},{ 4, 1},{ 2, 1}, + { 0, 32},{ 0, 2},{ 2, 1},{ 0, 33},{ 0, 18},{ 10, 1}, + { 6, 1},{ 2, 1},{ 0, 34},{ 2, 1},{ 0, 48},{ 0, 3}, + { 2, 1},{ 0, 49},{ 0, 19},{ 10, 1},{ 4, 1},{ 2, 1}, + { 0, 50},{ 0, 35},{ 4, 1},{ 2, 1},{ 0, 64},{ 0, 4}, + { 0, 65},{ 6, 1},{ 2, 1},{ 0, 20},{ 2, 1},{ 0, 51}, + { 0, 66},{ 4, 1},{ 2, 1},{ 0, 36},{ 0, 80},{ 2, 1}, + { 0, 67},{ 0, 52},{138, 1},{ 40, 1},{ 16, 1},{ 6, 1}, + { 4, 1},{ 2, 1},{ 0, 5},{ 0, 21},{ 0, 81},{ 4, 1}, // 60 + + { 2, 1},{ 0, 82},{ 0, 37},{ 4, 1},{ 2, 1},{ 0, 68}, + { 0, 53},{ 0, 83},{ 10, 1},{ 6, 1},{ 4, 1},{ 2, 1}, + { 0, 96},{ 0, 6},{ 0, 97},{ 2, 1},{ 0, 22},{ 0, 98}, + { 8, 1},{ 4, 1},{ 2, 1},{ 0, 38},{ 0, 84},{ 2, 1}, + { 0, 69},{ 0, 99},{ 4, 1},{ 2, 1},{ 0, 54},{ 0,112}, + { 0,113},{ 40, 1},{ 18, 1},{ 8, 1},{ 2, 1},{ 0, 23}, + { 2, 1},{ 0, 7},{ 2, 1},{ 0, 85},{ 0,100},{ 4, 1}, + { 2, 1},{ 0,114},{ 0, 39},{ 4, 1},{ 2, 1},{ 0, 70}, + { 0,101},{ 0,115},{ 10, 1},{ 6, 1},{ 2, 1},{ 0, 55}, + { 2, 1},{ 0, 86},{ 0, 8},{ 2, 1},{ 0,128},{ 0,129}, // 120 + + { 6, 1},{ 2, 1},{ 0, 24},{ 2, 1},{ 0,116},{ 0, 71}, + { 2, 1},{ 0,130},{ 2, 1},{ 0, 40},{ 0,102},{ 24, 1}, + { 14, 1},{ 8, 1},{ 4, 1},{ 2, 1},{ 0,131},{ 0, 56}, + { 2, 1},{ 0,117},{ 0,132},{ 4, 1},{ 2, 1},{ 0, 72}, + { 0,144},{ 0,145},{ 6, 1},{ 2, 1},{ 0, 25},{ 2, 1}, + { 0, 9},{ 0,118},{ 2, 1},{ 0,146},{ 0, 41},{ 14, 1}, + { 8, 1},{ 4, 1},{ 2, 1},{ 0,133},{ 0, 88},{ 2, 1}, + { 0,147},{ 0, 57},{ 4, 1},{ 2, 1},{ 0,160},{ 0, 10}, + { 0, 26},{ 8, 1},{ 2, 1},{ 0,162},{ 2, 1},{ 0,103}, + { 2, 1},{ 0, 87},{ 0, 73},{ 6, 1},{ 2, 1},{ 0,148}, // 180 + + { 2, 1},{ 0,119},{ 0,134},{ 2, 1},{ 0,161},{ 2, 1}, + { 0,104},{ 0,149},{220, 1},{126, 1},{ 50, 1},{ 26, 1}, + { 12, 1},{ 6, 1},{ 2, 1},{ 0, 42},{ 2, 1},{ 0, 89}, + { 0, 58},{ 2, 1},{ 0,163},{ 2, 1},{ 0,135},{ 0,120}, + { 8, 1},{ 4, 1},{ 2, 1},{ 0,164},{ 0, 74},{ 2, 1}, + { 0,150},{ 0,105},{ 4, 1},{ 2, 1},{ 0,176},{ 0, 11}, + { 0,177},{ 10, 1},{ 4, 1},{ 2, 1},{ 0, 27},{ 0,178}, + { 2, 1},{ 0, 43},{ 2, 1},{ 0,165},{ 0, 90},{ 6, 1}, + { 2, 1},{ 0,179},{ 2, 1},{ 0,166},{ 0,106},{ 4, 1}, + { 2, 1},{ 0,180},{ 0, 75},{ 2, 1},{ 0, 12},{ 0,193}, // 240 + + { 30, 1},{ 14, 1},{ 6, 1},{ 4, 1},{ 2, 1},{ 0,181}, + { 0,194},{ 0, 44},{ 4, 1},{ 2, 1},{ 0,167},{ 0,195}, + { 2, 1},{ 0,107},{ 0,196},{ 8, 1},{ 2, 1},{ 0, 29}, + { 4, 1},{ 2, 1},{ 0,136},{ 0,151},{ 0, 59},{ 4, 1}, + { 2, 1},{ 0,209},{ 0,210},{ 2, 1},{ 0, 45},{ 0,211}, + { 18, 1},{ 6, 1},{ 4, 1},{ 2, 1},{ 0, 30},{ 0, 46}, + { 0,226},{ 6, 1},{ 4, 1},{ 2, 1},{ 0,121},{ 0,152}, + { 0,192},{ 2, 1},{ 0, 28},{ 2, 1},{ 0,137},{ 0, 91}, + { 14, 1},{ 6, 1},{ 2, 1},{ 0, 60},{ 2, 1},{ 0,122}, + { 0,182},{ 4, 1},{ 2, 1},{ 0, 76},{ 0,153},{ 2, 1}, // 300 + + { 0,168},{ 0,138},{ 6, 1},{ 2, 1},{ 0, 13},{ 2, 1}, + { 0,197},{ 0, 92},{ 4, 1},{ 2, 1},{ 0, 61},{ 0,198}, + { 2, 1},{ 0,108},{ 0,154},{ 88, 1},{ 86, 1},{ 36, 1}, + { 16, 1},{ 8, 1},{ 4, 1},{ 2, 1},{ 0,139},{ 0, 77}, + { 2, 1},{ 0,199},{ 0,124},{ 4, 1},{ 2, 1},{ 0,213}, + { 0, 93},{ 2, 1},{ 0,224},{ 0, 14},{ 8, 1},{ 2, 1}, + { 0,227},{ 4, 1},{ 2, 1},{ 0,208},{ 0,183},{ 0,123}, + { 6, 1},{ 4, 1},{ 2, 1},{ 0,169},{ 0,184},{ 0,212}, + { 2, 1},{ 0,225},{ 2, 1},{ 0,170},{ 0,185},{ 24, 1}, + { 10, 1},{ 6, 1},{ 4, 1},{ 2, 1},{ 0,155},{ 0,214}, // 360 + + { 0,109},{ 2, 1},{ 0, 62},{ 0,200},{ 6, 1},{ 4, 1}, + { 2, 1},{ 0,140},{ 0,228},{ 0, 78},{ 4, 1},{ 2, 1}, + { 0,215},{ 0,229},{ 2, 1},{ 0,186},{ 0,171},{ 12, 1}, + { 4, 1},{ 2, 1},{ 0,156},{ 0,230},{ 4, 1},{ 2, 1}, + { 0,110},{ 0,216},{ 2, 1},{ 0,141},{ 0,187},{ 8, 1}, + { 4, 1},{ 2, 1},{ 0,231},{ 0,157},{ 2, 1},{ 0,232}, + { 0,142},{ 4, 1},{ 2, 1},{ 0,203},{ 0,188},{ 0,158}, + { 0,241},{ 2, 1},{ 0, 31},{ 2, 1},{ 0, 15},{ 0, 47}, + { 66, 1},{ 56, 1},{ 2, 1},{ 0,242},{ 52, 1},{ 50, 1}, + { 20, 1},{ 8, 1},{ 2, 1},{ 0,189},{ 2, 1},{ 0, 94}, // 420 + + { 2, 1},{ 0,125},{ 0,201},{ 6, 1},{ 2, 1},{ 0,202}, + { 2, 1},{ 0,172},{ 0,126},{ 4, 1},{ 2, 1},{ 0,218}, + { 0,173},{ 0,204},{ 10, 1},{ 6, 1},{ 2, 1},{ 0,174}, + { 2, 1},{ 0,219},{ 0,220},{ 2, 1},{ 0,205},{ 0,190}, + { 6, 1},{ 4, 1},{ 2, 1},{ 0,235},{ 0,237},{ 0,238}, + { 6, 1},{ 4, 1},{ 2, 1},{ 0,217},{ 0,234},{ 0,233}, + { 2, 1},{ 0,222},{ 4, 1},{ 2, 1},{ 0,221},{ 0,236}, + { 0,206},{ 0, 63},{ 0,240},{ 4, 1},{ 2, 1},{ 0,243}, + { 0,244},{ 2, 1},{ 0, 79},{ 2, 1},{ 0,245},{ 0, 95}, + { 10, 1},{ 2, 1},{ 0,255},{ 4, 1},{ 2, 1},{ 0,246}, // 480 + + { 0,111},{ 2, 1},{ 0,247},{ 0,127},{ 12, 1},{ 6, 1}, + { 2, 1},{ 0,143},{ 2, 1},{ 0,248},{ 0,249},{ 4, 1}, + { 2, 1},{ 0,159},{ 0,250},{ 0,175},{ 8, 1},{ 4, 1}, + { 2, 1},{ 0,251},{ 0,191},{ 2, 1},{ 0,252},{ 0,207}, + { 4, 1},{ 2, 1},{ 0,253},{ 0,223},{ 2, 1},{ 0,254}, + { 0,239}}, + +htd24[512][2]={{ 60, 1},{ 8, 1},{ 4, 1},{ 2, 1},{ 0, 0},{ 0, 16}, + { 2, 1},{ 0, 1},{ 0, 17},{ 14, 1},{ 6, 1},{ 4, 1}, + { 2, 1},{ 0, 32},{ 0, 2},{ 0, 33},{ 2, 1},{ 0, 18}, + { 2, 1},{ 0, 34},{ 2, 1},{ 0, 48},{ 0, 3},{ 14, 1}, + { 4, 1},{ 2, 1},{ 0, 49},{ 0, 19},{ 4, 1},{ 2, 1}, + { 0, 50},{ 0, 35},{ 4, 1},{ 2, 1},{ 0, 64},{ 0, 4}, + { 0, 65},{ 8, 1},{ 4, 1},{ 2, 1},{ 0, 20},{ 0, 51}, + { 2, 1},{ 0, 66},{ 0, 36},{ 6, 1},{ 4, 1},{ 2, 1}, + { 0, 67},{ 0, 52},{ 0, 81},{ 6, 1},{ 4, 1},{ 2, 1}, + { 0, 80},{ 0, 5},{ 0, 21},{ 2, 1},{ 0, 82},{ 0, 37}, // 60 + + {250+85, 1},{ 98, 1},{ 34, 1},{ 18, 1},{ 10, 1},{ 4, 1}, + { 2, 1},{ 0, 68},{ 0, 83},{ 2, 1},{ 0, 53},{ 2, 1}, + { 0, 96},{ 0, 6},{ 4, 1},{ 2, 1},{ 0, 97},{ 0, 22}, + { 2, 1},{ 0, 98},{ 0, 38},{ 8, 1},{ 4, 1},{ 2, 1}, + { 0, 84},{ 0, 69},{ 2, 1},{ 0, 99},{ 0, 54},{ 4, 1}, + { 2, 1},{ 0,113},{ 0, 85},{ 2, 1},{ 0,100},{ 0, 70}, + { 32, 1},{ 14, 1},{ 6, 1},{ 2, 1},{ 0,114},{ 2, 1}, + { 0, 39},{ 0, 55},{ 2, 1},{ 0,115},{ 4, 1},{ 2, 1}, + { 0,112},{ 0, 7},{ 0, 23},{ 10, 1},{ 4, 1},{ 2, 1}, + { 0,101},{ 0, 86},{ 4, 1},{ 2, 1},{ 0,128},{ 0, 8}, // 120 + + { 0,129},{ 4, 1},{ 2, 1},{ 0,116},{ 0, 71},{ 2, 1}, + { 0, 24},{ 0,130},{ 16, 1},{ 8, 1},{ 4, 1},{ 2, 1}, + { 0, 40},{ 0,102},{ 2, 1},{ 0,131},{ 0, 56},{ 4, 1}, + { 2, 1},{ 0,117},{ 0, 87},{ 2, 1},{ 0,132},{ 0, 72}, + { 8, 1},{ 4, 1},{ 2, 1},{ 0,145},{ 0, 25},{ 2, 1}, + { 0,146},{ 0,118},{ 4, 1},{ 2, 1},{ 0,103},{ 0, 41}, + { 2, 1},{ 0,133},{ 0, 88},{ 92, 1},{ 34, 1},{ 16, 1}, + { 8, 1},{ 4, 1},{ 2, 1},{ 0,147},{ 0, 57},{ 2, 1}, + { 0,148},{ 0, 73},{ 4, 1},{ 2, 1},{ 0,119},{ 0,134}, + { 2, 1},{ 0,104},{ 0,161},{ 8, 1},{ 4, 1},{ 2, 1}, // 180 + + { 0,162},{ 0, 42},{ 2, 1},{ 0,149},{ 0, 89},{ 4, 1}, + { 2, 1},{ 0,163},{ 0, 58},{ 2, 1},{ 0,135},{ 2, 1}, + { 0,120},{ 0, 74},{ 22, 1},{ 12, 1},{ 4, 1},{ 2, 1}, + { 0,164},{ 0,150},{ 4, 1},{ 2, 1},{ 0,105},{ 0,177}, + { 2, 1},{ 0, 27},{ 0,165},{ 6, 1},{ 2, 1},{ 0,178}, + { 2, 1},{ 0, 90},{ 0, 43},{ 2, 1},{ 0,136},{ 0,179}, + { 16, 1},{ 10, 1},{ 6, 1},{ 2, 1},{ 0,144},{ 2, 1}, + { 0, 9},{ 0,160},{ 2, 1},{ 0,151},{ 0,121},{ 4, 1}, + { 2, 1},{ 0,166},{ 0,106},{ 0,180},{ 12, 1},{ 6, 1}, + { 2, 1},{ 0, 26},{ 2, 1},{ 0, 10},{ 0,176},{ 2, 1}, // 240 + + { 0, 59},{ 2, 1},{ 0, 11},{ 0,192},{ 4, 1},{ 2, 1}, + { 0, 75},{ 0,193},{ 2, 1},{ 0,152},{ 0,137},{ 67, 1}, + { 34, 1},{ 16, 1},{ 8, 1},{ 4, 1},{ 2, 1},{ 0, 28}, + { 0,181},{ 2, 1},{ 0, 91},{ 0,194},{ 4, 1},{ 2, 1}, + { 0, 44},{ 0,167},{ 2, 1},{ 0,122},{ 0,195},{ 10, 1}, + { 6, 1},{ 2, 1},{ 0, 60},{ 2, 1},{ 0, 12},{ 0,208}, + { 2, 1},{ 0,182},{ 0,107},{ 4, 1},{ 2, 1},{ 0,196}, + { 0, 76},{ 2, 1},{ 0,153},{ 0,168},{ 16, 1},{ 8, 1}, + { 4, 1},{ 2, 1},{ 0,138},{ 0,197},{ 2, 1},{ 0, 92}, + { 0,209},{ 4, 1},{ 2, 1},{ 0,183},{ 0,123},{ 2, 1}, // 300 + + { 0, 29},{ 0,210},{ 9, 1},{ 4, 1},{ 2, 1},{ 0, 45}, + { 0,211},{ 2, 1},{ 0, 61},{ 0,198},{ 85,250},{ 4, 1}, // 306 - + { 2, 1},{ 0,108},{ 0,169},{ 2, 1},{ 0,154},{ 0,212}, + { 32, 1},{ 16, 1},{ 8, 1},{ 4, 1},{ 2, 1},{ 0,184}, + { 0,139},{ 2, 1},{ 0, 77},{ 0,199},{ 4, 1},{ 2, 1}, + { 0,124},{ 0,213},{ 2, 1},{ 0, 93},{ 0,225},{ 8, 1}, + { 4, 1},{ 2, 1},{ 0, 30},{ 0,226},{ 2, 1},{ 0,170}, + { 0,185},{ 4, 1},{ 2, 1},{ 0,155},{ 0,227},{ 2, 1}, + { 0,214},{ 0,109},{ 20, 1},{ 10, 1},{ 6, 1},{ 2, 1}, + { 0, 62},{ 2, 1},{ 0, 46},{ 0, 78},{ 2, 1},{ 0,200}, // 360 + + { 0,140},{ 4, 1},{ 2, 1},{ 0,228},{ 0,215},{ 4, 1}, + { 2, 1},{ 0,125},{ 0,171},{ 0,229},{ 10, 1},{ 4, 1}, + { 2, 1},{ 0,186},{ 0, 94},{ 2, 1},{ 0,201},{ 2, 1}, + { 0,156},{ 0,110},{ 8, 1},{ 2, 1},{ 0,230},{ 2, 1}, + { 0, 13},{ 2, 1},{ 0,224},{ 0, 14},{ 4, 1},{ 2, 1}, + { 0,216},{ 0,141},{ 2, 1},{ 0,187},{ 0,202},{ 74, 1}, + { 2, 1},{ 0,255},{ 64, 1},{ 58, 1},{ 32, 1},{ 16, 1}, + { 8, 1},{ 4, 1},{ 2, 1},{ 0,172},{ 0,231},{ 2, 1}, + { 0,126},{ 0,217},{ 4, 1},{ 2, 1},{ 0,157},{ 0,232}, + { 2, 1},{ 0,142},{ 0,203},{ 8, 1},{ 4, 1},{ 2, 1}, // 420 + + { 0,188},{ 0,218},{ 2, 1},{ 0,173},{ 0,233},{ 4, 1}, + { 2, 1},{ 0,158},{ 0,204},{ 2, 1},{ 0,219},{ 0,189}, + { 16, 1},{ 8, 1},{ 4, 1},{ 2, 1},{ 0,234},{ 0,174}, + { 2, 1},{ 0,220},{ 0,205},{ 4, 1},{ 2, 1},{ 0,235}, + { 0,190},{ 2, 1},{ 0,221},{ 0,236},{ 8, 1},{ 4, 1}, + { 2, 1},{ 0,206},{ 0,237},{ 2, 1},{ 0,222},{ 0,238}, + { 0, 15},{ 4, 1},{ 2, 1},{ 0,240},{ 0, 31},{ 0,241}, + { 4, 1},{ 2, 1},{ 0,242},{ 0, 47},{ 2, 1},{ 0,243}, + { 0, 63},{ 18, 1},{ 8, 1},{ 4, 1},{ 2, 1},{ 0,244}, + { 0, 79},{ 2, 1},{ 0,245},{ 0, 95},{ 4, 1},{ 2, 1}, // 480 + + { 0,246},{ 0,111},{ 2, 1},{ 0,247},{ 2, 1},{ 0,127}, + { 0,143},{ 10, 1},{ 4, 1},{ 2, 1},{ 0,248},{ 0,249}, + { 4, 1},{ 2, 1},{ 0,159},{ 0,175},{ 0,250},{ 8, 1}, + { 4, 1},{ 2, 1},{ 0,251},{ 0,191},{ 2, 1},{ 0,252}, + { 0,207},{ 4, 1},{ 2, 1},{ 0,253},{ 0,223},{ 2, 1}, + { 0,254},{ 0,239}}, + +htd32[ 31][2]={{ 2, 1},{ 0, 0},{ 8, 1},{ 4, 1},{ 2, 1},{ 0, 8}, + { 0, 4},{ 2, 1},{ 0, 1},{ 0, 2},{ 8, 1},{ 4, 1}, + { 2, 1},{ 0, 12},{ 0, 10},{ 2, 1},{ 0, 3},{ 0, 6}, + { 6, 1},{ 2, 1},{ 0, 9},{ 2, 1},{ 0, 5},{ 0, 7}, + { 4, 1},{ 2, 1},{ 0, 14},{ 0, 13},{ 2, 1},{ 0, 15}, + { 0, 11}}, + +htd33[ 31][2]={{ 16, 1},{ 8, 1},{ 4, 1},{ 2, 1},{ 0, 0},{ 0, 1}, + { 2, 1},{ 0, 2},{ 0, 3},{ 4, 1},{ 2, 1},{ 0, 4}, + { 0, 5},{ 2, 1},{ 0, 6},{ 0, 7},{ 8, 1},{ 4, 1}, + { 2, 1},{ 0, 8},{ 0, 9},{ 2, 1},{ 0, 10},{ 0, 11}, + { 4, 1},{ 2, 1},{ 0, 12},{ 0, 13},{ 2, 1},{ 0, 14}, + { 0, 15}}; + +const ATTR_ALIGN(64) HUFFMANCODETABLE Mpegtoraw::ht[HTN]= +{ + { 0, 0-1, 0-1, 0, 0, htd33}, + { 1, 2-1, 2-1, 0, 7,htd01}, + { 2, 3-1, 3-1, 0, 17,htd02}, + { 3, 3-1, 3-1, 0, 17,htd03}, + { 4, 0-1, 0-1, 0, 0, htd33}, + { 5, 4-1, 4-1, 0, 31,htd05}, + { 6, 4-1, 4-1, 0, 31,htd06}, + { 7, 6-1, 6-1, 0, 71,htd07}, + { 8, 6-1, 6-1, 0, 71,htd08}, + { 9, 6-1, 6-1, 0, 71,htd09}, + {10, 8-1, 8-1, 0,127,htd10}, + {11, 8-1, 8-1, 0,127,htd11}, + {12, 8-1, 8-1, 0,127,htd12}, + {13,16-1,16-1, 0,511,htd13}, + {14, 0-1, 0-1, 0, 0, htd33}, + {15,16-1,16-1, 0,511,htd15}, + {16,16-1,16-1, 1,511,htd16}, + {17,16-1,16-1, 2,511,htd16}, + {18,16-1,16-1, 3,511,htd16}, + {19,16-1,16-1, 4,511,htd16}, + {20,16-1,16-1, 6,511,htd16}, + {21,16-1,16-1, 8,511,htd16}, + {22,16-1,16-1,10,511,htd16}, + {23,16-1,16-1,13,511,htd16}, + {24,16-1,16-1, 4,512,htd24}, + {25,16-1,16-1, 5,512,htd24}, + {26,16-1,16-1, 6,512,htd24}, + {27,16-1,16-1, 7,512,htd24}, + {28,16-1,16-1, 8,512,htd24}, + {29,16-1,16-1, 9,512,htd24}, + {30,16-1,16-1,11,512,htd24}, + {31,16-1,16-1,13,512,htd24}, + {32, 1-1,16-1, 0, 31,htd32}, + {33, 1-1,16-1, 0, 31,htd33} +}; diff --git a/mpeglib/lib/splay/mpeg2tables.h b/mpeglib/lib/splay/mpeg2tables.h new file mode 100644 index 00000000..1430a123 --- /dev/null +++ b/mpeglib/lib/splay/mpeg2tables.h @@ -0,0 +1,432 @@ + +#ifndef __MPEG2TABLES_H +#define __MPEG2TABLES_H + + +#define MAXTABLE 3 + + +// Tables for layer 2. + +// bitalloclengthtable :0,1 supported 2. 2 ot tested & disabled +// this table merges the subbands to the longer one. +// 8 < 12 , 27 < 30 but the "length" is the same + +static const int bitalloclengthtable[MAXTABLE][MAXSUBBAND]= +{ {4,4,3,3,3,3,3,3,3,3,3,3,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3, 3,3,3,3,3,3,3,2,2,2,2,2,2,2,0,0}, + {4,4,4,4,3,3,3,3,3,3,3,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0} }; + + +/* +Orignal is: +{ {4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3, 3,3,3,3,3,3,3,2,2,2,2,0,0,0,0,0}, + {4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3, 3,3,3,3,3,3,3,2,2,2,2,2,2,2,0,0}, + {4,4,3,3,3,3,3,3,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {4,4,3,3,3,3,3,3,3,3,3,3,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {4,4,4,4,3,3,3,3,3,3,3,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0} }; + +*/ + + + + + +static const REAL group5bits[27*3]= +{ + -2.0/3.0, -2.0/3.0, -2.0/3.0, + 0.0, -2.0/3.0, -2.0/3.0, + 2.0/3.0, -2.0/3.0, -2.0/3.0, + -2.0/3.0, 0.0, -2.0/3.0, + 0.0, 0.0, -2.0/3.0, + 2.0/3.0, 0.0, -2.0/3.0, + -2.0/3.0, 2.0/3.0, -2.0/3.0, + 0.0, 2.0/3.0, -2.0/3.0, + 2.0/3.0, 2.0/3.0, -2.0/3.0, + -2.0/3.0, -2.0/3.0, 0.0, + 0.0, -2.0/3.0, 0.0, + 2.0/3.0, -2.0/3.0, 0.0, + -2.0/3.0, 0.0, 0.0, + 0.0, 0.0, 0.0, + 2.0/3.0, 0.0, 0.0, + -2.0/3.0, 2.0/3.0, 0.0, + 0.0, 2.0/3.0, 0.0, + 2.0/3.0, 2.0/3.0, 0.0, + -2.0/3.0, -2.0/3.0, 2.0/3.0, + 0.0, -2.0/3.0, 2.0/3.0, + 2.0/3.0, -2.0/3.0, 2.0/3.0, + -2.0/3.0, 0.0, 2.0/3.0, + 0.0, 0.0, 2.0/3.0, + 2.0/3.0, 0.0, 2.0/3.0, + -2.0/3.0, 2.0/3.0, 2.0/3.0, + 0.0, 2.0/3.0, 2.0/3.0, + 2.0/3.0, 2.0/3.0, 2.0/3.0 +}; + +static const REAL group7bits[125*3]= +{ + -0.8,-0.8,-0.8, -0.4,-0.8,-0.8, 0.0,-0.8,-0.8, 0.4,-0.8,-0.8, 0.8,-0.8,-0.8, + -0.8,-0.4,-0.8, -0.4,-0.4,-0.8, 0.0,-0.4,-0.8, 0.4,-0.4,-0.8, 0.8,-0.4,-0.8, + -0.8, 0.0,-0.8, -0.4, 0.0,-0.8, 0.0, 0.0,-0.8, 0.4, 0.0,-0.8, 0.8, 0.0,-0.8, + -0.8, 0.4,-0.8, -0.4, 0.4,-0.8, 0.0, 0.4,-0.8, 0.4, 0.4,-0.8, 0.8, 0.4,-0.8, + -0.8, 0.8,-0.8, -0.4, 0.8,-0.8, 0.0, 0.8,-0.8, 0.4, 0.8,-0.8, 0.8, 0.8,-0.8, + -0.8,-0.8,-0.4, -0.4,-0.8,-0.4, 0.0,-0.8,-0.4, 0.4,-0.8,-0.4, 0.8,-0.8,-0.4, + -0.8,-0.4,-0.4, -0.4,-0.4,-0.4, 0.0,-0.4,-0.4, 0.4,-0.4,-0.4, 0.8,-0.4,-0.4, + -0.8, 0.0,-0.4, -0.4, 0.0,-0.4, 0.0, 0.0,-0.4, 0.4, 0.0,-0.4, 0.8, 0.0,-0.4, + -0.8, 0.4,-0.4, -0.4, 0.4,-0.4, 0.0, 0.4,-0.4, 0.4, 0.4,-0.4, 0.8, 0.4,-0.4, + -0.8, 0.8,-0.4, -0.4, 0.8,-0.4, 0.0, 0.8,-0.4, 0.4, 0.8,-0.4, 0.8, 0.8,-0.4, + -0.8,-0.8, 0.0, -0.4,-0.8, 0.0, 0.0,-0.8, 0.0, 0.4,-0.8, 0.0, 0.8,-0.8, 0.0, + -0.8,-0.4, 0.0, -0.4,-0.4, 0.0, 0.0,-0.4, 0.0, 0.4,-0.4, 0.0, 0.8,-0.4, 0.0, + -0.8, 0.0, 0.0, -0.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.4, 0.0, 0.0, 0.8, 0.0, 0.0, + -0.8, 0.4, 0.0, -0.4, 0.4, 0.0, 0.0, 0.4, 0.0, 0.4, 0.4, 0.0, 0.8, 0.4, 0.0, + -0.8, 0.8, 0.0, -0.4, 0.8, 0.0, 0.0, 0.8, 0.0, 0.4, 0.8, 0.0, 0.8, 0.8, 0.0, + -0.8,-0.8, 0.4, -0.4,-0.8, 0.4, 0.0,-0.8, 0.4, 0.4,-0.8, 0.4, 0.8,-0.8, 0.4, + -0.8,-0.4, 0.4, -0.4,-0.4, 0.4, 0.0,-0.4, 0.4, 0.4,-0.4, 0.4, 0.8,-0.4, 0.4, + -0.8, 0.0, 0.4, -0.4, 0.0, 0.4, 0.0, 0.0, 0.4, 0.4, 0.0, 0.4, 0.8, 0.0, 0.4, + -0.8, 0.4, 0.4, -0.4, 0.4, 0.4, 0.0, 0.4, 0.4, 0.4, 0.4, 0.4, 0.8, 0.4, 0.4, + -0.8, 0.8, 0.4, -0.4, 0.8, 0.4, 0.0, 0.8, 0.4, 0.4, 0.8, 0.4, 0.8, 0.8, 0.4, + -0.8,-0.8, 0.8, -0.4,-0.8, 0.8, 0.0,-0.8, 0.8, 0.4,-0.8, 0.8, 0.8,-0.8, 0.8, + -0.8,-0.4, 0.8, -0.4,-0.4, 0.8, 0.0,-0.4, 0.8, 0.4,-0.4, 0.8, 0.8,-0.4, 0.8, + -0.8, 0.0, 0.8, -0.4, 0.0, 0.8, 0.0, 0.0, 0.8, 0.4, 0.0, 0.8, 0.8, 0.0, 0.8, + -0.8, 0.4, 0.8, -0.4, 0.4, 0.8, 0.0, 0.4, 0.8, 0.4, 0.4, 0.8, 0.8, 0.4, 0.8, + -0.8, 0.8, 0.8, -0.4, 0.8, 0.8, 0.0, 0.8, 0.8, 0.4, 0.8, 0.8, 0.8, 0.8, 0.8 +}; + +static const REAL group10bits[729*3]= +{ + -8.0/9.0,-8.0/9.0,-8.0/9.0, -6.0/9.0,-8.0/9.0,-8.0/9.0, -4.0/9.0,-8.0/9.0,-8.0/9.0, + -2.0/9.0,-8.0/9.0,-8.0/9.0, 0.0,-8.0/9.0,-8.0/9.0, 2.0/9.0,-8.0/9.0,-8.0/9.0, + 4.0/9.0,-8.0/9.0,-8.0/9.0, 6.0/9.0,-8.0/9.0,-8.0/9.0, 8.0/9.0,-8.0/9.0,-8.0/9.0, + -8.0/9.0,-6.0/9.0,-8.0/9.0, -6.0/9.0,-6.0/9.0,-8.0/9.0, -4.0/9.0,-6.0/9.0,-8.0/9.0, + -2.0/9.0,-6.0/9.0,-8.0/9.0, 0.0,-6.0/9.0,-8.0/9.0, 2.0/9.0,-6.0/9.0,-8.0/9.0, + 4.0/9.0,-6.0/9.0,-8.0/9.0, 6.0/9.0,-6.0/9.0,-8.0/9.0, 8.0/9.0,-6.0/9.0,-8.0/9.0, + -8.0/9.0,-4.0/9.0,-8.0/9.0, -6.0/9.0,-4.0/9.0,-8.0/9.0, -4.0/9.0,-4.0/9.0,-8.0/9.0, + -2.0/9.0,-4.0/9.0,-8.0/9.0, 0.0,-4.0/9.0,-8.0/9.0, 2.0/9.0,-4.0/9.0,-8.0/9.0, + 4.0/9.0,-4.0/9.0,-8.0/9.0, 6.0/9.0,-4.0/9.0,-8.0/9.0, 8.0/9.0,-4.0/9.0,-8.0/9.0, + -8.0/9.0,-2.0/9.0,-8.0/9.0, -6.0/9.0,-2.0/9.0,-8.0/9.0, -4.0/9.0,-2.0/9.0,-8.0/9.0, + -2.0/9.0,-2.0/9.0,-8.0/9.0, 0.0,-2.0/9.0,-8.0/9.0, 2.0/9.0,-2.0/9.0,-8.0/9.0, + 4.0/9.0,-2.0/9.0,-8.0/9.0, 6.0/9.0,-2.0/9.0,-8.0/9.0, 8.0/9.0,-2.0/9.0,-8.0/9.0, + -8.0/9.0, 0.0,-8.0/9.0, -6.0/9.0, 0.0,-8.0/9.0, -4.0/9.0, 0.0,-8.0/9.0, + -2.0/9.0, 0.0,-8.0/9.0, 0.0, 0.0,-8.0/9.0, 2.0/9.0, 0.0,-8.0/9.0, + 4.0/9.0, 0.0,-8.0/9.0, 6.0/9.0, 0.0,-8.0/9.0, 8.0/9.0, 0.0,-8.0/9.0, + -8.0/9.0, 2.0/9.0,-8.0/9.0, -6.0/9.0, 2.0/9.0,-8.0/9.0, -4.0/9.0, 2.0/9.0,-8.0/9.0, + -2.0/9.0, 2.0/9.0,-8.0/9.0, 0.0, 2.0/9.0,-8.0/9.0, 2.0/9.0, 2.0/9.0,-8.0/9.0, + 4.0/9.0, 2.0/9.0,-8.0/9.0, 6.0/9.0, 2.0/9.0,-8.0/9.0, 8.0/9.0, 2.0/9.0,-8.0/9.0, + -8.0/9.0, 4.0/9.0,-8.0/9.0, -6.0/9.0, 4.0/9.0,-8.0/9.0, -4.0/9.0, 4.0/9.0,-8.0/9.0, + -2.0/9.0, 4.0/9.0,-8.0/9.0, 0.0, 4.0/9.0,-8.0/9.0, 2.0/9.0, 4.0/9.0,-8.0/9.0, + 4.0/9.0, 4.0/9.0,-8.0/9.0, 6.0/9.0, 4.0/9.0,-8.0/9.0, 8.0/9.0, 4.0/9.0,-8.0/9.0, + -8.0/9.0, 6.0/9.0,-8.0/9.0, -6.0/9.0, 6.0/9.0,-8.0/9.0, -4.0/9.0, 6.0/9.0,-8.0/9.0, + -2.0/9.0, 6.0/9.0,-8.0/9.0, 0.0, 6.0/9.0,-8.0/9.0, 2.0/9.0, 6.0/9.0,-8.0/9.0, + 4.0/9.0, 6.0/9.0,-8.0/9.0, 6.0/9.0, 6.0/9.0,-8.0/9.0, 8.0/9.0, 6.0/9.0,-8.0/9.0, + -8.0/9.0, 8.0/9.0,-8.0/9.0, -6.0/9.0, 8.0/9.0,-8.0/9.0, -4.0/9.0, 8.0/9.0,-8.0/9.0, + -2.0/9.0, 8.0/9.0,-8.0/9.0, 0.0, 8.0/9.0,-8.0/9.0, 2.0/9.0, 8.0/9.0,-8.0/9.0, + 4.0/9.0, 8.0/9.0,-8.0/9.0, 6.0/9.0, 8.0/9.0,-8.0/9.0, 8.0/9.0, 8.0/9.0,-8.0/9.0, + -8.0/9.0,-8.0/9.0,-6.0/9.0, -6.0/9.0,-8.0/9.0,-6.0/9.0, -4.0/9.0,-8.0/9.0,-6.0/9.0, + -2.0/9.0,-8.0/9.0,-6.0/9.0, 0.0,-8.0/9.0,-6.0/9.0, 2.0/9.0,-8.0/9.0,-6.0/9.0, + 4.0/9.0,-8.0/9.0,-6.0/9.0, 6.0/9.0,-8.0/9.0,-6.0/9.0, 8.0/9.0,-8.0/9.0,-6.0/9.0, + -8.0/9.0,-6.0/9.0,-6.0/9.0, -6.0/9.0,-6.0/9.0,-6.0/9.0, -4.0/9.0,-6.0/9.0,-6.0/9.0, + -2.0/9.0,-6.0/9.0,-6.0/9.0, 0.0,-6.0/9.0,-6.0/9.0, 2.0/9.0,-6.0/9.0,-6.0/9.0, + 4.0/9.0,-6.0/9.0,-6.0/9.0, 6.0/9.0,-6.0/9.0,-6.0/9.0, 8.0/9.0,-6.0/9.0,-6.0/9.0, + -8.0/9.0,-4.0/9.0,-6.0/9.0, -6.0/9.0,-4.0/9.0,-6.0/9.0, -4.0/9.0,-4.0/9.0,-6.0/9.0, + -2.0/9.0,-4.0/9.0,-6.0/9.0, 0.0,-4.0/9.0,-6.0/9.0, 2.0/9.0,-4.0/9.0,-6.0/9.0, + 4.0/9.0,-4.0/9.0,-6.0/9.0, 6.0/9.0,-4.0/9.0,-6.0/9.0, 8.0/9.0,-4.0/9.0,-6.0/9.0, + -8.0/9.0,-2.0/9.0,-6.0/9.0, -6.0/9.0,-2.0/9.0,-6.0/9.0, -4.0/9.0,-2.0/9.0,-6.0/9.0, + -2.0/9.0,-2.0/9.0,-6.0/9.0, 0.0,-2.0/9.0,-6.0/9.0, 2.0/9.0,-2.0/9.0,-6.0/9.0, + 4.0/9.0,-2.0/9.0,-6.0/9.0, 6.0/9.0,-2.0/9.0,-6.0/9.0, 8.0/9.0,-2.0/9.0,-6.0/9.0, + -8.0/9.0, 0.0,-6.0/9.0, -6.0/9.0, 0.0,-6.0/9.0, -4.0/9.0, 0.0,-6.0/9.0, + -2.0/9.0, 0.0,-6.0/9.0, 0.0, 0.0,-6.0/9.0, 2.0/9.0, 0.0,-6.0/9.0, + 4.0/9.0, 0.0,-6.0/9.0, 6.0/9.0, 0.0,-6.0/9.0, 8.0/9.0, 0.0,-6.0/9.0, + -8.0/9.0, 2.0/9.0,-6.0/9.0, -6.0/9.0, 2.0/9.0,-6.0/9.0, -4.0/9.0, 2.0/9.0,-6.0/9.0, + -2.0/9.0, 2.0/9.0,-6.0/9.0, 0.0, 2.0/9.0,-6.0/9.0, 2.0/9.0, 2.0/9.0,-6.0/9.0, + 4.0/9.0, 2.0/9.0,-6.0/9.0, 6.0/9.0, 2.0/9.0,-6.0/9.0, 8.0/9.0, 2.0/9.0,-6.0/9.0, + -8.0/9.0, 4.0/9.0,-6.0/9.0, -6.0/9.0, 4.0/9.0,-6.0/9.0, -4.0/9.0, 4.0/9.0,-6.0/9.0, + -2.0/9.0, 4.0/9.0,-6.0/9.0, 0.0, 4.0/9.0,-6.0/9.0, 2.0/9.0, 4.0/9.0,-6.0/9.0, + 4.0/9.0, 4.0/9.0,-6.0/9.0, 6.0/9.0, 4.0/9.0,-6.0/9.0, 8.0/9.0, 4.0/9.0,-6.0/9.0, + -8.0/9.0, 6.0/9.0,-6.0/9.0, -6.0/9.0, 6.0/9.0,-6.0/9.0, -4.0/9.0, 6.0/9.0,-6.0/9.0, + -2.0/9.0, 6.0/9.0,-6.0/9.0, 0.0, 6.0/9.0,-6.0/9.0, 2.0/9.0, 6.0/9.0,-6.0/9.0, + 4.0/9.0, 6.0/9.0,-6.0/9.0, 6.0/9.0, 6.0/9.0,-6.0/9.0, 8.0/9.0, 6.0/9.0,-6.0/9.0, + -8.0/9.0, 8.0/9.0,-6.0/9.0, -6.0/9.0, 8.0/9.0,-6.0/9.0, -4.0/9.0, 8.0/9.0,-6.0/9.0, + -2.0/9.0, 8.0/9.0,-6.0/9.0, 0.0, 8.0/9.0,-6.0/9.0, 2.0/9.0, 8.0/9.0,-6.0/9.0, + 4.0/9.0, 8.0/9.0,-6.0/9.0, 6.0/9.0, 8.0/9.0,-6.0/9.0, 8.0/9.0, 8.0/9.0,-6.0/9.0, + -8.0/9.0,-8.0/9.0,-4.0/9.0, -6.0/9.0,-8.0/9.0,-4.0/9.0, -4.0/9.0,-8.0/9.0,-4.0/9.0, + -2.0/9.0,-8.0/9.0,-4.0/9.0, 0.0,-8.0/9.0,-4.0/9.0, 2.0/9.0,-8.0/9.0,-4.0/9.0, + 4.0/9.0,-8.0/9.0,-4.0/9.0, 6.0/9.0,-8.0/9.0,-4.0/9.0, 8.0/9.0,-8.0/9.0,-4.0/9.0, + -8.0/9.0,-6.0/9.0,-4.0/9.0, -6.0/9.0,-6.0/9.0,-4.0/9.0, -4.0/9.0,-6.0/9.0,-4.0/9.0, + -2.0/9.0,-6.0/9.0,-4.0/9.0, 0.0,-6.0/9.0,-4.0/9.0, 2.0/9.0,-6.0/9.0,-4.0/9.0, + 4.0/9.0,-6.0/9.0,-4.0/9.0, 6.0/9.0,-6.0/9.0,-4.0/9.0, 8.0/9.0,-6.0/9.0,-4.0/9.0, + -8.0/9.0,-4.0/9.0,-4.0/9.0, -6.0/9.0,-4.0/9.0,-4.0/9.0, -4.0/9.0,-4.0/9.0,-4.0/9.0, + -2.0/9.0,-4.0/9.0,-4.0/9.0, 0.0,-4.0/9.0,-4.0/9.0, 2.0/9.0,-4.0/9.0,-4.0/9.0, + 4.0/9.0,-4.0/9.0,-4.0/9.0, 6.0/9.0,-4.0/9.0,-4.0/9.0, 8.0/9.0,-4.0/9.0,-4.0/9.0, + -8.0/9.0,-2.0/9.0,-4.0/9.0, -6.0/9.0,-2.0/9.0,-4.0/9.0, -4.0/9.0,-2.0/9.0,-4.0/9.0, + -2.0/9.0,-2.0/9.0,-4.0/9.0, 0.0,-2.0/9.0,-4.0/9.0, 2.0/9.0,-2.0/9.0,-4.0/9.0, + 4.0/9.0,-2.0/9.0,-4.0/9.0, 6.0/9.0,-2.0/9.0,-4.0/9.0, 8.0/9.0,-2.0/9.0,-4.0/9.0, + -8.0/9.0, 0.0,-4.0/9.0, -6.0/9.0, 0.0,-4.0/9.0, -4.0/9.0, 0.0,-4.0/9.0, + -2.0/9.0, 0.0,-4.0/9.0, 0.0, 0.0,-4.0/9.0, 2.0/9.0, 0.0,-4.0/9.0, + 4.0/9.0, 0.0,-4.0/9.0, 6.0/9.0, 0.0,-4.0/9.0, 8.0/9.0, 0.0,-4.0/9.0, + -8.0/9.0, 2.0/9.0,-4.0/9.0, -6.0/9.0, 2.0/9.0,-4.0/9.0, -4.0/9.0, 2.0/9.0,-4.0/9.0, + -2.0/9.0, 2.0/9.0,-4.0/9.0, 0.0, 2.0/9.0,-4.0/9.0, 2.0/9.0, 2.0/9.0,-4.0/9.0, + 4.0/9.0, 2.0/9.0,-4.0/9.0, 6.0/9.0, 2.0/9.0,-4.0/9.0, 8.0/9.0, 2.0/9.0,-4.0/9.0, + -8.0/9.0, 4.0/9.0,-4.0/9.0, -6.0/9.0, 4.0/9.0,-4.0/9.0, -4.0/9.0, 4.0/9.0,-4.0/9.0, + -2.0/9.0, 4.0/9.0,-4.0/9.0, 0.0, 4.0/9.0,-4.0/9.0, 2.0/9.0, 4.0/9.0,-4.0/9.0, + 4.0/9.0, 4.0/9.0,-4.0/9.0, 6.0/9.0, 4.0/9.0,-4.0/9.0, 8.0/9.0, 4.0/9.0,-4.0/9.0, + -8.0/9.0, 6.0/9.0,-4.0/9.0, -6.0/9.0, 6.0/9.0,-4.0/9.0, -4.0/9.0, 6.0/9.0,-4.0/9.0, + -2.0/9.0, 6.0/9.0,-4.0/9.0, 0.0, 6.0/9.0,-4.0/9.0, 2.0/9.0, 6.0/9.0,-4.0/9.0, + 4.0/9.0, 6.0/9.0,-4.0/9.0, 6.0/9.0, 6.0/9.0,-4.0/9.0, 8.0/9.0, 6.0/9.0,-4.0/9.0, + -8.0/9.0, 8.0/9.0,-4.0/9.0, -6.0/9.0, 8.0/9.0,-4.0/9.0, -4.0/9.0, 8.0/9.0,-4.0/9.0, + -2.0/9.0, 8.0/9.0,-4.0/9.0, 0.0, 8.0/9.0,-4.0/9.0, 2.0/9.0, 8.0/9.0,-4.0/9.0, + 4.0/9.0, 8.0/9.0,-4.0/9.0, 6.0/9.0, 8.0/9.0,-4.0/9.0, 8.0/9.0, 8.0/9.0,-4.0/9.0, + -8.0/9.0,-8.0/9.0,-2.0/9.0, -6.0/9.0,-8.0/9.0,-2.0/9.0, -4.0/9.0,-8.0/9.0,-2.0/9.0, + -2.0/9.0,-8.0/9.0,-2.0/9.0, 0.0,-8.0/9.0,-2.0/9.0, 2.0/9.0,-8.0/9.0,-2.0/9.0, + 4.0/9.0,-8.0/9.0,-2.0/9.0, 6.0/9.0,-8.0/9.0,-2.0/9.0, 8.0/9.0,-8.0/9.0,-2.0/9.0, + -8.0/9.0,-6.0/9.0,-2.0/9.0, -6.0/9.0,-6.0/9.0,-2.0/9.0, -4.0/9.0,-6.0/9.0,-2.0/9.0, + -2.0/9.0,-6.0/9.0,-2.0/9.0, 0.0,-6.0/9.0,-2.0/9.0, 2.0/9.0,-6.0/9.0,-2.0/9.0, + 4.0/9.0,-6.0/9.0,-2.0/9.0, 6.0/9.0,-6.0/9.0,-2.0/9.0, 8.0/9.0,-6.0/9.0,-2.0/9.0, + -8.0/9.0,-4.0/9.0,-2.0/9.0, -6.0/9.0,-4.0/9.0,-2.0/9.0, -4.0/9.0,-4.0/9.0,-2.0/9.0, + -2.0/9.0,-4.0/9.0,-2.0/9.0, 0.0,-4.0/9.0,-2.0/9.0, 2.0/9.0,-4.0/9.0,-2.0/9.0, + 4.0/9.0,-4.0/9.0,-2.0/9.0, 6.0/9.0,-4.0/9.0,-2.0/9.0, 8.0/9.0,-4.0/9.0,-2.0/9.0, + -8.0/9.0,-2.0/9.0,-2.0/9.0, -6.0/9.0,-2.0/9.0,-2.0/9.0, -4.0/9.0,-2.0/9.0,-2.0/9.0, + -2.0/9.0,-2.0/9.0,-2.0/9.0, 0.0,-2.0/9.0,-2.0/9.0, 2.0/9.0,-2.0/9.0,-2.0/9.0, + 4.0/9.0,-2.0/9.0,-2.0/9.0, 6.0/9.0,-2.0/9.0,-2.0/9.0, 8.0/9.0,-2.0/9.0,-2.0/9.0, + -8.0/9.0, 0.0,-2.0/9.0, -6.0/9.0, 0.0,-2.0/9.0, -4.0/9.0, 0.0,-2.0/9.0, + -2.0/9.0, 0.0,-2.0/9.0, 0.0, 0.0,-2.0/9.0, 2.0/9.0, 0.0,-2.0/9.0, + 4.0/9.0, 0.0,-2.0/9.0, 6.0/9.0, 0.0,-2.0/9.0, 8.0/9.0, 0.0,-2.0/9.0, + -8.0/9.0, 2.0/9.0,-2.0/9.0, -6.0/9.0, 2.0/9.0,-2.0/9.0, -4.0/9.0, 2.0/9.0,-2.0/9.0, + -2.0/9.0, 2.0/9.0,-2.0/9.0, 0.0, 2.0/9.0,-2.0/9.0, 2.0/9.0, 2.0/9.0,-2.0/9.0, + 4.0/9.0, 2.0/9.0,-2.0/9.0, 6.0/9.0, 2.0/9.0,-2.0/9.0, 8.0/9.0, 2.0/9.0,-2.0/9.0, + -8.0/9.0, 4.0/9.0,-2.0/9.0, -6.0/9.0, 4.0/9.0,-2.0/9.0, -4.0/9.0, 4.0/9.0,-2.0/9.0, + -2.0/9.0, 4.0/9.0,-2.0/9.0, 0.0, 4.0/9.0,-2.0/9.0, 2.0/9.0, 4.0/9.0,-2.0/9.0, + 4.0/9.0, 4.0/9.0,-2.0/9.0, 6.0/9.0, 4.0/9.0,-2.0/9.0, 8.0/9.0, 4.0/9.0,-2.0/9.0, + -8.0/9.0, 6.0/9.0,-2.0/9.0, -6.0/9.0, 6.0/9.0,-2.0/9.0, -4.0/9.0, 6.0/9.0,-2.0/9.0, + -2.0/9.0, 6.0/9.0,-2.0/9.0, 0.0, 6.0/9.0,-2.0/9.0, 2.0/9.0, 6.0/9.0,-2.0/9.0, + 4.0/9.0, 6.0/9.0,-2.0/9.0, 6.0/9.0, 6.0/9.0,-2.0/9.0, 8.0/9.0, 6.0/9.0,-2.0/9.0, + -8.0/9.0, 8.0/9.0,-2.0/9.0, -6.0/9.0, 8.0/9.0,-2.0/9.0, -4.0/9.0, 8.0/9.0,-2.0/9.0, + -2.0/9.0, 8.0/9.0,-2.0/9.0, 0.0, 8.0/9.0,-2.0/9.0, 2.0/9.0, 8.0/9.0,-2.0/9.0, + 4.0/9.0, 8.0/9.0,-2.0/9.0, 6.0/9.0, 8.0/9.0,-2.0/9.0, 8.0/9.0, 8.0/9.0,-2.0/9.0, + -8.0/9.0,-8.0/9.0, 0.0, -6.0/9.0,-8.0/9.0, 0.0, -4.0/9.0,-8.0/9.0, 0.0, + -2.0/9.0,-8.0/9.0, 0.0, 0.0,-8.0/9.0, 0.0, 2.0/9.0,-8.0/9.0, 0.0, + 4.0/9.0,-8.0/9.0, 0.0, 6.0/9.0,-8.0/9.0, 0.0, 8.0/9.0,-8.0/9.0, 0.0, + -8.0/9.0,-6.0/9.0, 0.0, -6.0/9.0,-6.0/9.0, 0.0, -4.0/9.0,-6.0/9.0, 0.0, + -2.0/9.0,-6.0/9.0, 0.0, 0.0,-6.0/9.0, 0.0, 2.0/9.0,-6.0/9.0, 0.0, + 4.0/9.0,-6.0/9.0, 0.0, 6.0/9.0,-6.0/9.0, 0.0, 8.0/9.0,-6.0/9.0, 0.0, + -8.0/9.0,-4.0/9.0, 0.0, -6.0/9.0,-4.0/9.0, 0.0, -4.0/9.0,-4.0/9.0, 0.0, + -2.0/9.0,-4.0/9.0, 0.0, 0.0,-4.0/9.0, 0.0, 2.0/9.0,-4.0/9.0, 0.0, + 4.0/9.0,-4.0/9.0, 0.0, 6.0/9.0,-4.0/9.0, 0.0, 8.0/9.0,-4.0/9.0, 0.0, + -8.0/9.0,-2.0/9.0, 0.0, -6.0/9.0,-2.0/9.0, 0.0, -4.0/9.0,-2.0/9.0, 0.0, + -2.0/9.0,-2.0/9.0, 0.0, 0.0,-2.0/9.0, 0.0, 2.0/9.0,-2.0/9.0, 0.0, + 4.0/9.0,-2.0/9.0, 0.0, 6.0/9.0,-2.0/9.0, 0.0, 8.0/9.0,-2.0/9.0, 0.0, + -8.0/9.0, 0.0, 0.0, -6.0/9.0, 0.0, 0.0, -4.0/9.0, 0.0, 0.0, + -2.0/9.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.0/9.0, 0.0, 0.0, + 4.0/9.0, 0.0, 0.0, 6.0/9.0, 0.0, 0.0, 8.0/9.0, 0.0, 0.0, + -8.0/9.0, 2.0/9.0, 0.0, -6.0/9.0, 2.0/9.0, 0.0, -4.0/9.0, 2.0/9.0, 0.0, + -2.0/9.0, 2.0/9.0, 0.0, 0.0, 2.0/9.0, 0.0, 2.0/9.0, 2.0/9.0, 0.0, + 4.0/9.0, 2.0/9.0, 0.0, 6.0/9.0, 2.0/9.0, 0.0, 8.0/9.0, 2.0/9.0, 0.0, + -8.0/9.0, 4.0/9.0, 0.0, -6.0/9.0, 4.0/9.0, 0.0, -4.0/9.0, 4.0/9.0, 0.0, + -2.0/9.0, 4.0/9.0, 0.0, 0.0, 4.0/9.0, 0.0, 2.0/9.0, 4.0/9.0, 0.0, + 4.0/9.0, 4.0/9.0, 0.0, 6.0/9.0, 4.0/9.0, 0.0, 8.0/9.0, 4.0/9.0, 0.0, + -8.0/9.0, 6.0/9.0, 0.0, -6.0/9.0, 6.0/9.0, 0.0, -4.0/9.0, 6.0/9.0, 0.0, + -2.0/9.0, 6.0/9.0, 0.0, 0.0, 6.0/9.0, 0.0, 2.0/9.0, 6.0/9.0, 0.0, + 4.0/9.0, 6.0/9.0, 0.0, 6.0/9.0, 6.0/9.0, 0.0, 8.0/9.0, 6.0/9.0, 0.0, + -8.0/9.0, 8.0/9.0, 0.0, -6.0/9.0, 8.0/9.0, 0.0, -4.0/9.0, 8.0/9.0, 0.0, + -2.0/9.0, 8.0/9.0, 0.0, 0.0, 8.0/9.0, 0.0, 2.0/9.0, 8.0/9.0, 0.0, + 4.0/9.0, 8.0/9.0, 0.0, 6.0/9.0, 8.0/9.0, 0.0, 8.0/9.0, 8.0/9.0, 0.0, + -8.0/9.0,-8.0/9.0, 2.0/9.0, -6.0/9.0,-8.0/9.0, 2.0/9.0, -4.0/9.0,-8.0/9.0, 2.0/9.0, + -2.0/9.0,-8.0/9.0, 2.0/9.0, 0.0,-8.0/9.0, 2.0/9.0, 2.0/9.0,-8.0/9.0, 2.0/9.0, + 4.0/9.0,-8.0/9.0, 2.0/9.0, 6.0/9.0,-8.0/9.0, 2.0/9.0, 8.0/9.0,-8.0/9.0, 2.0/9.0, + -8.0/9.0,-6.0/9.0, 2.0/9.0, -6.0/9.0,-6.0/9.0, 2.0/9.0, -4.0/9.0,-6.0/9.0, 2.0/9.0, + -2.0/9.0,-6.0/9.0, 2.0/9.0, 0.0,-6.0/9.0, 2.0/9.0, 2.0/9.0,-6.0/9.0, 2.0/9.0, + 4.0/9.0,-6.0/9.0, 2.0/9.0, 6.0/9.0,-6.0/9.0, 2.0/9.0, 8.0/9.0,-6.0/9.0, 2.0/9.0, + -8.0/9.0,-4.0/9.0, 2.0/9.0, -6.0/9.0,-4.0/9.0, 2.0/9.0, -4.0/9.0,-4.0/9.0, 2.0/9.0, + -2.0/9.0,-4.0/9.0, 2.0/9.0, 0.0,-4.0/9.0, 2.0/9.0, 2.0/9.0,-4.0/9.0, 2.0/9.0, + 4.0/9.0,-4.0/9.0, 2.0/9.0, 6.0/9.0,-4.0/9.0, 2.0/9.0, 8.0/9.0,-4.0/9.0, 2.0/9.0, + -8.0/9.0,-2.0/9.0, 2.0/9.0, -6.0/9.0,-2.0/9.0, 2.0/9.0, -4.0/9.0,-2.0/9.0, 2.0/9.0, + -2.0/9.0,-2.0/9.0, 2.0/9.0, 0.0,-2.0/9.0, 2.0/9.0, 2.0/9.0,-2.0/9.0, 2.0/9.0, + 4.0/9.0,-2.0/9.0, 2.0/9.0, 6.0/9.0,-2.0/9.0, 2.0/9.0, 8.0/9.0,-2.0/9.0, 2.0/9.0, + -8.0/9.0, 0.0, 2.0/9.0, -6.0/9.0, 0.0, 2.0/9.0, -4.0/9.0, 0.0, 2.0/9.0, + -2.0/9.0, 0.0, 2.0/9.0, 0.0, 0.0, 2.0/9.0, 2.0/9.0, 0.0, 2.0/9.0, + 4.0/9.0, 0.0, 2.0/9.0, 6.0/9.0, 0.0, 2.0/9.0, 8.0/9.0, 0.0, 2.0/9.0, + -8.0/9.0, 2.0/9.0, 2.0/9.0, -6.0/9.0, 2.0/9.0, 2.0/9.0, -4.0/9.0, 2.0/9.0, 2.0/9.0, + -2.0/9.0, 2.0/9.0, 2.0/9.0, 0.0, 2.0/9.0, 2.0/9.0, 2.0/9.0, 2.0/9.0, 2.0/9.0, + 4.0/9.0, 2.0/9.0, 2.0/9.0, 6.0/9.0, 2.0/9.0, 2.0/9.0, 8.0/9.0, 2.0/9.0, 2.0/9.0, + -8.0/9.0, 4.0/9.0, 2.0/9.0, -6.0/9.0, 4.0/9.0, 2.0/9.0, -4.0/9.0, 4.0/9.0, 2.0/9.0, + -2.0/9.0, 4.0/9.0, 2.0/9.0, 0.0, 4.0/9.0, 2.0/9.0, 2.0/9.0, 4.0/9.0, 2.0/9.0, + 4.0/9.0, 4.0/9.0, 2.0/9.0, 6.0/9.0, 4.0/9.0, 2.0/9.0, 8.0/9.0, 4.0/9.0, 2.0/9.0, + -8.0/9.0, 6.0/9.0, 2.0/9.0, -6.0/9.0, 6.0/9.0, 2.0/9.0, -4.0/9.0, 6.0/9.0, 2.0/9.0, + -2.0/9.0, 6.0/9.0, 2.0/9.0, 0.0, 6.0/9.0, 2.0/9.0, 2.0/9.0, 6.0/9.0, 2.0/9.0, + 4.0/9.0, 6.0/9.0, 2.0/9.0, 6.0/9.0, 6.0/9.0, 2.0/9.0, 8.0/9.0, 6.0/9.0, 2.0/9.0, + -8.0/9.0, 8.0/9.0, 2.0/9.0, -6.0/9.0, 8.0/9.0, 2.0/9.0, -4.0/9.0, 8.0/9.0, 2.0/9.0, + -2.0/9.0, 8.0/9.0, 2.0/9.0, 0.0, 8.0/9.0, 2.0/9.0, 2.0/9.0, 8.0/9.0, 2.0/9.0, + 4.0/9.0, 8.0/9.0, 2.0/9.0, 6.0/9.0, 8.0/9.0, 2.0/9.0, 8.0/9.0, 8.0/9.0, 2.0/9.0, + -8.0/9.0,-8.0/9.0, 4.0/9.0, -6.0/9.0,-8.0/9.0, 4.0/9.0, -4.0/9.0,-8.0/9.0, 4.0/9.0, + -2.0/9.0,-8.0/9.0, 4.0/9.0, 0.0,-8.0/9.0, 4.0/9.0, 2.0/9.0,-8.0/9.0, 4.0/9.0, + 4.0/9.0,-8.0/9.0, 4.0/9.0, 6.0/9.0,-8.0/9.0, 4.0/9.0, 8.0/9.0,-8.0/9.0, 4.0/9.0, + -8.0/9.0,-6.0/9.0, 4.0/9.0, -6.0/9.0,-6.0/9.0, 4.0/9.0, -4.0/9.0,-6.0/9.0, 4.0/9.0, + -2.0/9.0,-6.0/9.0, 4.0/9.0, 0.0,-6.0/9.0, 4.0/9.0, 2.0/9.0,-6.0/9.0, 4.0/9.0, + 4.0/9.0,-6.0/9.0, 4.0/9.0, 6.0/9.0,-6.0/9.0, 4.0/9.0, 8.0/9.0,-6.0/9.0, 4.0/9.0, + -8.0/9.0,-4.0/9.0, 4.0/9.0, -6.0/9.0,-4.0/9.0, 4.0/9.0, -4.0/9.0,-4.0/9.0, 4.0/9.0, + -2.0/9.0,-4.0/9.0, 4.0/9.0, 0.0,-4.0/9.0, 4.0/9.0, 2.0/9.0,-4.0/9.0, 4.0/9.0, + 4.0/9.0,-4.0/9.0, 4.0/9.0, 6.0/9.0,-4.0/9.0, 4.0/9.0, 8.0/9.0,-4.0/9.0, 4.0/9.0, + -8.0/9.0,-2.0/9.0, 4.0/9.0, -6.0/9.0,-2.0/9.0, 4.0/9.0, -4.0/9.0,-2.0/9.0, 4.0/9.0, + -2.0/9.0,-2.0/9.0, 4.0/9.0, 0.0,-2.0/9.0, 4.0/9.0, 2.0/9.0,-2.0/9.0, 4.0/9.0, + 4.0/9.0,-2.0/9.0, 4.0/9.0, 6.0/9.0,-2.0/9.0, 4.0/9.0, 8.0/9.0,-2.0/9.0, 4.0/9.0, + -8.0/9.0, 0.0, 4.0/9.0, -6.0/9.0, 0.0, 4.0/9.0, -4.0/9.0, 0.0, 4.0/9.0, + -2.0/9.0, 0.0, 4.0/9.0, 0.0, 0.0, 4.0/9.0, 2.0/9.0, 0.0, 4.0/9.0, + 4.0/9.0, 0.0, 4.0/9.0, 6.0/9.0, 0.0, 4.0/9.0, 8.0/9.0, 0.0, 4.0/9.0, + -8.0/9.0, 2.0/9.0, 4.0/9.0, -6.0/9.0, 2.0/9.0, 4.0/9.0, -4.0/9.0, 2.0/9.0, 4.0/9.0, + -2.0/9.0, 2.0/9.0, 4.0/9.0, 0.0, 2.0/9.0, 4.0/9.0, 2.0/9.0, 2.0/9.0, 4.0/9.0, + 4.0/9.0, 2.0/9.0, 4.0/9.0, 6.0/9.0, 2.0/9.0, 4.0/9.0, 8.0/9.0, 2.0/9.0, 4.0/9.0, + -8.0/9.0, 4.0/9.0, 4.0/9.0, -6.0/9.0, 4.0/9.0, 4.0/9.0, -4.0/9.0, 4.0/9.0, 4.0/9.0, + -2.0/9.0, 4.0/9.0, 4.0/9.0, 0.0, 4.0/9.0, 4.0/9.0, 2.0/9.0, 4.0/9.0, 4.0/9.0, + 4.0/9.0, 4.0/9.0, 4.0/9.0, 6.0/9.0, 4.0/9.0, 4.0/9.0, 8.0/9.0, 4.0/9.0, 4.0/9.0, + -8.0/9.0, 6.0/9.0, 4.0/9.0, -6.0/9.0, 6.0/9.0, 4.0/9.0, -4.0/9.0, 6.0/9.0, 4.0/9.0, + -2.0/9.0, 6.0/9.0, 4.0/9.0, 0.0, 6.0/9.0, 4.0/9.0, 2.0/9.0, 6.0/9.0, 4.0/9.0, + 4.0/9.0, 6.0/9.0, 4.0/9.0, 6.0/9.0, 6.0/9.0, 4.0/9.0, 8.0/9.0, 6.0/9.0, 4.0/9.0, + -8.0/9.0, 8.0/9.0, 4.0/9.0, -6.0/9.0, 8.0/9.0, 4.0/9.0, -4.0/9.0, 8.0/9.0, 4.0/9.0, + -2.0/9.0, 8.0/9.0, 4.0/9.0, 0.0, 8.0/9.0, 4.0/9.0, 2.0/9.0, 8.0/9.0, 4.0/9.0, + 4.0/9.0, 8.0/9.0, 4.0/9.0, 6.0/9.0, 8.0/9.0, 4.0/9.0, 8.0/9.0, 8.0/9.0, 4.0/9.0, + -8.0/9.0,-8.0/9.0, 6.0/9.0, -6.0/9.0,-8.0/9.0, 6.0/9.0, -4.0/9.0,-8.0/9.0, 6.0/9.0, + -2.0/9.0,-8.0/9.0, 6.0/9.0, 0.0,-8.0/9.0, 6.0/9.0, 2.0/9.0,-8.0/9.0, 6.0/9.0, + 4.0/9.0,-8.0/9.0, 6.0/9.0, 6.0/9.0,-8.0/9.0, 6.0/9.0, 8.0/9.0,-8.0/9.0, 6.0/9.0, + -8.0/9.0,-6.0/9.0, 6.0/9.0, -6.0/9.0,-6.0/9.0, 6.0/9.0, -4.0/9.0,-6.0/9.0, 6.0/9.0, + -2.0/9.0,-6.0/9.0, 6.0/9.0, 0.0,-6.0/9.0, 6.0/9.0, 2.0/9.0,-6.0/9.0, 6.0/9.0, + 4.0/9.0,-6.0/9.0, 6.0/9.0, 6.0/9.0,-6.0/9.0, 6.0/9.0, 8.0/9.0,-6.0/9.0, 6.0/9.0, + -8.0/9.0,-4.0/9.0, 6.0/9.0, -6.0/9.0,-4.0/9.0, 6.0/9.0, -4.0/9.0,-4.0/9.0, 6.0/9.0, + -2.0/9.0,-4.0/9.0, 6.0/9.0, 0.0,-4.0/9.0, 6.0/9.0, 2.0/9.0,-4.0/9.0, 6.0/9.0, + 4.0/9.0,-4.0/9.0, 6.0/9.0, 6.0/9.0,-4.0/9.0, 6.0/9.0, 8.0/9.0,-4.0/9.0, 6.0/9.0, + -8.0/9.0,-2.0/9.0, 6.0/9.0, -6.0/9.0,-2.0/9.0, 6.0/9.0, -4.0/9.0,-2.0/9.0, 6.0/9.0, + -2.0/9.0,-2.0/9.0, 6.0/9.0, 0.0,-2.0/9.0, 6.0/9.0, 2.0/9.0,-2.0/9.0, 6.0/9.0, + 4.0/9.0,-2.0/9.0, 6.0/9.0, 6.0/9.0,-2.0/9.0, 6.0/9.0, 8.0/9.0,-2.0/9.0, 6.0/9.0, + -8.0/9.0, 0.0, 6.0/9.0, -6.0/9.0, 0.0, 6.0/9.0, -4.0/9.0, 0.0, 6.0/9.0, + -2.0/9.0, 0.0, 6.0/9.0, 0.0, 0.0, 6.0/9.0, 2.0/9.0, 0.0, 6.0/9.0, + 4.0/9.0, 0.0, 6.0/9.0, 6.0/9.0, 0.0, 6.0/9.0, 8.0/9.0, 0.0, 6.0/9.0, + -8.0/9.0, 2.0/9.0, 6.0/9.0, -6.0/9.0, 2.0/9.0, 6.0/9.0, -4.0/9.0, 2.0/9.0, 6.0/9.0, + -2.0/9.0, 2.0/9.0, 6.0/9.0, 0.0, 2.0/9.0, 6.0/9.0, 2.0/9.0, 2.0/9.0, 6.0/9.0, + 4.0/9.0, 2.0/9.0, 6.0/9.0, 6.0/9.0, 2.0/9.0, 6.0/9.0, 8.0/9.0, 2.0/9.0, 6.0/9.0, + -8.0/9.0, 4.0/9.0, 6.0/9.0, -6.0/9.0, 4.0/9.0, 6.0/9.0, -4.0/9.0, 4.0/9.0, 6.0/9.0, + -2.0/9.0, 4.0/9.0, 6.0/9.0, 0.0, 4.0/9.0, 6.0/9.0, 2.0/9.0, 4.0/9.0, 6.0/9.0, + 4.0/9.0, 4.0/9.0, 6.0/9.0, 6.0/9.0, 4.0/9.0, 6.0/9.0, 8.0/9.0, 4.0/9.0, 6.0/9.0, + -8.0/9.0, 6.0/9.0, 6.0/9.0, -6.0/9.0, 6.0/9.0, 6.0/9.0, -4.0/9.0, 6.0/9.0, 6.0/9.0, + -2.0/9.0, 6.0/9.0, 6.0/9.0, 0.0, 6.0/9.0, 6.0/9.0, 2.0/9.0, 6.0/9.0, 6.0/9.0, + 4.0/9.0, 6.0/9.0, 6.0/9.0, 6.0/9.0, 6.0/9.0, 6.0/9.0, 8.0/9.0, 6.0/9.0, 6.0/9.0, + -8.0/9.0, 8.0/9.0, 6.0/9.0, -6.0/9.0, 8.0/9.0, 6.0/9.0, -4.0/9.0, 8.0/9.0, 6.0/9.0, + -2.0/9.0, 8.0/9.0, 6.0/9.0, 0.0, 8.0/9.0, 6.0/9.0, 2.0/9.0, 8.0/9.0, 6.0/9.0, + 4.0/9.0, 8.0/9.0, 6.0/9.0, 6.0/9.0, 8.0/9.0, 6.0/9.0, 8.0/9.0, 8.0/9.0, 6.0/9.0, + -8.0/9.0,-8.0/9.0, 8.0/9.0, -6.0/9.0,-8.0/9.0, 8.0/9.0, -4.0/9.0,-8.0/9.0, 8.0/9.0, + -2.0/9.0,-8.0/9.0, 8.0/9.0, 0.0,-8.0/9.0, 8.0/9.0, 2.0/9.0,-8.0/9.0, 8.0/9.0, + 4.0/9.0,-8.0/9.0, 8.0/9.0, 6.0/9.0,-8.0/9.0, 8.0/9.0, 8.0/9.0,-8.0/9.0, 8.0/9.0, + -8.0/9.0,-6.0/9.0, 8.0/9.0, -6.0/9.0,-6.0/9.0, 8.0/9.0, -4.0/9.0,-6.0/9.0, 8.0/9.0, + -2.0/9.0,-6.0/9.0, 8.0/9.0, 0.0,-6.0/9.0, 8.0/9.0, 2.0/9.0,-6.0/9.0, 8.0/9.0, + 4.0/9.0,-6.0/9.0, 8.0/9.0, 6.0/9.0,-6.0/9.0, 8.0/9.0, 8.0/9.0,-6.0/9.0, 8.0/9.0, + -8.0/9.0,-4.0/9.0, 8.0/9.0, -6.0/9.0,-4.0/9.0, 8.0/9.0, -4.0/9.0,-4.0/9.0, 8.0/9.0, + -2.0/9.0,-4.0/9.0, 8.0/9.0, 0.0,-4.0/9.0, 8.0/9.0, 2.0/9.0,-4.0/9.0, 8.0/9.0, + 4.0/9.0,-4.0/9.0, 8.0/9.0, 6.0/9.0,-4.0/9.0, 8.0/9.0, 8.0/9.0,-4.0/9.0, 8.0/9.0, + -8.0/9.0,-2.0/9.0, 8.0/9.0, -6.0/9.0,-2.0/9.0, 8.0/9.0, -4.0/9.0,-2.0/9.0, 8.0/9.0, + -2.0/9.0,-2.0/9.0, 8.0/9.0, 0.0,-2.0/9.0, 8.0/9.0, 2.0/9.0,-2.0/9.0, 8.0/9.0, + 4.0/9.0,-2.0/9.0, 8.0/9.0, 6.0/9.0,-2.0/9.0, 8.0/9.0, 8.0/9.0,-2.0/9.0, 8.0/9.0, + -8.0/9.0, 0.0, 8.0/9.0, -6.0/9.0, 0.0, 8.0/9.0, -4.0/9.0, 0.0, 8.0/9.0, + -2.0/9.0, 0.0, 8.0/9.0, 0.0, 0.0, 8.0/9.0, 2.0/9.0, 0.0, 8.0/9.0, + 4.0/9.0, 0.0, 8.0/9.0, 6.0/9.0, 0.0, 8.0/9.0, 8.0/9.0, 0.0, 8.0/9.0, + -8.0/9.0, 2.0/9.0, 8.0/9.0, -6.0/9.0, 2.0/9.0, 8.0/9.0, -4.0/9.0, 2.0/9.0, 8.0/9.0, + -2.0/9.0, 2.0/9.0, 8.0/9.0, 0.0, 2.0/9.0, 8.0/9.0, 2.0/9.0, 2.0/9.0, 8.0/9.0, + 4.0/9.0, 2.0/9.0, 8.0/9.0, 6.0/9.0, 2.0/9.0, 8.0/9.0, 8.0/9.0, 2.0/9.0, 8.0/9.0, + -8.0/9.0, 4.0/9.0, 8.0/9.0, -6.0/9.0, 4.0/9.0, 8.0/9.0, -4.0/9.0, 4.0/9.0, 8.0/9.0, + -2.0/9.0, 4.0/9.0, 8.0/9.0, 0.0, 4.0/9.0, 8.0/9.0, 2.0/9.0, 4.0/9.0, 8.0/9.0, + 4.0/9.0, 4.0/9.0, 8.0/9.0, 6.0/9.0, 4.0/9.0, 8.0/9.0, 8.0/9.0, 4.0/9.0, 8.0/9.0, + -8.0/9.0, 6.0/9.0, 8.0/9.0, -6.0/9.0, 6.0/9.0, 8.0/9.0, -4.0/9.0, 6.0/9.0, 8.0/9.0, + -2.0/9.0, 6.0/9.0, 8.0/9.0, 0.0, 6.0/9.0, 8.0/9.0, 2.0/9.0, 6.0/9.0, 8.0/9.0, + 4.0/9.0, 6.0/9.0, 8.0/9.0, 6.0/9.0, 6.0/9.0, 8.0/9.0, 8.0/9.0, 6.0/9.0, 8.0/9.0, + -8.0/9.0, 8.0/9.0, 8.0/9.0, -6.0/9.0, 8.0/9.0, 8.0/9.0, -4.0/9.0, 8.0/9.0, 8.0/9.0, + -2.0/9.0, 8.0/9.0, 8.0/9.0, 0.0, 8.0/9.0, 8.0/9.0, 2.0/9.0, 8.0/9.0, 8.0/9.0, + 4.0/9.0, 8.0/9.0, 8.0/9.0, 6.0/9.0, 8.0/9.0, 8.0/9.0, 8.0/9.0, 8.0/9.0, 8.0/9.0 +}; + + +static const REAL *grouptableA[16] = +{ 0,group5bits,group7bits,group10bits,0,0,0,0,0,0,0,0,0,0,0,0}; +static const REAL *grouptableB1[16] = +{ 0,group5bits,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; +static const REAL *grouptableB234[16] = +{ 0,group5bits,group7bits,0,group10bits,0,0,0,0,0,0,0,0,0,0,0}; + +static const int codelengthtableA[16] = +{ 0, 5, 7, 10, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; +static const int codelengthtableB1[16] = +{ 0, 5, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; +static const int codelengthtableB2[16] = +{ 0, 5, 7, 3, 10, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16 }; +static const int codelengthtableB3[8] = { 0, 5, 7, 3, 10, 4, 5, 16 }; +static const int codelengthtableB4[4] = { 0, 5, 7, 16 }; + + +static const REAL factortableA[16] = +{ 0.0, 1.0/2.0, 1.0/4.0, 1.0/8.0, + 1.0/8.0, 1.0/16.0, 1.0/32.0, 1.0/64.0, + 1.0/128.0, 1.0/256.0, 1.0/512.0, 1.0/1024.0, + 1.0/2048.0, 1.0/4096.0, 1.0/8192.0, 1.0/16384.0 }; +static const REAL factortableB1[16] = +{ 0.0, 1.0/2.0, 1.0/4.0, 1.0/8.0, + 1.0/16.0, 1.0/32.0, 1.0/64.0, 1.0/128.0, + 1.0/256.0, 1.0/512.0, 1.0/1024.0, 1.0/2048.0, + 1.0/4096.0, 1.0/8192.0, 1.0/16384.0, 1.0/32768.0 }; +static const REAL factortableB2[16] = +{ 0.0, 1.0/2.0, 1.0/4.0, 1.0/4.0, + 1.0/8.0, 1.0/8.0, 1.0/16.0, 1.0/32.0, + 1.0/64.0, 1.0/128.0, 1.0/256.0, 1.0/512.0, + 1.0/1024.0, 1.0/2048.0, 1.0/4096.0, 1.0/32768.0 }; +static const REAL factortableB3[8] = +{ 0.0, 1.0/2.0, 1.0/4.0, 1.0/4.0, 1.0/8.0, 1.0/8.0, 1.0/16.0, 1.0/32768.0 }; +static const REAL factortableB4[4] = { 0.0, 1.0/2.0, 1.0/4.0, 1.0/32768.0 }; + + +static const REAL ctableA[16]= +{ 0.0, 1.33333333333, 1.60000000000, 1.77777777777, + 1.06666666666, 1.03225806452, 1.01587301587, 1.00787401575, + 1.00392156863, 1.00195694716, 1.00097751711, 1.00048851979, + 1.00024420024, 1.00012208522, 1.00006103888, 1.00003051851}; +static const REAL ctableB1[16]= +{ 0.0, 1.33333333333, 1.14285714286, 1.06666666666, + 1.03225806452, 1.01587301587, 1.00787401575, 1.00392156863, + 1.00195694716, 1.00097751711, 1.00048851979, 1.00024420024, + 1.00012208522, 1.00006103888, 1.00003051851, 1.00001525902}; +static const REAL ctableB2[16] = +{ 0.0, 1.33333333333, 1.60000000000, 1.14285714286, + 1.77777777777, 1.06666666666, 1.03225806452, 1.01587301587, + 1.00787401575, 1.00392156863, 1.00195694716, 1.00097751711, + 1.00048851979, 1.00024420024, 1.00012208522, 1.00001525902}; +static const REAL ctableB3[8] = +{ 0.0, 1.33333333333, 1.60000000000, 1.14285714286, + 1.77777777777, 1.06666666666, 1.03225806452, 1.00001525902 }; +static const REAL ctableB4[4] = +{ 0.0, 1.33333333333, 1.60000000000, 1.00001525902 }; + + +static const REAL dtableA[16]= +{ 0.0, 0.50000000000, 0.50000000000, 0.50000000000, + 0.12500000000, 0.06250000000, 0.03125000000, 0.01562500000, + 0.00781250000, 0.00390625000, 0.00195312500, 0.00097656250, + 0.00048828125, 0.00024414063, 0.00012207031, 0.00006103516}; + +static const REAL dtableB1[16]= +{ 0.0, 0.50000000000, 0.25000000000, 0.12500000000, + 0.06250000000, 0.03125000000, 0.01562500000, 0.00781250000, + 0.00390625000, 0.00195312500, 0.00097656250, 0.00048828125, + 0.00024414063, 0.00012207031, 0.00006103516, 0.00003051758}; + +static const REAL dtableB2[16]= +{ 0.0, 0.50000000000, 0.50000000000, 0.25000000000, + 0.50000000000, 0.12500000000, 0.06250000000, 0.03125000000, + 0.01562500000, 0.00781250000, 0.00390625000, 0.00195312500, + 0.00097656250, 0.00048828125, 0.00024414063, 0.00003051758}; + +static const REAL dtableB3[8]= +{ 0.0, 0.50000000000, 0.50000000000, 0.25000000000, + 0.50000000000, 0.12500000000, 0.06250000000, 0.00003051758}; + +static const REAL dtableB4[4]= +{0.0, 0.50000000000, 0.50000000000, 0.00003051758}; + + + + + + +#endif diff --git a/mpeglib/lib/splay/mpegAudioBitWindow.cpp b/mpeglib/lib/splay/mpegAudioBitWindow.cpp new file mode 100644 index 00000000..5e63f1fc --- /dev/null +++ b/mpeglib/lib/splay/mpegAudioBitWindow.cpp @@ -0,0 +1,41 @@ +/* + bitwindow class + 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 "mpegAudioBitWindow.h" + + +#include <iostream> + +using namespace std; + +int MpegAudioBitWindow::getCanReadBits() { + int p=bitindex>>3; + int bytes=point - p; + int bits=bytes*8+(bitindex&7); + cout << "point:"<<point + << " p:"<<p + << " bytes:"<<bytes + <<" bitindex:"<<bitindex<<" can read:"<<bits<<endl; + return bits; +} + +void MpegAudioBitWindow::wrap(void) { + int p=bitindex>>3; + point&=(WINDOWSIZE-1); + + if(p>=point) { + for(register int i=4;i<point;i++) + buffer[WINDOWSIZE+i]=buffer[i]; + } + *((int *)(buffer+WINDOWSIZE))=*((int *)buffer); +} diff --git a/mpeglib/lib/splay/mpegAudioBitWindow.h b/mpeglib/lib/splay/mpegAudioBitWindow.h new file mode 100644 index 00000000..f7a2f64c --- /dev/null +++ b/mpeglib/lib/splay/mpegAudioBitWindow.h @@ -0,0 +1,141 @@ +/* + bitwindow class + 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 __MPEGBITWINDOW_H +#define __MPEGBITWINDOW_H + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef WORDS_BIGENDIAN +#define _KEY 0 +#else +#define _KEY 3 +#endif + + + +#define WINDOWSIZE 4096 +#define BITWINDOWSIZE (WINDOWSIZE*8) + + +class MpegAudioBitWindow { + + int point,bitindex; + char buffer[2*WINDOWSIZE]; + + public: + MpegAudioBitWindow(){bitindex=point=0;} + + inline void initialize(void) {bitindex=point=0;} + inline int gettotalbit(void) const {return bitindex;} + + inline void putbyte(int c) {buffer[point&(WINDOWSIZE-1)]=c;point++;} + void wrap(void); + inline void rewind(int bits) {bitindex-=bits;} + inline void forward(int bits) {bitindex+=bits;} + + // returns number of bits which can safley read + int getCanReadBits(); + + + // + // Ugly bitgetting inline functions for higher speed + // + + + inline int getbits(int bits) { + union + { + char store[4]; + int current; + }u; + int bi; + + if(!bits)return 0; + + u.current=0; + bi=(bitindex&7); + u.store[_KEY]=buffer[(bitindex>>3)&(WINDOWSIZE-1)]<<bi; + //u.store[_KEY]=buffer[bitindex>>3]<<bi; + bi=8-bi; + bitindex+=bi; + + while(bits) { + if(!bi) { + u.store[_KEY]=buffer[(bitindex>>3)&(WINDOWSIZE-1)]; + //u.store[_KEY]=buffer[bitindex>>3]; + bitindex+=8; + bi=8; + } + + if(bits>=bi) { + u.current<<=bi; + bits-=bi; + bi=0; + } + else { + u.current<<=bits; + bi-=bits; + bits=0; + } + } + bitindex-=bi; + + return (u.current>>8); + } + + + int getbit(void) { + register int r=(buffer[(bitindex>>3)&(WINDOWSIZE-1)]>>(7-(bitindex&7)))&1; + //register int r=(buffer[bitindex>>3]>>(7-(bitindex&7)))&1; + bitindex++; + return r; + } + + // no range check version + inline int getbits9_f(int bits) { + register unsigned short a; + { + int offset=bitindex>>3; + a=(((unsigned char)buffer[offset])<<8)|((unsigned char)buffer[offset+1]); + } + a<<=(bitindex&7); + bitindex+=bits; + return (int)((unsigned int)(a>>(16-bits))); + } + + // range check version + int getbits9(int bits) { + register unsigned short a; + { + int offset=(bitindex>>3)&(WINDOWSIZE-1); + a=(((unsigned char)buffer[offset])<<8)|((unsigned char)buffer[offset+1]); + } + + a<<=(bitindex&7); + bitindex+=bits; + return (int)((unsigned int)(a>>(16-bits))); + } + + int peek8() { + int offset = (bitindex>>3)&(WINDOWSIZE-1), a; + a=(((unsigned char)buffer[offset])<<8) | ((unsigned char)buffer[offset+1]); + return (a >> (8-(bitindex&7))) & 0xff; + } + + +}; +#endif diff --git a/mpeglib/lib/splay/mpegAudioFrame.cpp b/mpeglib/lib/splay/mpegAudioFrame.cpp new file mode 100644 index 00000000..807a23a6 --- /dev/null +++ b/mpeglib/lib/splay/mpegAudioFrame.cpp @@ -0,0 +1,200 @@ +/* + converts raw mpeg audio stream data into mpeg I encoded audio frames/packets + Copyright (C) 2001 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 "mpegAudioFrame.h" + +#define MPEGAUDIOFRAMESIZE 4096 + +#define FRAME_SYNC 0 +#define FRAME_CHECK_HEADER_1 1 +#define FRAME_CHECK_HEADER_2 2 + +#include <iostream> + +using namespace std; + +MpegAudioFrame::MpegAudioFrame():Framer(MPEGAUDIOFRAMESIZE) { + mpegAudioHeader=new MpegAudioHeader(); +} + + +MpegAudioFrame::~MpegAudioFrame() { + delete mpegAudioHeader; +} + + +void MpegAudioFrame::unsync(RawDataBuffer* store,int ) { + // invalidate header in buffer + unsigned char* start=store->ptr(); + start[0]=0x0; + start[1]=0x0; + store->setpos(0); + find_frame_state=FRAME_SYNC; + framesize=0; +} + + +/** + here we parse byte by byte the raw input, first + we search for the magic bytes: 0xfffx, then + we read the remaining 2 bytes for the header, + check if they are "wrong" in a mpeg I audio special way. + If everything is fine, we continue with the next state. + + Note: we can be sure here, that the "store" can at least + store 4 bytes. +*/ +int MpegAudioFrame::find_frame(RawDataBuffer* input_buffer, + RawDataBuffer* store_buffer) { + unsigned char* store=store_buffer->current(); + int back=false; + + if (find_frame_state == FRAME_SYNC) { + if (store_buffer->pos() != 0) { + cout << "store buffer not at beginning MpegAudioFrame::find_frame"<<endl; + cout << "current state requires this"<<endl; + exit(0); + } + } + + while(input_buffer->eof()==false) { + // search for sync bytes + unsigned char* input=input_buffer->current(); + if (find_frame_state == FRAME_SYNC) { + while(input_buffer->eof() == false) { + input=input_buffer->current(); + // shift + store[0]=store[1]; + store[1]=input[0]; + input_buffer->inc(); + + if (store[0] != 0xff) { + continue; + } + // upper 4 bit are syncword, except bit one + // which is layer 2.5 indicator. + if ( (store[1] & 0xe0) != 0xe0) { + continue; + } + + // found header, now check if other info is ok, too. + store_buffer->setpos(2); + find_frame_state=FRAME_CHECK_HEADER_1; + break; + } + // back to "main loop" + continue; + } + // ok, try to read two other bytes and then validate the header + if (find_frame_state == FRAME_CHECK_HEADER_1) { + store[2]=input[0]; + input_buffer->inc(); + find_frame_state=FRAME_CHECK_HEADER_2; + // back to main loop + continue; + } + if (find_frame_state == FRAME_CHECK_HEADER_2) { + store[3]=input[0]; + input_buffer->inc(); + } + + // ok, read 4 header bytes. Now check the validity of the + // header. + int lHeaderOk; + lHeaderOk=mpegAudioHeader->parseHeader(store); + if (lHeaderOk == false) { + find_frame_state=FRAME_SYNC; + store_buffer->setpos(0); + // go back to "sync for frame" + continue; + } + framesize=mpegAudioHeader->getFramesize(); + // if framesize > max mepg framsize its an error + if (framesize+4 >= store_buffer->size()) { + find_frame_state=FRAME_SYNC; + store_buffer->setpos(0); + // go back to "sync for frame" + continue; + } + // don't allow stupid framesizes: + if (framesize <= 4) { + find_frame_state=FRAME_SYNC; + store_buffer->setpos(0); + continue; + } + // yup! found valid header. forward states + store_buffer->setpos(4); + back=true; + break; + } + return back; +} + + +/** + here we read data until len=framesize. + Then we go to the HAS_FRAME state. +*/ +int MpegAudioFrame::read_frame(RawDataBuffer* input_buffer, + RawDataBuffer* store_buffer) { + unsigned char* store=store_buffer->current(); + + while(input_buffer->eof()==false) { + int has=store_buffer->pos(); + int need=framesize-has; + if(need == 0) { + // yup! frame fully read. forward states. + // go to end state for main_state. + return true; + } + // try to do a memcpy for speed. + int can=input_buffer->untilend(); + if(can > need) { + can=need; + } + unsigned char* input=input_buffer->current(); + memcpy(store,input,can); + store_buffer->inc(can); + input_buffer->inc(can); + } + int need=framesize-store_buffer->pos(); + + if(need == 0) { + // yup! frame fully read. forward states. + // go to end state for main_state. + return true; + } + return false; +} + + + +void MpegAudioFrame::printPrivateStates() { + cout << "MpegAudioFrame::printPrivateStates"<<endl; + switch(find_frame_state) { + case FRAME_SYNC: + cout << "frame_state: FRAME_SYNC"<<endl; + break; + case FRAME_CHECK_HEADER_1: + cout << "frame_state: FRAME_CHECK_HEADER_1"<<endl; + break; + case FRAME_CHECK_HEADER_2: + cout << "frame_state: FRAME_CHECK_HEADER_2"<<endl; + break; + default: + cout << "unknown illegal frame_state:"<<find_frame_state<<endl; + } + + +} + diff --git a/mpeglib/lib/splay/mpegAudioFrame.h b/mpeglib/lib/splay/mpegAudioFrame.h new file mode 100644 index 00000000..8b4f6c4f --- /dev/null +++ b/mpeglib/lib/splay/mpegAudioFrame.h @@ -0,0 +1,66 @@ +/* + converts raw mpeg audio stream data into mpeg I encoded audio frames/packets + Copyright (C) 2001 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 __MPEGAUDIOFRAME_H +#define __MPEGAUDIOFRAME_H + +#include "mpegAudioHeader.h" +#include "../frame/framer.h" +#include <kdemacros.h> + +/* + Here we are framing from raw to mpeg audio. +*/ + + + + +class KDE_EXPORT MpegAudioFrame : public Framer { + + // max size of buffer is: + // header: 4 + // max bitrate: 448 + // min freq: 22050 + // padding: 1 + // ------------------ + // maxsize: 4+144000*max(bitrate)/min(freq)+1 ca: 2931 byte + // then we add a "sentinel" at the end these are 4 byte. + // so we should be ok, with a 4KB buffer. + + // internal, how much data we need to read + int framesize; + + // internall, for header searching + int find_frame_state; + + // internal use for header parsing+validating + MpegAudioHeader* mpegAudioHeader; + + public: + MpegAudioFrame(); + ~MpegAudioFrame(); + + + private: + + int find_frame(RawDataBuffer* input,RawDataBuffer* store); + int read_frame(RawDataBuffer* input,RawDataBuffer* store); + + void unsync(RawDataBuffer* store,int lReset); + void printPrivateStates(); + +}; + + +#endif diff --git a/mpeglib/lib/splay/mpegAudioHeader.cpp b/mpeglib/lib/splay/mpegAudioHeader.cpp new file mode 100644 index 00000000..7e34b212 --- /dev/null +++ b/mpeglib/lib/splay/mpegAudioHeader.cpp @@ -0,0 +1,268 @@ +/* + stores information after we found a header. + 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 "mpegAudioHeader.h" + +#define DEBUG_HEADER(x) +//#define DEBUG_HEADER(x) x + + +#include <iostream> + +using namespace std; + +static const int frequencies[3][3]= { + {44100,48000,32000}, // MPEG 1 + {22050,24000,16000}, // MPEG 2 + {11025,12000,8000} // MPEG 2.5 +}; + +static int translate[3][2][16] = { { { 2,0,0,2,2,2,3,3,3,3,3,3,3,3,3,2 } , + { 2,0,0,0,0,0,0,2,2,2,3,3,3,3,3,2 } } , + { { 2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2 } , + { 2,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2 } } , + { { 2,1,1,2,2,2,3,3,3,3,3,3,3,3,3,2 } , + { 2,1,1,1,1,1,1,2,2,2,3,3,3,3,3,2 } } }; + + +static int sblims[5] = { 8 , 12 , 27, 30 , 30 }; + + +static const int bitrate[2][3][15]= { + // MPEG 1 + {{0,32,64,96,128,160,192,224,256,288,320,352,384,416,448}, + {0,32,48,56,64,80,96,112,128,160,192,224,256,320,384}, + {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320}}, + + // MPEG 2 + {{0,32,48,56,64,80,96,112,128,144,160,176,192,224,256}, + {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160}, + {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160}} +}; + + +MpegAudioHeader::MpegAudioHeader() { + +} + + +MpegAudioHeader::~MpegAudioHeader() { +} + + +int MpegAudioHeader::getChannelbitrate() { + cout << "getChannelbitrate not implemented"<<endl; + return 0; +} + +int MpegAudioHeader::parseHeader(unsigned char* buf){ + + int c; + int mpeg25=false; + + + // Analyzing + header[0]=buf[0]; + header[1]=buf[1]; + header[2]=buf[2]; + header[3]=buf[3]; + + c=buf[1]; + lmpeg25=false; + if ( (c&0xf0) == 0xe0) { + lmpeg25=true; + } + + c&=0xf; + protection=c&1; + layer=4-((c>>1)&3); + // we catch the layer==4 error later, for now go on with parsing + version=(int)(((c>>3)&1)^1); + if ((version==0) && lmpeg25) { + DEBUG_HEADER(cout << "wrong lsf/mpeg25 combination"<<endl;) + return false; + } + c=buf[2]; + + c=((c))>>1; + padding=(c&1); + c>>=1; + frequency=(int)(c&3); + c>>=2; + bitrateindex=(int)c; + if(bitrateindex>=15) { + DEBUG_HEADER(cout << "bitrateindex error"<<endl;) + return false; + } + c=buf[3]; + + c=((unsigned int)(c))>>4; + extendedmode=c&3; + mode=(int)(c>>2); + + + // Making information + inputstereo= (mode==_MODE_SINGLE)?0:1; + + // + // frequency can be 0,1 or 2 but the mask above allows 3 as well + // check now. + if (frequency > 2) { + DEBUG_HEADER(cout << "frequency value out of range"<<endl;) + return false; + } + + // + // does not belong here should be in the layer specific parts. [START] + // + + switch(layer) { + case 3: + subbandnumber=0; + stereobound=0; + tableindex=0; + break; + case 2: + tableindex = translate[frequency][inputstereo][bitrateindex]; + subbandnumber = sblims[tableindex]; + stereobound = subbandnumber; + /* + Now merge the tableindex, for the bitalloclengthtable + */ + tableindex=tableindex>>1; + if(mode==_MODE_SINGLE)stereobound=0; + if(mode==_MODE_JOINT)stereobound=(extendedmode+1)<<2; + + break; + case 1: + subbandnumber=MAXSUBBAND; + stereobound=subbandnumber; + tableindex=0; + if(mode==_MODE_SINGLE)stereobound=0; + if(mode==_MODE_JOINT)stereobound=(extendedmode+1)<<2; + break; + default: + DEBUG_HEADER(cout <<"unknown layer"<<endl;) + return false; + } + + // + // does not belong here should be in the layer specific parts. [END] + // + frequencyHz=frequencies[version+lmpeg25][frequency]; + // framesize & slots + if(layer==1) { + if (frequencyHz <= 0) { + return false; + } + framesize=(12000*bitrate[version][0][bitrateindex])/frequencyHz; + + if(frequency==_FREQUENCY_44100 && padding)framesize++; + framesize<<=2; + } else { + int freq=frequencyHz<<version; + if (freq <= 0) { + return false; + } + framesize=(144000*bitrate[version][layer-1][bitrateindex])/freq; + + if(padding)framesize++; + if(layer==3) { + if(version) + layer3slots=framesize-((mode==_MODE_SINGLE)?9:17) + -(protection?0:2) + -4; + else + layer3slots=framesize-((mode==_MODE_SINGLE)?17:32) + -(protection?0:2) + -4; + } + } + if (framesize <= 0) { + DEBUG_HEADER(cout << "framesize negative"<<endl;) + return false; + } + return true; + +} + + +int MpegAudioHeader::getpcmperframe() { + int s; + + s=32; + if(layer==3) { + s*=18; + if(version==0)s*=2; + } + else { + s*=SCALEBLOCK; + if(layer==2)s*=3; + } + + return s; +} + + +void MpegAudioHeader::copyTo(MpegAudioHeader* dest) { + dest->protection=protection; + dest->layer=layer; + dest->version=version; + dest->padding=padding; + dest->frequency=frequency; + dest->frequencyHz=frequencyHz; + dest->bitrateindex=bitrateindex; + dest->extendedmode=extendedmode; + dest->mode=mode; + dest->inputstereo=inputstereo; + dest->channelbitrate=channelbitrate; + dest->tableindex=tableindex; + dest->subbandnumber=subbandnumber; + dest->stereobound=stereobound; + dest->framesize=framesize; + dest->layer3slots=layer3slots; + dest->lmpeg25=lmpeg25; +} + + +void MpegAudioHeader::print(const char* name) { + cout << "MpegAudioHeader [START]:"<<name<<endl; + printf("header:%1x%1x%1x%1x\n",header[0],header[1],header[2],header[3]); + cout << "getProtection:"<<getProtection()<<endl; + cout << "getLayer:"<<getLayer()<<endl; + cout << "getVersion:"<<getVersion()<<endl; + cout << "getPadding:"<<getPadding()<<endl; + cout << "getFrequency:"<<getFrequency()<<endl; + cout << "getFrequencyHz:"<<getFrequencyHz()<<endl; + cout << "getBitrateindex:"<<getBitrateindex()<<endl; + cout << "getExtendedmode:"<<getExtendedmode()<<endl; + cout << "getMode():"<<getMode()<<endl; + cout << "getInputstereo:"<<getInputstereo()<<endl; + cout << "getChannelbitrate:"<<getChannelbitrate()<<endl; + cout << "getTableindex:"<<getTableindex()<<endl; + cout << "getSubbandnumber:"<<getSubbandnumber()<<endl; + cout << "getStereobound:"<<getStereobound()<<endl; + cout << "getFramesize:"<<getFramesize()<<endl; + cout << "getLayer3slots:"<<getLayer3slots()<<endl; + cout << "getpcmperframe:"<<getpcmperframe()<<endl; + cout << "MpegAudioHeader [END]:"<<name<<endl; + +} + + + + + + + diff --git a/mpeglib/lib/splay/mpegAudioHeader.h b/mpeglib/lib/splay/mpegAudioHeader.h new file mode 100644 index 00000000..ff5b885a --- /dev/null +++ b/mpeglib/lib/splay/mpegAudioHeader.h @@ -0,0 +1,101 @@ +/* + stores information after we found a header. + 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 __MPEGHEADERINFO_H +#define __MPEGHEADERINFO_H + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define _FREQUENCY_44100 0 +#define _FREQUENCY_48000 1 +#define _FREQUENCY_32000 2 + +#define _MODE_FULLSTEREO 0 +#define _MODE_JOINT 1 +#define _MODE_DUAL 2 +#define _MODE_SINGLE 3 + +#define _VERSION_1 0 +#define _VERSION_2 1 + + +#define MAXSUBBAND 32 +#define SCALEBLOCK 12 + + + +class MpegAudioHeader { + + int protection; + int layer; + int version; + int padding; + int frequency; + int frequencyHz; + int bitrateindex; + int extendedmode; + int mode; + int inputstereo; + int channelbitrate; + int tableindex; + int subbandnumber; + int stereobound; + int framesize; + int layer3slots; + int lmpeg25; + unsigned char header[4]; + + public: + MpegAudioHeader(); + ~MpegAudioHeader(); + + int parseHeader(unsigned char* buf); + + inline int getProtection() { return protection; } + inline int getLayer() { return layer; } + inline int getVersion() { return version; } + inline int getPadding() { return padding; } + inline int getFrequency() { return frequency; } + inline int getFrequencyHz() { return frequencyHz; } + inline int getBitrateindex() { return bitrateindex; } + inline int getExtendedmode() { return extendedmode; } + inline int getMode() { return mode; } + inline int getInputstereo() { return inputstereo; } + inline int getFramesize() { return framesize; } + inline int getLayer25() { return lmpeg25; } + + // MPEG layer 2 + inline int getTableindex() { return tableindex; } + // MPEG layer 1/2 + inline int getSubbandnumber() { return subbandnumber; } + inline int getStereobound() { return stereobound; } + // MPEG layer 3 + inline int getLayer3slots() { return layer3slots; } + + int getChannelbitrate(); + + + inline unsigned char* getHeader() { return header; } + int getpcmperframe(); + + + void copyTo(MpegAudioHeader* dest); + + void print(const char* name); + void printStates(const char* name); +}; +#endif diff --git a/mpeglib/lib/splay/mpegAudioInfo.cpp b/mpeglib/lib/splay/mpegAudioInfo.cpp new file mode 100644 index 00000000..981b5bd6 --- /dev/null +++ b/mpeglib/lib/splay/mpegAudioInfo.cpp @@ -0,0 +1,262 @@ +/* + length detection etc.. for mpeg audio + Copyright (C) 2001 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 _FROM_SOURCE +#define _FROM_SOURCE 1 +#endif +#include "dxHead.h" +#include <string.h> +#include "mpegAudioInfo.h" +#include "mpegAudioHeader.h" +#include "mpegAudioStream.h" +#include "mpegAudioFrame.h" + +#include <iostream> + +using namespace std; + +#define _NEED_LENGTH 1 +#define _NEED_ID3 2 +#define _NEED_NOTHING 3 + + +MpegAudioInfo::MpegAudioInfo(FileAccess* input) { + xHeadData=new XHEADDATA(); + xHeadData->toc=new unsigned char[101]; + lXingVBR=false; + id3=new ID3TAG(); + this->input=input; + mpegAudioFrame =new MpegAudioFrame(); + mpegAudioStream=new MpegAudioStream(); + mpegAudioHeader=new MpegAudioHeader(); + reset(); +} + + +MpegAudioInfo::~MpegAudioInfo() { + delete[] (xHeadData->toc); + delete xHeadData; + delete id3; + delete mpegAudioStream; + delete mpegAudioHeader; + delete mpegAudioFrame; +} + + +int MpegAudioInfo::getByteDirect() { + unsigned char byte; + if (input->read((char*)&byte,1) != 1) { + leof=true; + return -1; + } + return (int)byte; +} + +void MpegAudioInfo::reset() { + length=0; + initState=_NEED_LENGTH; + lNeedInit=true; +} + + +int MpegAudioInfo::getNeedInit() { + return lNeedInit; +} + +void MpegAudioInfo::setNeedInit(int lNeedInit) { + this->lNeedInit=lNeedInit; +} + + +int MpegAudioInfo::initialize() { + long fileSize=input->getByteLength(); + switch(initState) { + case _NEED_NOTHING: + return true; + break; + case _NEED_LENGTH: + if (initializeLength(fileSize) == true) { + initState=_NEED_ID3; + } + return false; + case _NEED_ID3: + if (initializeID3(fileSize) == true) { + initState=_NEED_NOTHING; + return true; + } + return false; + default: + cout << "unknown initState in MpegAudioInfo::initialize"<<endl; + exit(0); + } + // never happens + return true; +} + + +int MpegAudioInfo::initializeLength(long fileSize) { + // if we are streaming don't touch the stream for length detection + if (fileSize == 0) { + return true; + } + int back=getFrame(mpegAudioFrame); + if (back != true) { + return back; + } + // found a valid frame (back == true) + // store information in header. + if (mpegAudioHeader->parseHeader(mpegAudioFrame->outdata()) == false) { + cout << "parse header false"<<endl; + return false; + } + calculateLength(fileSize); + return back; +} + +int MpegAudioInfo::initializeID3(long fileSize) { + int pos=input->getBytePosition(); + if (input->seek(fileSize-128)<0) { + return true; + } + parseID3(); + input->seek(pos); + return true; +} + + +long MpegAudioInfo::getLength() { + return length; +} + + +void MpegAudioInfo::calculateLength(long fileSize) { + + int totalframe=0; + int framesize=mpegAudioHeader->getFramesize(); + if (framesize > 0) { + totalframe=fileSize/framesize; + + if (parseXing(mpegAudioFrame->outdata(),mpegAudioFrame->len()) == true) { + lXingVBR=true; + totalframe=xHeadData->frames; + } + } + + float pcm=mpegAudioHeader->getpcmperframe(); + float wavfilesize=(totalframe*pcm); + float frequence=(float)mpegAudioHeader->getFrequencyHz(); + length=0; + if (frequence != 0) { + length=(int)(wavfilesize/frequence); + } +} + + +int MpegAudioInfo::parseXing(unsigned char* frame,int size) { + + int back=false; + if (size < 152) { + return false; + } + back=GetXingHeader(xHeadData,(unsigned char*)frame); + return back; + +} + + + +long MpegAudioInfo::getSeekPosition(int second) { + float length=getLength(); + long fileSize=input->getByteLength(); + long pos=0; + if (length<1.0) { + return 0; + } + float percent=(float)second/length; + + if (lXingVBR) { + pos=SeekPoint(xHeadData->toc,(int)fileSize,100.0*percent); + return pos; + } + pos=(long)(percent*(float)fileSize); + return pos; +} + + +void MpegAudioInfo::parseID3() { + + id3->name [0]=0; + id3->artist [0]=0; + id3->album [0]=0; + id3->year [0]=0; + id3->comment [0]=0; + id3->genre =0; + + leof=false; + + while(leof == false) { + if(getByteDirect()==0x54) + if(getByteDirect()==0x41) + if(getByteDirect()==0x47) { + input->read((char*)&id3->name ,30);id3->name[30]=0; + input->read((char*)&id3->artist ,30);id3->artist[30]=0; + input->read((char*)&id3->album ,30);id3->album[30]=0; + input->read((char*)&id3->year , 4);id3->year[4]=0; + input->read((char*)&id3->comment ,30);id3->comment[30]=0; + input->read((char*)&id3->genre ,1); + return; + } + } +} + + + +void MpegAudioInfo::print(const char* msg) { + cout << "MpegAudioInfo:"<<msg<<endl; + cout << "Length (sec):"<<length<<endl; + cout << "VBR:"<<lXingVBR<<endl; + cout << "ID3: Name:"<<id3->name<<endl; + cout << "ID3: Artist:"<<id3->artist<<endl; + cout << "ID3: Album:"<<id3->album<<endl; + cout << "ID3: year:"<<id3->year<<endl; + cout << "ID3: genre:"<<(int)(id3->genre)<<endl; + cout << "ID3: comment:"<<id3->comment<<endl; + +} + + +int MpegAudioInfo::getFrame(MpegAudioFrame* frame) { + int state=frame->getState(); + switch(state) { + case FRAME_NEED: { + int bytes=frame->canStore(); + int read=input->read((char*)inputbuffer,bytes); + if (read <= 0) { + // read error. reset framer + frame->reset(); + break; + } + frame->store(inputbuffer,bytes); + break; + } + case FRAME_WORK: + frame->work(); + break; + case FRAME_HAS: + return true; + break; + default: + cout << "unknown state in mpeg audio framing"<<endl; + exit(0); + } + return false; +} diff --git a/mpeglib/lib/splay/mpegAudioInfo.h b/mpeglib/lib/splay/mpegAudioInfo.h new file mode 100644 index 00000000..65298ca6 --- /dev/null +++ b/mpeglib/lib/splay/mpegAudioInfo.h @@ -0,0 +1,95 @@ +/* + length detection etc.. for mpeg audio + Copyright (C) 2001 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 __MPEGAUDIOINFO_H +#define __MPEGAUDIOINFO_H + +#include "../util/file/fileAccess.h" + +class MpegAudioStream; +class MpegAudioHeader; +class MpegAudioFrame; + +typedef struct { + char name [30+1]; + char artist [30+1]; + char album [30+1]; + char year [ 4+1]; + char comment[30+1]; + unsigned char genre; +} ID3TAG; + + +class MpegAudioInfo { + + long length; + int lXingVBR; + ID3TAG* id3; + MpegAudioStream* mpegAudioStream; + MpegAudioHeader* mpegAudioHeader; + MpegAudioFrame * mpegAudioFrame; + FileAccess* input; + int leof; + + int initState; + unsigned char inputbuffer[8192]; + int lNeedInit; + public: + MpegAudioInfo(FileAccess* input); + ~MpegAudioInfo(); + + void reset(); + int initialize(); + + // store info wheter init need or not here.(after reset its true) + int getNeedInit(); + void setNeedInit(int lNeedInit); + + + // returns byte positions + long getSeekPosition(int second); + // returns length in seconds + long getLength(); + + // for id3 parsing you need to seek -128 bytes before the end of strem + // after parseID3 you must jump back to 0. This method is blocking + int initializeID3(); + ID3TAG* getID3(); + + void print(const char* msg); + + private: + // non-blocking init. return true,false,or -1==eof + int initializeLength(long fileSize); + int initializeID3(long fileSize); + + + + void calculateLength(long fileSize); + int parseXing(unsigned char* frame,int size); + + // used for seek + void parseID3(); + int getByteDirect(); + + // extension for xing vbr +#ifdef _FROM_SOURCE + XHEADDATA* xHeadData; +#else + void* xHeadData; +#endif + + private: + int getFrame(MpegAudioFrame* frame); + +}; +#endif diff --git a/mpeglib/lib/splay/mpegAudioStream.cpp b/mpeglib/lib/splay/mpegAudioStream.cpp new file mode 100644 index 00000000..b3061224 --- /dev/null +++ b/mpeglib/lib/splay/mpegAudioStream.cpp @@ -0,0 +1,43 @@ +/* + initializer/resyncer/frame detection etc.. for mpeg audio + 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 "mpegAudioStream.h" + +#include <stdlib.h> + +MpegAudioStream::MpegAudioStream() { + buffer=NULL; +} + + +MpegAudioStream::~MpegAudioStream() { +} + + + +void MpegAudioStream::setFrame(unsigned char* ptr,int len) { + this->buffer=(char*)ptr; + this->len=len; + bitindex=0; +} + + + + + + + + + + diff --git a/mpeglib/lib/splay/mpegAudioStream.h b/mpeglib/lib/splay/mpegAudioStream.h new file mode 100644 index 00000000..9e4accc3 --- /dev/null +++ b/mpeglib/lib/splay/mpegAudioStream.h @@ -0,0 +1,139 @@ +/* + initializer/resyncer/frame detection etc.. for mpeg audio + 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 __MPEGAUDIOSTREAM_H +#define __MPEGAUDIOSTREAM_H + +// we include this for the big_endian define + +#include "mpegAudioBitWindow.h" + +#define _MAX_MPEG_BUFFERSIZE 4096 + + +/** + Here we go from the frame to the bitlevel. + + +*/ + +class MpegAudioStream { + + char* buffer; + int len; + int bitindex; + + public: + MpegAudioStream(); + ~MpegAudioStream(); + + void setFrame(unsigned char* prt,int len); + + // Bit functions + + inline char* getBuffer() { return buffer; } + inline int getBufferSize() { return _MAX_MPEG_BUFFERSIZE ;} + inline void sync() { bitindex=(bitindex+7)&0xFFFFFFF8; } + inline int issync() { return (bitindex&7);}; + + /** + Now follow ugly inline function. The performance gain is 1.5 % + on a 400 MHz AMD + */ + + inline int getbyte() { + int r=(unsigned char)buffer[bitindex>>3]; + bitindex+=8; + return r; + } + + inline int getbits9(int bits) { + register unsigned short a; + { + int offset=bitindex>>3; + + a=(((unsigned char)buffer[offset])<<8) | + ((unsigned char)buffer[offset+1]); + } + + a<<=(bitindex&7); + bitindex+=bits; + return (int)((unsigned int)(a>>(16-bits))); + } + + inline int getbits8() { + register unsigned short a; + + { + int offset=bitindex>>3; + + a=(((unsigned char)buffer[offset])<<8) | + ((unsigned char)buffer[offset+1]); + } + + a<<=(bitindex&7); + bitindex+=8; + return (int)((unsigned int)(a>>8)); + } + + inline int getbit() { + register int r=(buffer[bitindex>>3]>>(7-(bitindex&7)))&1; + + bitindex++; + return r; + } + + inline int getbits(int bits) { + union + { + char store[4]; + int current; + }u; + int bi; + + if(!bits)return 0; + + u.current=0; + bi=(bitindex&7); + u.store[_KEY]=buffer[bitindex>>3]<<bi; + bi=8-bi; + bitindex+=bi; + + while(bits) { + if(!bi) { + u.store[_KEY]=buffer[bitindex>>3]; + bitindex+=8; + bi=8; + } + if(bits>=bi) { + u.current<<=bi; + bits-=bi; + bi=0; + } else { + u.current<<=bits; + bi-=bits; + bits=0; + } + } + bitindex-=bi; + return (u.current>>8); + } + + + + +}; + + +#endif diff --git a/mpeglib/lib/splay/mpeglayer1.cpp b/mpeglib/lib/splay/mpeglayer1.cpp new file mode 100644 index 00000000..a32951c4 --- /dev/null +++ b/mpeglib/lib/splay/mpeglayer1.cpp @@ -0,0 +1,109 @@ +/* MPEG/WAVE Sound library + + (C) 1997 by Jung woo-jae */ + +// Mpeglayer1.cc +// It's for MPEG Layer 1 + + + +#include "mpegsound.h" +#include "synthesis.h" + +// Tables for layer 1 +static const REAL factortable[15] = +{ + 0.0, + (1.0/2.0) * (4.0/3.0), (1.0/4.0) * (8.0/7.0), + (1.0/8.0) * (16.0/15.0), (1.0/16.0) * (32.0/31.0), + (1.0/32.0) * (64.0/63.0), (1.0/64.0) * (128.0/127.0), + (1.0/128.0) * (256.0/255.0), (1.0/256.0) * (512.0/511.0), + (1.0/512.0) * (1024.0/1023.0), (1.0/1024.0) * (2048.0/2047.0), + (1.0/2048.0) * (4096.0/4095.0), (1.0/4096.0) * (8192.0/8191.0), + (1.0/8192.0) * (16384.0/16383.0), (1.0/16384.0) * (32768.0/32767.0) +}; + +static const REAL offsettable[15] = +{ + 0.0, + ((1.0/2.0)-1.0) * (4.0/3.0), ((1.0/4.0)-1.0) * (8.0/7.0), + ((1.0/8.0)-1.0) * (16.0/15.0), ((1.0/16.0)-1.0) * (32.0/31.0), + ((1.0/32.0)-1.0) * (64.0/63.0), ((1.0/64.0)-1.0) * (128.0/127.0), + ((1.0/128.0)-1.0) * (256.0/255.0), ((1.0/256.0)-1.0) * (512.0/511.0), + ((1.0/512.0)-1.0) * (1024.0/1023.0), ((1.0/1024.0)-1.0) * (2048.0/2047.0), + ((1.0/2048.0)-1.0) * (4096.0/4095.0), ((1.0/4096.0)-1.0) * (8192.0/8191.0), + ((1.0/8192.0)-1.0) * (16384.0/16383.0), ((1.0/16384.0)-1.0) * (32768.0/32767.0) +}; + +// Mpeg layer 1 +void Mpegtoraw::extractlayer1(void) +{ + int inputstereo=mpegAudioHeader->getInputstereo(); + int stereobound=mpegAudioHeader->getStereobound(); + REAL fraction[MAXCHANNEL][MAXSUBBAND]; + REAL scalefactor[MAXCHANNEL][MAXSUBBAND]; + + int bitalloc[MAXCHANNEL][MAXSUBBAND], + sample[MAXCHANNEL][MAXSUBBAND]; + + register int i,j; + int s=stereobound,l; + + +// Bitalloc + for(i=0;i<s;i++) + { + bitalloc[LS][i]=getbits(4); + bitalloc[RS][i]=getbits(4); + } + for(;i<MAXSUBBAND;i++) + bitalloc[LS][i]= + bitalloc[RS][i]=getbits(4); + +// Scale index + if(inputstereo) + for(i=0;i<MAXSUBBAND;i++) + { + if(bitalloc[LS][i])scalefactor[LS][i]=scalefactorstable[getbits(6)]; + if(bitalloc[RS][i])scalefactor[RS][i]=scalefactorstable[getbits(6)]; + } + else + for(i=0;i<MAXSUBBAND;i++) + if(bitalloc[LS][i])scalefactor[LS][i]=scalefactorstable[getbits(6)]; + + for(l=0;l<SCALEBLOCK;l++) + { + // Sample + for(i=0;i<s;i++) + { + if((j=bitalloc[LS][i]))sample[LS][i]=getbits(j+1); + if((j=bitalloc[RS][i]))sample[RS][i]=getbits(j+1); + } + for(;i<MAXSUBBAND;i++) + if((j=bitalloc[LS][i]))sample[LS][i]=sample[RS][i]=getbits(j+1); + + + // Fraction + if(lOutputStereo) + for(i=0;i<MAXSUBBAND;i++) + { + if((j=bitalloc[LS][i])) + fraction[LS][i]=(REAL(sample[LS][i])*factortable[j]+offsettable[j]) + *scalefactor[LS][i]; + else fraction[LS][i]=0.0; + if((j=bitalloc[RS][i])) + fraction[RS][i]=(REAL(sample[RS][i])*factortable[j]+offsettable[j]) + *scalefactor[RS][i]; + else fraction[RS][i]=0.0; + } + else + for(i=0;i<MAXSUBBAND;i++) + if((j=bitalloc[LS][i])) + fraction[LS][i]=(REAL(sample[LS][i])*factortable[j]+offsettable[j]) + *scalefactor[LS][i]; + else fraction[LS][i]=0.0; + + synthesis->doSynth(lDownSample,lOutputStereo, + fraction[LS],fraction[RS]); + } +} diff --git a/mpeglib/lib/splay/mpeglayer2.cpp b/mpeglib/lib/splay/mpeglayer2.cpp new file mode 100644 index 00000000..4012ff27 --- /dev/null +++ b/mpeglib/lib/splay/mpeglayer2.cpp @@ -0,0 +1,449 @@ +/* MPEG/WAVE Sound library + + (C) 1997 by Jung woo-jae */ + +// Mpeglayer2.cc +// It's for MPEG Layer 2 + + +#include "mpegsound.h" +#include "synthesis.h" + +#include <iostream> + +using namespace std; + +#define BUGFIX +#include "mpeg2tables.h" + + +// workaround for buggy mpeg2 streams. +// tested with 12 monkey cdi, worgked fine. +// problem was: the stream produced ints +// with access out of the tables +// if we have such an access we set it to a zero entry +#ifdef BUGFIX +static int checkCodeRange(int code,const REAL* group) { + int back=0; + if (group == NULL) { + cout << "group null"<<endl; + return 0; + } + back=code; + + if (group == group5bits) { + if (back > 27*3) { + // redirect to zero value + back=3; + } + return back; + } + if (group == group7bits) { + if (back > 125*3) { + back=6; + } + return back; + } + if (group == group10bits) { + if (back > 729*3) { + back=12; + } + return back; + } + DEBUG_LAYER(cout << "unknown group found!"<<endl;) + return -1; +} + + +#endif + + + + + + + + +// Mpeg layer 2 +void Mpegtoraw::extractlayer2(void) { + int inputstereo=mpegAudioHeader->getInputstereo(); + int tableindex=mpegAudioHeader->getTableindex(); + int subbandnumber=mpegAudioHeader->getSubbandnumber(); + int stereobound=mpegAudioHeader->getStereobound(); + + REAL fraction[MAXCHANNEL][3][MAXSUBBAND]; + unsigned int bitalloc[MAXCHANNEL][MAXSUBBAND], + scaleselector[MAXCHANNEL][MAXSUBBAND]; + REAL scalefactor[2][3][MAXSUBBAND]; + + const REAL *group[MAXCHANNEL][MAXSUBBAND]; + unsigned int codelength[MAXCHANNEL][MAXSUBBAND]; + REAL factor[MAXCHANNEL][MAXSUBBAND]; + REAL c[MAXCHANNEL][MAXSUBBAND],d[MAXCHANNEL][MAXSUBBAND]; + + int s=stereobound,n=subbandnumber; + + + // Bitalloc + { + register int i; + register const int *t=bitalloclengthtable[tableindex]; + for(i=0;i<s;i++,t++) + { + bitalloc[LS][i]=getbits(*t); + bitalloc[RS][i]=getbits(*t); + } + for(;i<n;i++,t++) { + bitalloc[LS][i]=bitalloc[RS][i]=getbits(*t); + } + } + + + + // Scale selector + if(inputstereo) + for(register int i=0;i<n;i++) + { + if(bitalloc[LS][i])scaleselector[LS][i]=getbits(2); + if(bitalloc[RS][i])scaleselector[RS][i]=getbits(2); + } + else + for(register int i=0;i<n;i++) + if(bitalloc[LS][i])scaleselector[LS][i]=getbits(2); + + // Scale index + { + register int i,j; + + + for(i=0;i<n;i++) + { + if((j=bitalloc[LS][i])) + { + if(!tableindex) + { + group[LS][i]=grouptableA[j]; + codelength[LS][i]=codelengthtableA[j]; + factor[LS][i]=factortableA[j]; + c[LS][i]=ctableA[j]; + d[LS][i]=dtableA[j]; + } + else + { + if(i<=2) + { + group[LS][i]=grouptableB1[j]; + codelength[LS][i]=codelengthtableB1[j]; + factor[LS][i]=factortableB1[j]; + c[LS][i]=ctableB1[j]; + d[LS][i]=dtableB1[j]; + } + else + { + group[LS][i]=grouptableB234[j]; + if(i<=10) + { + codelength[LS][i]=codelengthtableB2[j]; + factor[LS][i]=factortableB2[j]; + c[LS][i]=ctableB2[j]; + d[LS][i]=dtableB2[j]; + } + else if(i<=22) + { + codelength[LS][i]=codelengthtableB3[j]; + factor[LS][i]=factortableB3[j]; + c[LS][i]=ctableB3[j]; + d[LS][i]=dtableB3[j]; + } + else + { + codelength[LS][i]=codelengthtableB4[j]; + factor[LS][i]=factortableB4[j]; + c[LS][i]=ctableB4[j]; + d[LS][i]=dtableB4[j]; + } + } + } + + + switch(scaleselector[LS][i]) + { + case 0:scalefactor[LS][0][i]=scalefactorstable[getbits(6)]; + scalefactor[LS][1][i]=scalefactorstable[getbits(6)]; + scalefactor[LS][2][i]=scalefactorstable[getbits(6)]; + break; + case 1:scalefactor[LS][0][i]= + scalefactor[LS][1][i]=scalefactorstable[getbits(6)]; + scalefactor[LS][2][i]=scalefactorstable[getbits(6)]; + break; + case 2:scalefactor[LS][0][i]= + scalefactor[LS][1][i]= + scalefactor[LS][2][i]=scalefactorstable[getbits(6)]; + break; + case 3:scalefactor[LS][0][i]=scalefactorstable[getbits(6)]; + scalefactor[LS][1][i]= + scalefactor[LS][2][i]=scalefactorstable[getbits(6)]; + break; + default: + cout << "scaleselector left default never happens"<<endl; + break; + } + } + + + if(inputstereo && (j=bitalloc[RS][i])) + { + if(!tableindex) + { + group[RS][i]=grouptableA[j]; + codelength[RS][i]=codelengthtableA[j]; + factor[RS][i]=factortableA[j]; + c[RS][i]=ctableA[j]; + d[RS][i]=dtableA[j]; + } + else + { + if(i<=2) + { + group[RS][i]=grouptableB1[j]; + codelength[RS][i]=codelengthtableB1[j]; + factor[RS][i]=factortableB1[j]; + c[RS][i]=ctableB1[j]; + d[RS][i]=dtableB1[j]; + } + else + { + group[RS][i]=grouptableB234[j]; + if(i<=10) + { + codelength[RS][i]=codelengthtableB2[j]; + factor[RS][i]=factortableB2[j]; + c[RS][i]=ctableB2[j]; + d[RS][i]=dtableB2[j]; + } + else if(i<=22) + { + codelength[RS][i]=codelengthtableB3[j]; + factor[RS][i]=factortableB3[j]; + c[RS][i]=ctableB3[j]; + d[RS][i]=dtableB3[j]; + } + else + { + codelength[RS][i]=codelengthtableB4[j]; + factor[RS][i]=factortableB4[j]; + c[RS][i]=ctableB4[j]; + d[RS][i]=dtableB4[j]; + } + } + } + + + switch(scaleselector[RS][i]) + { + case 0 : scalefactor[RS][0][i]=scalefactorstable[getbits(6)]; + scalefactor[RS][1][i]=scalefactorstable[getbits(6)]; + scalefactor[RS][2][i]=scalefactorstable[getbits(6)]; + break; + case 1 : scalefactor[RS][0][i]= + scalefactor[RS][1][i]=scalefactorstable[getbits(6)]; + scalefactor[RS][2][i]=scalefactorstable[getbits(6)]; + break; + case 2 : scalefactor[RS][0][i]= + scalefactor[RS][1][i]= + scalefactor[RS][2][i]=scalefactorstable[getbits(6)]; + break; + case 3 : scalefactor[RS][0][i]=scalefactorstable[getbits(6)]; + scalefactor[RS][1][i]= + scalefactor[RS][2][i]=scalefactorstable[getbits(6)]; + break; + default: + cout << "scaleselector right default never happens"<<endl; + break; + } + + + } + } + } + + + +// Read Sample + { + register int i; + + for(int l=0;l<SCALEBLOCK;l++) + { + // Read Sample + for(i=0;i<s;i++) + { + if(bitalloc[LS][i]) + { + if(group[LS][i]) + { + register const REAL *s; + int code=getbits(codelength[LS][i]); + + + + code+=code<<1; +#ifdef BUGFIX + // bugfix for bad streams + code=checkCodeRange(code,group[LS][i]); + if (code == -1) return; +#endif + s=group[LS][i]+code; + + fraction[LS][0][i]=s[0]; + fraction[LS][1][i]=s[1]; + fraction[LS][2][i]=s[2]; + } + else + { + fraction[LS][0][i]= + REAL(getbits(codelength[LS][i]))*factor[LS][i]-1.0; + fraction[LS][1][i]= + REAL(getbits(codelength[LS][i]))*factor[LS][i]-1.0; + fraction[LS][2][i]= + REAL(getbits(codelength[LS][i]))*factor[LS][i]-1.0; + } + } + else fraction[LS][0][i]=fraction[LS][1][i]=fraction[LS][2][i]=0.0; + + + if(inputstereo && bitalloc[RS][i]) + { + if(group[RS][i]) + { + const REAL *s; + int code=getbits(codelength[RS][i]); + + code+=code<<1; +#ifdef BUGFIX + // bugfix for bad streams + code=checkCodeRange(code,group[RS][i]); + if (code == -1) return; +#endif + s=group[RS][i]+code; + + fraction[RS][0][i]=s[0]; + fraction[RS][1][i]=s[1]; + fraction[RS][2][i]=s[2]; + } + else + { + fraction[RS][0][i]= + REAL(getbits(codelength[RS][i]))*factor[RS][i]-1.0; + fraction[RS][1][i]= + REAL(getbits(codelength[RS][i]))*factor[RS][i]-1.0; + fraction[RS][2][i]= + REAL(getbits(codelength[RS][i]))*factor[RS][i]-1.0; + } + } + else fraction[RS][0][i]=fraction[RS][1][i]=fraction[RS][2][i]=0.0; + } + + + for(;i<n;i++) + { + if(bitalloc[LS][i]) + { + if(group[LS][i]) + { + register const REAL *s; + int code=getbits(codelength[LS][i]); + + code+=code<<1; +#ifdef BUGFIX + // bugfix for bad streams + code=checkCodeRange(code,group[LS][i]); + if (code == -1) return; +#endif + s=group[LS][i]+code; + + fraction[LS][0][i]=fraction[RS][0][i]=s[0]; + fraction[LS][1][i]=fraction[RS][1][i]=s[1]; + fraction[LS][2][i]=fraction[RS][2][i]=s[2]; + } + else + { + fraction[LS][0][i]=fraction[RS][0][i]= + REAL(getbits(codelength[LS][i]))*factor[LS][i]-1.0; + fraction[LS][1][i]=fraction[RS][1][i]= + REAL(getbits(codelength[LS][i]))*factor[LS][i]-1.0; + fraction[LS][2][i]=fraction[RS][2][i]= + REAL(getbits(codelength[LS][i]))*factor[LS][i]-1.0; + } + } + else fraction[LS][0][i]=fraction[LS][1][i]=fraction[LS][2][i]= + fraction[RS][0][i]=fraction[RS][1][i]=fraction[RS][2][i]=0.0; + } + + + + + //Fraction + if(lOutputStereo) + for(i=0;i<n;i++) + { + if(bitalloc[LS][i]) + { + if(!group[LS][i]) + { + fraction[LS][0][i]=(fraction[LS][0][i]+d[LS][i])*c[LS][i]; + fraction[LS][1][i]=(fraction[LS][1][i]+d[LS][i])*c[LS][i]; + fraction[LS][2][i]=(fraction[LS][2][i]+d[LS][i])*c[LS][i]; + } + + register REAL t=scalefactor[LS][l>>2][i]; + fraction[LS][0][i]*=t; + fraction[LS][1][i]*=t; + fraction[LS][2][i]*=t; + } + + if(bitalloc[RS][i]) + { + if(!group[RS][i]) + { + fraction[RS][0][i]=(fraction[RS][0][i]+d[RS][i])*c[LS][i]; + fraction[RS][1][i]=(fraction[RS][1][i]+d[RS][i])*c[LS][i]; + fraction[RS][2][i]=(fraction[RS][2][i]+d[RS][i])*c[LS][i]; + } + + register REAL t=scalefactor[RS][l>>2][i]; + fraction[RS][0][i]*=t; + fraction[RS][1][i]*=t; + fraction[RS][2][i]*=t; + } + } + else + for(i=0;i<n;i++) + if(bitalloc[LS][i]) + { + if(!group[LS][i]) + { + fraction[LS][0][i]=(fraction[LS][0][i]+d[LS][i])*c[LS][i]; + fraction[LS][1][i]=(fraction[LS][1][i]+d[LS][i])*c[LS][i]; + fraction[LS][2][i]=(fraction[LS][2][i]+d[LS][i])*c[LS][i]; + } + + register REAL t=scalefactor[LS][l>>2][i]; + fraction[LS][0][i]*=t; + fraction[LS][1][i]*=t; + fraction[LS][2][i]*=t; + } + + + for(;i<MAXSUBBAND;i++) + fraction[LS][0][i]=fraction[LS][1][i]=fraction[LS][2][i]= + fraction[RS][0][i]=fraction[RS][1][i]=fraction[RS][2][i]=0.0; + + for(i=0;i<3;i++) { + synthesis->doSynth(lDownSample,lOutputStereo, + fraction[LS][i],fraction[RS][i]); + } + + } + } +} diff --git a/mpeglib/lib/splay/mpeglayer3.cpp b/mpeglib/lib/splay/mpeglayer3.cpp new file mode 100644 index 00000000..eeb09697 --- /dev/null +++ b/mpeglib/lib/splay/mpeglayer3.cpp @@ -0,0 +1,1761 @@ +/* MPEG/WAVE Sound library + + (C) 1997 by Jung woo-jae */ + +// Mpeglayer3.cc +// It's for MPEG Layer 3 +// I've made array of superior functions for speed. +// Extend TO_FOUR_THIRDS to negative. +// Bug fix : maplay 1.2+ have wrong TO_FOUR_THIRDS ranges. +// Force to mono!! +// MPEG-2 is implemented +// Speed up in fixstereo (maybe buggy) + + + +#include "mpegsound.h" +#include "huffmanlookup.h" +#include "dump.h" +#include "synthesis.h" + +inline int Mpegtoraw::wgetbit (void) {return bitwindow.getbit (); } +inline int Mpegtoraw::wgetbits9(int bits){return bitwindow.getbits9(bits);} +inline int Mpegtoraw::wgetbits (int bits){return bitwindow.getbits (bits);} +inline int Mpegtoraw::wgetCanReadBits () {return bitwindow.getCanReadBits();} + + +#define MUL3(a) (((a)<<1)+(a)) + +#define REAL0 0 + +// 576 +#define ARRAYSIZE (SBLIMIT*SSLIMIT) +#define REALSIZE (sizeof(REAL)) + + +#define MAPLAY_OPT 1 + + +#ifdef NATIVE_ASSEMBLY +inline void long_memset(void * s,unsigned int c,int count) +{ +__asm__ __volatile__( + "cld\n\t" + "rep ; stosl\n\t" + : /* no output */ + :"a" (c), "c" (count/4), "D" ((long) s) + :"cx","di","memory"); +} +#endif + +#define FOURTHIRDSTABLENUMBER (8250) +static int initializedlayer3=false; + +static REAL two_to_negative_half_pow[70]; +static REAL TO_FOUR_THIRDSTABLE[FOURTHIRDSTABLENUMBER*2]; +static REAL POW2[256]; +static REAL POW2_1[8][2][16]; +static REAL ca[8],cs[8]; + + + + +typedef struct +{ + REAL l,r; +}RATIOS; + +static RATIOS rat_1[16],rat_2[2][64]; + +void Mpegtoraw::layer3initialize(void) +{ + + int i,j,k,l; + + //maplay opt. + nonzero[0] = nonzero[1] = nonzero[2]=ARRAYSIZE; + + layer3framestart=0; + currentprevblock=0; + + for(l=0;l<2;l++) + for(i=0;i<2;i++) + for(j=0;j<SBLIMIT;j++) + for(k=0;k<SSLIMIT;k++) + prevblck[l][i][j][k]=0.0f; + + bitwindow.initialize(); + + if(initializedlayer3) { + return; + } + + + + for(i=0;i<256;i++) { + POW2[i]=(REAL)pow((double)2.0,(0.25* (double) (i-210.0))); + } + REAL *TO_FOUR_THIRDS=TO_FOUR_THIRDSTABLE+FOURTHIRDSTABLENUMBER; + + for(i=1;i<FOURTHIRDSTABLENUMBER;i++) + TO_FOUR_THIRDS[-i]= + -(TO_FOUR_THIRDS[i]=(REAL)pow((double)i,(double)4.0/3.0)); + // now set the zero value for both (otherwise it would be -0.0) + TO_FOUR_THIRDS[0]=(REAL)0; + + + for(i=0;i<8;i++) { + static double Ci[8]= {-0.6,-0.535,-0.33,-0.185, + -0.095,-0.041,-0.0142,-0.0037}; + double sq=sqrt(1.0f+Ci[i]*Ci[i]); + cs[i]=1.0f/sq; + ca[i]=Ci[i]/sq; + } + + initialize_win(); + initialize_dct12_dct36(); + for(i=0;i<70;i++) { + two_to_negative_half_pow[i]=(REAL)pow(2.0,-0.5*(double)i); + } + + + for(i=0;i<8;i++) + for(j=0;j<2;j++) + for(k=0;k<16;k++)POW2_1[i][j][k]=pow(2.0,(-2.0*i)-(0.5*(1.0+j)*k)); + + + /* + + for(i=0;i<8;i++) + for(k=0;k<16;k++) { + for(j=0;j<2;j++) { + REAL base=pow(2.0,-0.25*(j+1.0)); + REAL val=1.0; + + if (k>0) { + if ( k & 1) { + val=pow(base,(k+1.0)*0.5); + } else { + val=pow(base,k*0.5); + } + } + + POW2_MV[i][j][k]=val; + } + } + + for(i=0;i<8;i++) + for(j=0;j<2;j++) + for(k=0;k<16;k++) { + REAL a=POW2_1[i][j][k]; + REAL b=POW2_MV[i][j][k]; + printf("i:%d j%d k%d",i,j,k); + if (a != b) { + cout << "a:"<<a<<" b:"<<b<<endl; + } else { + cout << "same:"<<a<<endl; + } + } + */ + + + for(i=0;i<16;i++) { + double t = tan( (double) i * MY_PI / 12.0 ); + rat_1[i].l=t / (1.0+t); + rat_1[i].r=1.0 /(1.0+t); + } + + +#define IO0 ((double)0.840896415256) +#define IO1 ((double)0.707106781188) + rat_2[0][0].l=rat_2[0][0].r= + rat_2[1][0].l=rat_2[1][0].r=1.; + + for(i=1;i<64;i++) { + if((i%2)==1) { + rat_2[0][i].l=pow(IO0,(i+1)/2); + rat_2[1][i].l=pow(IO1,(i+1)/2); + rat_2[0][i].r= + rat_2[1][i].r=1.; + } + else { + rat_2[0][i].l= + rat_2[1][i].l=1.; + rat_2[0][i].r=pow(IO0,i/2); + rat_2[1][i].r=pow(IO1,i/2); + } + } + + initializedlayer3=true; +} + +bool Mpegtoraw::layer3getsideinfo(void) { + int inputstereo=mpegAudioHeader->getInputstereo(); + + + sideinfo.main_data_begin=getbits(9); + if(!inputstereo)sideinfo.private_bits=getbits(5); + else sideinfo.private_bits=getbits(3); + + sideinfo.ch[LS].scfsi[0]=getbit(); + sideinfo.ch[LS].scfsi[1]=getbit(); + sideinfo.ch[LS].scfsi[2]=getbit(); + sideinfo.ch[LS].scfsi[3]=getbit(); + if(inputstereo) { + sideinfo.ch[RS].scfsi[0]=getbit(); + sideinfo.ch[RS].scfsi[1]=getbit(); + sideinfo.ch[RS].scfsi[2]=getbit(); + sideinfo.ch[RS].scfsi[3]=getbit(); + } + + for(int gr=0,ch;gr<2;gr++) + for(ch=0;;ch++) { + layer3grinfo *gi=&(sideinfo.ch[ch].gr[gr]); + + gi->part2_3_length =getbits(12); + gi->big_values =getbits(9); + if(gi->big_values > 288) { + DEBUG_LAYER(fprintf(stderr,"big_values too large!\n");) + gi->big_values = 288; + return false; + } + + gi->global_gain =getbits(8); + gi->scalefac_compress =getbits(4); + gi->window_switching_flag=getbit(); + if(gi->window_switching_flag) { + gi->block_type =getbits(2); + gi->mixed_block_flag=getbit(); + + gi->table_select[0] =getbits(5); + gi->table_select[1] =getbits(5); + + gi->subblock_gain[0]=getbits(3); + gi->subblock_gain[1]=getbits(3); + gi->subblock_gain[2]=getbits(3); + + /* Set region_count parameters since they are implicit in this case. */ + if(gi->block_type==0) + { + DEBUG_LAYER(printf("Side info bad: block_type==0 split block.\n");) + return false; + } + else if (gi->block_type==2 && gi->mixed_block_flag==0) + gi->region0_count=8; /* MI 9; */ + else gi->region0_count=7; /* MI 8; */ + gi->region1_count=20-(gi->region0_count); + } + else + { + gi->table_select[0] =getbits(5); + gi->table_select[1] =getbits(5); + gi->table_select[2] =getbits(5); + gi->region0_count =getbits(4); + gi->region1_count =getbits(3); + gi->block_type =0; + } + gi->preflag =getbit(); + gi->scalefac_scale =getbit(); + gi->count1table_select=getbit(); + + gi->generalflag=gi->window_switching_flag && (gi->block_type==2); + + if(!inputstereo || ch)break; + } + + return true; +} + +bool Mpegtoraw::layer3getsideinfo_2(void) { + int inputstereo=mpegAudioHeader->getInputstereo(); + sideinfo.main_data_begin=getbits(8); + + if(!inputstereo)sideinfo.private_bits=getbit(); + else sideinfo.private_bits=getbits(2); + + for(int ch=0;;ch++) + { + layer3grinfo *gi=&(sideinfo.ch[ch].gr[0]); + + gi->part2_3_length =getbits(12); + gi->big_values =getbits(9); + if(gi->big_values > 288) { + DEBUG_LAYER(fprintf(stderr,"big_values too large!\n");) + gi->big_values = 288; + return false; + } + + gi->global_gain =getbits(8); + gi->scalefac_compress =getbits(9); + gi->window_switching_flag=getbit(); + if(gi->window_switching_flag) + { + gi->block_type =getbits(2); + gi->mixed_block_flag=getbit(); + + gi->table_select[0] =getbits(5); + gi->table_select[1] =getbits(5); + + gi->subblock_gain[0]=getbits(3); + gi->subblock_gain[1]=getbits(3); + gi->subblock_gain[2]=getbits(3); + + /* Set region_count parameters since they are implicit in this case. */ + if(gi->block_type==0) + { + DEBUG_LAYER(printf("Side info bad: block_type==0 split block.\n");) + return false; + } + else if (gi->block_type==2 && gi->mixed_block_flag==0) + gi->region0_count=8; /* MI 9; */ + else gi->region0_count=7; /* MI 8; */ + gi->region1_count=20-(gi->region0_count); + } + else + { + gi->table_select[0] =getbits(5); + gi->table_select[1] =getbits(5); + gi->table_select[2] =getbits(5); + gi->region0_count =getbits(4); + gi->region1_count =getbits(3); + gi->block_type =0; + } + gi->scalefac_scale =getbit(); + gi->count1table_select=getbit(); + + gi->generalflag=gi->window_switching_flag && (gi->block_type==2); + + if(!inputstereo || ch)break; + } + + return true; +} + +void Mpegtoraw::layer3getscalefactors(int ch,int gr) +{ + static int slen[2][16]={{0, 0, 0, 0, 3, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4}, + {0, 1, 2, 3, 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 2, 3}}; + + layer3grinfo *gi=&(sideinfo.ch[ch].gr[gr]); + register layer3scalefactor *sf=(&scalefactors[ch]); + int l0,l1; + + { + int scale_comp=gi->scalefac_compress; + + l0=slen[0][scale_comp]; + l1=slen[1][scale_comp]; + } + /* + wgetCanReadBits(); + cout << "lo:"<<l0<<" l1:"<<l1<<endl; + */ + if(gi->generalflag) + { + if(gi->mixed_block_flag) + { /* MIXED */ /* NEW-ag 11/25 */ + sf->l[0]=wgetbits9(l0);sf->l[1]=wgetbits9(l0); + sf->l[2]=wgetbits9(l0);sf->l[3]=wgetbits9(l0); + sf->l[4]=wgetbits9(l0);sf->l[5]=wgetbits9(l0); + sf->l[6]=wgetbits9(l0);sf->l[7]=wgetbits9(l0); + + sf->s[0][ 3]=wgetbits9(l0);sf->s[1][ 3]=wgetbits9(l0); + sf->s[2][ 3]=wgetbits9(l0); + sf->s[0][ 4]=wgetbits9(l0);sf->s[1][ 4]=wgetbits9(l0); + sf->s[2][ 4]=wgetbits9(l0); + sf->s[0][ 5]=wgetbits9(l0);sf->s[1][ 5]=wgetbits9(l0); + sf->s[2][ 5]=wgetbits9(l0); + + sf->s[0][ 6]=wgetbits9(l1);sf->s[1][ 6]=wgetbits9(l1); + sf->s[2][ 6]=wgetbits9(l1); + sf->s[0][ 7]=wgetbits9(l1);sf->s[1][ 7]=wgetbits9(l1); + sf->s[2][ 7]=wgetbits9(l1); + sf->s[0][ 8]=wgetbits9(l1);sf->s[1][ 8]=wgetbits9(l1); + sf->s[2][ 8]=wgetbits9(l1); + sf->s[0][ 9]=wgetbits9(l1);sf->s[1][ 9]=wgetbits9(l1); + sf->s[2][ 9]=wgetbits9(l1); + sf->s[0][10]=wgetbits9(l1);sf->s[1][10]=wgetbits9(l1); + sf->s[2][10]=wgetbits9(l1); + sf->s[0][11]=wgetbits9(l1);sf->s[1][11]=wgetbits9(l1); + sf->s[2][11]=wgetbits9(l1); + + sf->s[0][12]=sf->s[1][12]=sf->s[2][12]=0; + } + else + { /* SHORT*/ + sf->s[0][ 0]=wgetbits9(l0);sf->s[1][ 0]=wgetbits9(l0); + sf->s[2][ 0]=wgetbits9(l0); + sf->s[0][ 1]=wgetbits9(l0);sf->s[1][ 1]=wgetbits9(l0); + sf->s[2][ 1]=wgetbits9(l0); + sf->s[0][ 2]=wgetbits9(l0);sf->s[1][ 2]=wgetbits9(l0); + sf->s[2][ 2]=wgetbits9(l0); + sf->s[0][ 3]=wgetbits9(l0);sf->s[1][ 3]=wgetbits9(l0); + sf->s[2][ 3]=wgetbits9(l0); + sf->s[0][ 4]=wgetbits9(l0);sf->s[1][ 4]=wgetbits9(l0); + sf->s[2][ 4]=wgetbits9(l0); + sf->s[0][ 5]=wgetbits9(l0);sf->s[1][ 5]=wgetbits9(l0); + sf->s[2][ 5]=wgetbits9(l0); + + sf->s[0][ 6]=wgetbits9(l1);sf->s[1][ 6]=wgetbits9(l1); + sf->s[2][ 6]=wgetbits9(l1); + sf->s[0][ 7]=wgetbits9(l1);sf->s[1][ 7]=wgetbits9(l1); + sf->s[2][ 7]=wgetbits9(l1); + sf->s[0][ 8]=wgetbits9(l1);sf->s[1][ 8]=wgetbits9(l1); + sf->s[2][ 8]=wgetbits9(l1); + sf->s[0][ 9]=wgetbits9(l1);sf->s[1][ 9]=wgetbits9(l1); + sf->s[2][ 9]=wgetbits9(l1); + sf->s[0][10]=wgetbits9(l1);sf->s[1][10]=wgetbits9(l1); + sf->s[2][10]=wgetbits9(l1); + sf->s[0][11]=wgetbits9(l1);sf->s[1][11]=wgetbits9(l1); + sf->s[2][11]=wgetbits9(l1); + + sf->s[0][12]=sf->s[1][12]=sf->s[2][12]=0; + } + } + else + { /* LONG types 0,1,3 */ + if(gr==0) + { + sf->l[ 0]=wgetbits9(l0);sf->l[ 1]=wgetbits9(l0); + sf->l[ 2]=wgetbits9(l0);sf->l[ 3]=wgetbits9(l0); + sf->l[ 4]=wgetbits9(l0);sf->l[ 5]=wgetbits9(l0); + sf->l[ 6]=wgetbits9(l0);sf->l[ 7]=wgetbits9(l0); + sf->l[ 8]=wgetbits9(l0);sf->l[ 9]=wgetbits9(l0); + sf->l[10]=wgetbits9(l0); + sf->l[11]=wgetbits9(l1);sf->l[12]=wgetbits9(l1); + sf->l[13]=wgetbits9(l1);sf->l[14]=wgetbits9(l1); + sf->l[15]=wgetbits9(l1); + sf->l[16]=wgetbits9(l1);sf->l[17]=wgetbits9(l1); + sf->l[18]=wgetbits9(l1);sf->l[19]=wgetbits9(l1); + sf->l[20]=wgetbits9(l1); + } + else + { + if(sideinfo.ch[ch].scfsi[0]==0) + { + sf->l[ 0]=wgetbits9(l0);sf->l[ 1]=wgetbits9(l0); + sf->l[ 2]=wgetbits9(l0);sf->l[ 3]=wgetbits9(l0); + sf->l[ 4]=wgetbits9(l0);sf->l[ 5]=wgetbits9(l0); + } + if(sideinfo.ch[ch].scfsi[1]==0) + { + sf->l[ 6]=wgetbits9(l0);sf->l[ 7]=wgetbits9(l0); + sf->l[ 8]=wgetbits9(l0);sf->l[ 9]=wgetbits9(l0); + sf->l[10]=wgetbits9(l0); + } + if(sideinfo.ch[ch].scfsi[2]==0) + { + sf->l[11]=wgetbits9(l1);sf->l[12]=wgetbits9(l1); + sf->l[13]=wgetbits9(l1);sf->l[14]=wgetbits9(l1); + sf->l[15]=wgetbits9(l1); + } + if(sideinfo.ch[ch].scfsi[3]==0) + { + sf->l[16]=wgetbits9(l1);sf->l[17]=wgetbits9(l1); + sf->l[18]=wgetbits9(l1);sf->l[19]=wgetbits9(l1); + sf->l[20]=wgetbits9(l1); + } + } + sf->l[21]=sf->l[22]=0; + } + /* + cout << "end parse:"<<endl; + wgetCanReadBits(); + */ +} + +void Mpegtoraw::layer3getscalefactors_2(int ch) +{ + static int sfbblockindex[6][3][4]= + { + {{ 6, 5, 5, 5},{ 9, 9, 9, 9},{ 6, 9, 9, 9}}, + {{ 6, 5, 7, 3},{ 9, 9,12, 6},{ 6, 9,12, 6}}, + {{11,10, 0, 0},{18,18, 0, 0},{15,18, 0, 0}}, + {{ 7, 7, 7, 0},{12,12,12, 0},{ 6,15,12, 0}}, + {{ 6, 6, 6, 3},{12, 9, 9, 6},{ 6,12, 9, 6}}, + {{ 8, 8, 5, 0},{15,12, 9, 0},{ 6,18, 9, 0}} + }; + + int sb[54]; + int extendedmode=mpegAudioHeader->getExtendedmode(); + layer3grinfo *gi=&(sideinfo.ch[ch].gr[0]); + register layer3scalefactor *sf=(&scalefactors[ch]); + + { + int blocktypenumber,sc; + int blocknumber; + int slen[4]; + + if(gi->block_type==2)blocktypenumber=1+gi->mixed_block_flag; + else blocktypenumber=0; + + sc=gi->scalefac_compress; + if(!((extendedmode==1 || extendedmode==3) && (ch==1))) + { + if(sc<400) + { + slen[0]=(sc>>4)/5; + slen[1]=(sc>>4)%5; + slen[2]=(sc%16)>>2; + slen[3]=(sc%4); + gi->preflag=0; + blocknumber=0; + } + else if(sc<500) + { + sc-=400; + slen[0]=(sc>>2)/5; + slen[1]=(sc>>2)%5; + slen[2]=sc%4; + slen[3]=0; + gi->preflag=0; + blocknumber=1; + } + else // if(sc<512) + { + sc-=500; + slen[0]=sc/3; + slen[1]=sc%3; + slen[2]=0; + slen[3]=0; + gi->preflag=1; + blocknumber=2; + } + } + else + { + sc>>=1; + if(sc<180) + { + slen[0]=sc/36; + slen[1]=(sc%36)/6; + slen[2]=(sc%36)%6; + slen[3]=0; + gi->preflag=0; + blocknumber=3; + } + else if(sc<244) + { + sc-=180; + slen[0]=(sc%64)>>4; + slen[1]=(sc%16)>>2; + slen[2]=sc%4; + slen[3]=0; + gi->preflag=0; + blocknumber=4; + } + else // if(sc<255) + { + sc-=244; + slen[0]=sc/3; + slen[1]=sc%3; + slen[2]= + slen[3]=0; + gi->preflag=0; + blocknumber=5; + } + } + + { + int i,j,k,*si; + + si=sfbblockindex[blocknumber][blocktypenumber]; + for(i=0;i<45;i++)sb[i]=0; + + for(k=i=0;i<4;i++) + for(j=0;j<si[i];j++,k++) + if(slen[i]==0)sb[k]=0; + else sb[k]=wgetbits(slen[i]); + } + } + + + { + int sfb,window; + int k=0; + + if(gi->window_switching_flag && (gi->block_type==2)) + { + if(gi->mixed_block_flag) + { + for(sfb=0;sfb<8;sfb++)sf->l[sfb]=sb[k++]; + sfb=3; + } + else sfb=0; + + for(;sfb<12;sfb++) + for(window=0;window<3;window++) + sf->s[window][sfb]=sb[k++]; + + sf->s[0][12]=sf->s[1][12]=sf->s[2][12]=0; + } + else + { + for(sfb=0;sfb<21;sfb++) + sf->l[sfb]=sb[k++]; + sf->l[21]=sf->l[22]=0; + } + } +} + + +typedef unsigned int HUFFBITS; +#define MXOFF 250 + +/* do the huffman-decoding */ +/* note! for counta,countb -the 4 bit value is returned in y, discard x */ +// Huffman decoder for tablename<32 +inline void Mpegtoraw::huffmandecoder_1(const HUFFMANCODETABLE *h,int *x,int *y) +{ + HUFFBITS level=(1<<(sizeof(HUFFBITS)*8-1)); + int point=0; + + /* Lookup in Huffman table. */ + for(;;) + { + if(h->val[point][0]==0) + { /*end of tree*/ + int xx,yy; + + xx=h->val[point][1]>>4; + yy=h->val[point][1]&0xf; + + if(h->linbits) + { + if((h->xlen)==(unsigned)xx)xx+=wgetbits(h->linbits); + if(xx)if(wgetbit())xx=-xx; + if((h->ylen)==(unsigned)yy)yy+=wgetbits(h->linbits); + if(yy)if(wgetbit())yy=-yy; + } + else + { + if(xx)if(wgetbit())xx=-xx; + if(yy)if(wgetbit())yy=-yy; + } + *x=xx;*y=yy; + break; + } + + point+=h->val[point][wgetbit()]; + + level>>=1; + if(!(level || ((unsigned)point<ht->treelen))) + { + register int xx,yy; + + xx=(h->xlen<<1);// set x and y to a medium value as a simple concealment + yy=(h->ylen<<1); + + // h->xlen and h->ylen can't be 1 under tablename 32 + // if(xx) + if(wgetbit())xx=-xx; + // if(yy) + if(wgetbit())yy=-yy; + + *x=xx;*y=yy; + break; + } + } +} + +// Huffman decoder tablenumber>=32 +inline void Mpegtoraw::huffmandecoder_2(const HUFFMANCODETABLE *h, + int *x,int *y,int *v,int *w) +{ + HUFFBITS level=(1<<(sizeof(HUFFBITS)*8-1)); + int point=0; + + /* Lookup in Huffman table. */ + for(;;) + { + if(h->val[point][0]==0) + { /*end of tree*/ + register int t=h->val[point][1]; + + if(t&8)*v=1-(wgetbit()<<1); else *v=0; + if(t&4)*w=1-(wgetbit()<<1); else *w=0; + if(t&2)*x=1-(wgetbit()<<1); else *x=0; + if(t&1)*y=1-(wgetbit()<<1); else *y=0; + break; + } + point+=h->val[point][wgetbit()]; + level>>=1; + if(!(level || ((unsigned)point<ht->treelen))) + { + *v=1-(wgetbit()<<1); + *w=1-(wgetbit()<<1); + *x=1-(wgetbit()<<1); + *y=1-(wgetbit()<<1); + break; + } + } +} + +typedef struct +{ + int l[23]; + int s[14]; +}SFBANDINDEX; + +static SFBANDINDEX sfBandIndextable[3][3]= +{ + // MPEG 1 + {{{0,4,8,12,16,20,24,30,36,44,52,62,74,90,110,134,162,196,238,288,342,418,576}, + {0,4,8,12,16,22,30,40,52,66,84,106,136,192}}, + {{0,4,8,12,16,20,24,30,36,42,50,60,72,88,106,128,156,190,230,276,330,384,576}, + {0,4,8,12,16,22,28,38,50,64,80,100,126,192}}, + {{0,4,8,12,16,20,24,30,36,44,54,66,82,102,126,156,194,240,296,364,448,550,576}, + {0,4,8,12,16,22,30,42,58,78,104,138,180,192}}}, + + // MPEG 2 + {{{0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576}, + {0,4,8,12,18,24,32,42,56,74,100,132,174,192}}, + {{0,6,12,18,24,30,36,44,54,66,80,96,114,136,162,194,232,278,330,394,464,540,576}, + {0,4,8,12,18,26,36,48,62,80,104,136,180,192}}, + {{0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576}, + {0,4,8,12,18,26,36,48,62,80,104,134,174,192}}}, + // MPEG 2.5 + {{{0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576}, + {0,4,8,12,18,26,36,48,62,80,104,134,174,192}}, + {{0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576}, + {0,4,8,12,18,26,36,48,62,80,104,134,174,192}}, + {{0,12,24,36,48,60,72,88,108,132,160,192,232,280,336,400,476,566,568,570,572,574,576}, + {0,8,16,24,36,52,72,96,124,160,162,164,166,192}}} +}; + + +void Mpegtoraw::layer3huffmandecode(int ch,int gr,int out[SBLIMIT][SSLIMIT]) +{ + layer3grinfo *gi=&(sideinfo.ch[ch].gr[gr]); + int part2_3_end=layer3part2start+(gi->part2_3_length); + int region1Start,region2Start; + int i,e=gi->big_values<<1; + int version=mpegAudioHeader->getVersion(); + int frequency=mpegAudioHeader->getFrequency(); + int mpeg25=mpegAudioHeader->getLayer25(); + + /* Find region boundary for short block case. */ + if(gi->generalflag) { + /* Region2. */ + region1Start= + sfBandIndextable[mpeg25?2:version][frequency].s[3]*3; + /* MPEG1:sfb[9/3]*3=36 */ + region2Start=576;/* No Region2 for short block case. */ + } else { + /* Find region boundary for long block case. */ + region1Start= + sfBandIndextable[mpeg25?2:version][frequency].l[gi->region0_count+1]; + region2Start= + sfBandIndextable[mpeg25?2:version][frequency].l[gi->region0_count+ + gi->region1_count+2]; + } + + /* Read bigvalues area. */ + for(i=0;i<e;) + { + const HUFFMANCODETABLE *h; + register int end; + + if (i<region1Start) + { + h=&ht[gi->table_select[0]]; + if(region1Start>e)end=e; else end=region1Start; + } + else if(i<region2Start) + { + h=&ht[gi->table_select[1]]; + if(region2Start>e)end=e; else end=region2Start; + } + else + { + h=&ht[gi->table_select[2]]; + end=e; + } + + if(h->treelen) { + while(i<end) + { + + int skip = HuffmanLookup::decode(h->tablename, bitwindow.peek8(), + &out[0][i], &out[0][i+1]); + + if(skip) + bitwindow.forward(skip); + else + huffmandecoder_1(h,&out[0][i],&out[0][i+1]); + i+=2; + } + } else { + for(;i<end;i+=2) + out[0][i] = + out[0][i+1]=0; + } + } + + /* Read count1 area. */ + const HUFFMANCODETABLE *h=&ht[gi->count1table_select+32]; + while(bitwindow.gettotalbit()<part2_3_end) + { + huffmandecoder_2(h,&out[0][i+2],&out[0][i+3], + &out[0][i ],&out[0][i+1]); + i+=4; + + if(i>=ARRAYSIZE) + { + break; + } + } + + // nonzero is the _size_ of the array with the last nonzero value + if (i < ARRAYSIZE) { + nonzero[ch] = i; + } else { + // catch bugs + nonzero[ch] = ARRAYSIZE; + } + + // debug start +#ifndef MAPLAY_OPT + nonzero[ch]=ARRAYSIZE; + for(;i<ARRAYSIZE;i++)out[0][i]=0; +#endif + // debug end + + bitwindow.rewind(bitwindow.gettotalbit()-part2_3_end); +} + + +static int pretab[22]={0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,2,2,3,3,3,2,0}; + +inline REAL Mpegtoraw::layer3twopow2(int scale,int preflag, + int pretab_offset,int l) +{ + int index=l; + + if(preflag)index+=pretab_offset; + + return(two_to_negative_half_pow[index<<scale]); +} + +inline REAL Mpegtoraw::layer3twopow2_1(int a,int b,int c) +{ + return POW2_1[a][b][c]; +} + + +void Mpegtoraw::layer3dequantizesample(int ch,int gr, + int in[SBLIMIT][SSLIMIT], + REAL out[SBLIMIT][SSLIMIT]) +{ + int version=mpegAudioHeader->getVersion(); + int frequency=mpegAudioHeader->getFrequency(); + int mpeg25=mpegAudioHeader->getLayer25(); + layer3grinfo *gi=&(sideinfo.ch[ch].gr[gr]); + SFBANDINDEX *sfBandIndex=&(sfBandIndextable[mpeg25?2:version][frequency]); + REAL globalgain=POW2[gi->global_gain]; + REAL *TO_FOUR_THIRDS=TO_FOUR_THIRDSTABLE+FOURTHIRDSTABLENUMBER; + int arrayEnd=nonzero[ch]; + /* choose correct scalefactor band per block type, initialize boundary */ + /* and apply formula per block type */ + if(!gi->generalflag) { + /* LONG blocks: 0,1,3 */ + int next_cb_boundary; + int cb=-1,index=0; + REAL factor; + + + do + { + + next_cb_boundary=sfBandIndex->l[(++cb)+1]; + REAL val=layer3twopow2(gi->scalefac_scale,gi->preflag, + pretab[cb],scalefactors[ch].l[cb]); + factor=globalgain*val; + // maplay opt + if (arrayEnd < next_cb_boundary) { + next_cb_boundary=arrayEnd; + } + + for(;index<next_cb_boundary;) + { + out[0][index]=factor*TO_FOUR_THIRDS[in[0][index]];index++; + out[0][index]=factor*TO_FOUR_THIRDS[in[0][index]];index++; + } + + }while(index<arrayEnd); + } else if(!gi->mixed_block_flag) { + int cb=0,index=0; + int cb_width; + do + { + cb_width=(sfBandIndex->s[cb+1]-sfBandIndex->s[cb])>>1; + + for(register int k=0;k<3;k++) + { + register REAL factor; + register int count=cb_width; + // maplay12 opt. + if(index+(count<<1) > arrayEnd) { + if (index >= arrayEnd) break; + count=(arrayEnd-index)>>1; + } + + factor=globalgain* + layer3twopow2_1(gi->subblock_gain[k],gi->scalefac_scale, + scalefactors[ch].s[k][cb]); + + + do{ + out[0][index]=factor*TO_FOUR_THIRDS[in[0][index]];index++; + out[0][index]=factor*TO_FOUR_THIRDS[in[0][index]];index++; + }while(--count); + } + cb++; + }while(index<arrayEnd); + } else { + int cb_begin=0,cb_width=0; + int cb=0; + int next_cb_boundary=sfBandIndex->l[1]; /* LONG blocks: 0,1,3 */ + int index; + // I do not have an mp3 with this format, + // so we restore the "make rest of array zero" + // in this case + // to use the maplay opt here, we must make sure, that + // arrayEnd==ArraySize. + for(int i=arrayEnd;i<ARRAYSIZE;i++)in[0][i]=0; + + /* Compute overall (global) scaling. */ + { + for(int sb=0;sb<SBLIMIT;sb++) + { + int *i=in[sb]; + REAL *o=out[sb]; + + o[ 0]=globalgain*TO_FOUR_THIRDS[i[ 0]]; + o[ 1]=globalgain*TO_FOUR_THIRDS[i[ 1]]; + o[ 2]=globalgain*TO_FOUR_THIRDS[i[ 2]]; + o[ 3]=globalgain*TO_FOUR_THIRDS[i[ 3]]; + o[ 4]=globalgain*TO_FOUR_THIRDS[i[ 4]]; + o[ 5]=globalgain*TO_FOUR_THIRDS[i[ 5]]; + o[ 6]=globalgain*TO_FOUR_THIRDS[i[ 6]]; + o[ 7]=globalgain*TO_FOUR_THIRDS[i[ 7]]; + o[ 8]=globalgain*TO_FOUR_THIRDS[i[ 8]]; + o[ 9]=globalgain*TO_FOUR_THIRDS[i[ 9]]; + o[10]=globalgain*TO_FOUR_THIRDS[i[10]]; + o[11]=globalgain*TO_FOUR_THIRDS[i[11]]; + o[12]=globalgain*TO_FOUR_THIRDS[i[12]]; + o[13]=globalgain*TO_FOUR_THIRDS[i[13]]; + o[14]=globalgain*TO_FOUR_THIRDS[i[14]]; + o[15]=globalgain*TO_FOUR_THIRDS[i[15]]; + o[16]=globalgain*TO_FOUR_THIRDS[i[16]]; + o[17]=globalgain*TO_FOUR_THIRDS[i[17]]; + } + } + for(index=0;index<SSLIMIT*2;index++) + { + if(index==next_cb_boundary) + { + if(index==sfBandIndex->l[8]) + { + next_cb_boundary=sfBandIndex->s[4]; + next_cb_boundary=MUL3(next_cb_boundary); + cb=3; + cb_width=sfBandIndex->s[4]-sfBandIndex->s[3]; + cb_begin=sfBandIndex->s[3]; + cb_begin=MUL3(cb_begin); + } + else if(index<sfBandIndex->l[8]) + next_cb_boundary=sfBandIndex->l[(++cb)+1]; + else + { + next_cb_boundary=sfBandIndex->s[(++cb)+1]; + next_cb_boundary=MUL3(next_cb_boundary); + cb_begin=sfBandIndex->s[cb]; + cb_width=sfBandIndex->s[cb+1]-cb_begin; + cb_begin=MUL3(cb_begin); + } + } + /* LONG block types 0,1,3 & 1st 2 subbands of switched blocks */ + out[0][index]*=layer3twopow2(gi->scalefac_scale,gi->preflag, + pretab[cb],scalefactors[ch].l[cb]); + + } + + for(;index<ARRAYSIZE;index++) { + if(index==next_cb_boundary) { + if(index==sfBandIndex->l[8]) { + next_cb_boundary=sfBandIndex->s[4]; + next_cb_boundary=MUL3(next_cb_boundary); + cb=3; + cb_width=sfBandIndex->s[4]-sfBandIndex->s[3]; + cb_begin=sfBandIndex->s[3]; + cb_begin=(cb_begin<<2)-cb_begin; + } else if(index<sfBandIndex->l[8]) + next_cb_boundary=sfBandIndex->l[(++cb)+1]; + else { + next_cb_boundary=sfBandIndex->s[(++cb)+1]; + next_cb_boundary=MUL3(next_cb_boundary); + cb_begin=sfBandIndex->s[cb]; + cb_width=sfBandIndex->s[cb+1]-cb_begin; + cb_begin=MUL3(cb_begin); + } + } + { + /** + Here we check if we do a division by zero + and if the resulting t_index points + outside the array. (Needed for better robustness + of the mp3 decoder) + */ + unsigned int t_index=0; + if (cb_width) { + t_index=(unsigned int)((index-cb_begin)/cb_width); + if (t_index > 2) { + t_index=0; + } + } + + out[0][index]*=layer3twopow2_1(gi->subblock_gain[t_index], + gi->scalefac_scale, + scalefactors[ch].s[t_index][cb]); + } + } + } + /* + int i; + for(i=arrayEnd;i<ARRAYSIZE;i++) { + out[0][i]=(REAL) 0.0; + } + */ +} +// make the input to nonzero[2] zero +inline void Mpegtoraw::adjustNonZero(REAL in[2][SBLIMIT][SSLIMIT]) { + if ((nonzero[0] == 0) && (nonzero[1]==0)) { + in[RS][0][0]=(REAL) 0.0; + in[LS][0][0]=(REAL) 0.0; + nonzero[0]=1; + nonzero[1]=1; + nonzero[2]=1; + return; + } + + while(nonzero[0] > nonzero[1]) { + in[RS][0][nonzero[1]]=(REAL) 0.0; + nonzero[1]++; + } + while(nonzero[1] > nonzero[0]) { + in[LS][0][nonzero[0]]=(REAL) 0.0; + nonzero[0]++; + } + // now they are the same + // put this into the "max" var. + nonzero[2]=nonzero[1]; + +} + + +inline void Mpegtoraw::layer3fixtostereo(int gr,REAL in[2][SBLIMIT][SSLIMIT]) +{ + int version=mpegAudioHeader->getVersion(); + int frequency=mpegAudioHeader->getFrequency(); + int extendedmode=mpegAudioHeader->getExtendedmode(); + int mode=mpegAudioHeader->getMode(); + int inputstereo=mpegAudioHeader->getInputstereo(); + int mpeg25=mpegAudioHeader->getLayer25(); + layer3grinfo *gi=&(sideinfo.ch[0].gr[gr]); + SFBANDINDEX *sfBandIndex=&(sfBandIndextable[mpeg25?2:version][frequency]); + + int ms_stereo=(mode==_MODE_JOINT) && (extendedmode & 0x2); + int i_stereo =(mode==_MODE_JOINT) && (extendedmode & 0x1); + + + if(!inputstereo) + { /* mono , bypass xr[0][][] to lr[0][][]*/ + // memcpy(out[0][0],in[0][0],ARRAYSIZE*REALSIZE); + for(int i=nonzero[0];i<ARRAYSIZE;i++) { + in[LS][0][i]=(REAL) 0.0; + } + return; + } + // maplay opt. + adjustNonZero(in); + int maxArray=nonzero[2]; + + if(i_stereo) + { + + // not maplay optimised make defaults + int i; + for(i=maxArray;i<ARRAYSIZE;i++) { + in[LS][0][i]=in[RS][0][i]=(REAL) 0.0; + } + + + int is_pos[ARRAYSIZE]; + RATIOS is_ratio[ARRAYSIZE]; + RATIOS *ratios; + if(version)ratios=rat_2[gi->scalefac_compress%2]; + else ratios=rat_1; + + /* initialization */ + for(i=0;i<ARRAYSIZE;i+=2)is_pos[i]=is_pos[i+1]=7; + + if(gi->generalflag) + { + if(gi->mixed_block_flag) // Part I + { + int max_sfb=0; + + for(int j=0;j<3;j++) + { + int sfb,sfbcnt=2; + + for(sfb=12;sfb>=3;sfb--) + { + int lines; + + i=sfBandIndex->s[sfb]; + lines=sfBandIndex->s[sfb+1]-i; + i=MUL3(i)+(j+1)*lines-1; + for(;lines>0;lines--,i--) + if(in[1][0][i]!=0.0f) + { + sfbcnt=sfb; + sfb=0;break; // quit loop + } + } + sfb=sfbcnt+1; + + if(sfb>max_sfb)max_sfb=sfb; + + for(;sfb<12;sfb++) + { + int k,t; + + t=sfBandIndex->s[sfb]; + k=sfBandIndex->s[sfb+1]-t; + i=MUL3(t)+j*k; + + t=scalefactors[1].s[j][sfb]; + if(t!=7) + { + RATIOS r=ratios[t]; + + for(;k>0;k--,i++){ + is_pos[i]=t;is_ratio[i]=r;} + } + else + for(;k>0;k--,i++)is_pos[i]=t; + } + sfb=sfBandIndex->s[10]; + sfb=MUL3(sfb)+j*(sfBandIndex->s[11]-sfb); + + { + int k,t; + + t=sfBandIndex->s[11]; + k=sfBandIndex->s[12]-t; + i=MUL3(t)+j*k; + + t=is_pos[sfb]; + if(t!=7) + { + RATIOS r=is_ratio[sfb]; + + for(;k>0;k--,i++){ + is_pos[i]=t;is_ratio[i]=r;} + } + else + for(;k>0;k--,i++)is_pos[i]=t; + } + } + + if(max_sfb<=3) + { + { + REAL temp; + int k; + + temp=in[1][0][0];in[1][0][0]=1.0; + for(k=3*SSLIMIT-1;in[1][0][k]==0.0;k--); + in[1][0][0]=temp; + for(i=0;sfBandIndex->l[i]<=k;i++); + } + { + int sfb=i; + + i=sfBandIndex->l[i]; + for(;sfb<8;sfb++) + { + int t=scalefactors[1].l[sfb]; + int k=sfBandIndex->l[sfb+1]-sfBandIndex->l[sfb]; + + if(t!=7) + { + RATIOS r=ratios[t]; + + for(;k>0;k--,i++){ + is_pos[i]=t;is_ratio[i]=r;} + } + else for(;k>0;k--,i++)is_pos[i]=t; + } + } + } + } + else // Part II + { + for(int j=0;j<3;j++) + { + int sfbcnt=-1; + int sfb; + for(sfb=12;sfb>=0;sfb--) + { + int lines; + + { + int t; + + t=sfBandIndex->s[sfb]; + lines=sfBandIndex->s[sfb+1]-t; + i=MUL3(t)+(j+1)*lines-1; + } + + for(;lines>0;lines--,i--) + if(in[1][0][i]!=0.0f) + { + sfbcnt=sfb; + sfb=0;break; // quit loop + } + } + + for(sfb=sfbcnt+1;sfb<12;sfb++) + { + int k,t; + + t=sfBandIndex->s[sfb]; + k=sfBandIndex->s[sfb+1]-t; + i=MUL3(t)+j*k; + + t=scalefactors[1].s[j][sfb]; + if(t!=7) + { + RATIOS r=ratios[t]; + + for(;k>0;k--,i++){ + is_pos[i]=t;is_ratio[i]=r;} + } + else for(;k>0;k--,i++)is_pos[i]=t; + } + + { + int t1=sfBandIndex->s[10], + t2=sfBandIndex->s[11]; + int k,tt; + + tt=MUL3(t1)+j*(t2-t1); + k =sfBandIndex->s[12]-t2; + if(is_pos[tt]!=7) + { + RATIOS r=is_ratio[tt]; + int t=is_pos[tt]; + + i =MUL3(t1)+j*k; + for(;k>0;k--,i++){ + is_pos[i]=t;is_ratio[i]=r;} + } + else + for(;k>0;k--,i++)is_pos[i]=7; + } + } + } + } + else // ms-stereo (Part III) + { + { + REAL temp; + int k; + + temp=in[1][0][0];in[1][0][0]=1.0; + for(k=ARRAYSIZE-1;in[1][0][k]==0.0;k--); + in[1][0][0]=temp; + for(i=0;sfBandIndex->l[i]<=k;i++); + } + + { + int sfb; + + sfb=i; + i=sfBandIndex->l[i]; + for(;sfb<21;sfb++) + { + int k,t; + + k=sfBandIndex->l[sfb+1]-sfBandIndex->l[sfb]; + t=scalefactors[1].l[sfb]; + if(t!=7) + { + RATIOS r=ratios[t]; + + for(;k>0;k--,i++){ + is_pos[i]=t;is_ratio[i]=r;} + } + else + for(;k>0;k--,i++)is_pos[i]=t; + } + } + + { + int k,t,tt; + + tt=sfBandIndex->l[20]; + k=576-sfBandIndex->l[21]; + t=is_pos[tt]; + if(t!=7) + { + RATIOS r=is_ratio[tt]; + + for(;k>0;k--,i++){ + is_pos[i]=t;is_ratio[i]=r;} + } + else + for(;k>0;k--,i++)is_pos[i]=t; + } + } + + if(ms_stereo) + { + i=ARRAYSIZE-1; + do{ + if(is_pos[i]==7) + { + register REAL t=in[LS][0][i]; + in[LS][0][i]=(t+in[RS][0][i])*0.7071068f; + in[RS][0][i]=(t-in[RS][0][i])*0.7071068f; + } + else + { + in[RS][0][i]=in[LS][0][i]*is_ratio[i].r; + in[LS][0][i]*=is_ratio[i].l; + } + }while(i--); + } + else + { + i=ARRAYSIZE-1; + do{ + if(is_pos[i]!=7) + { + in[RS][0][i]=in[LS][0][i]*is_ratio[i].r; + in[LS][0][i]*=is_ratio[i].l; + } + }while(i--); + } + } + else + { + + if(ms_stereo) + { + int i=maxArray-1; + do{ + register REAL t=in[LS][0][i]; + + in[LS][0][i]=(t+in[RS][0][i])*0.7071068f; + in[RS][0][i]=(t-in[RS][0][i])*0.7071068f; + }while(i--); + } + for(int i=maxArray;i<ARRAYSIZE;i++) { + in[LS][0][i]=in[RS][0][i]=(REAL) 0.0; + } + + } + + + // channels==2 +} + +inline void layer3reorder_1(int version,int frequency, + REAL in[SBLIMIT][SSLIMIT], + REAL out[SBLIMIT][SSLIMIT]) +{ + SFBANDINDEX *sfBandIndex=&(sfBandIndextable[version][frequency]); + int sfb,sfb_start,sfb_lines; + + /* NO REORDER FOR LOW 2 SUBBANDS */ + out[0][ 0]=in[0][ 0];out[0][ 1]=in[0][ 1];out[0][ 2]=in[0][ 2]; + out[0][ 3]=in[0][ 3];out[0][ 4]=in[0][ 4];out[0][ 5]=in[0][ 5]; + out[0][ 6]=in[0][ 6];out[0][ 7]=in[0][ 7];out[0][ 8]=in[0][ 8]; + out[0][ 9]=in[0][ 9];out[0][10]=in[0][10];out[0][11]=in[0][11]; + out[0][12]=in[0][12];out[0][13]=in[0][13];out[0][14]=in[0][14]; + out[0][15]=in[0][15];out[0][16]=in[0][16];out[0][17]=in[0][17]; + + out[1][ 0]=in[1][ 0];out[1][ 1]=in[1][ 1];out[1][ 2]=in[1][ 2]; + out[1][ 3]=in[1][ 3];out[1][ 4]=in[1][ 4];out[1][ 5]=in[1][ 5]; + out[1][ 6]=in[1][ 6];out[1][ 7]=in[1][ 7];out[1][ 8]=in[1][ 8]; + out[1][ 9]=in[1][ 9];out[1][10]=in[1][10];out[1][11]=in[1][11]; + out[1][12]=in[1][12];out[1][13]=in[1][13];out[1][14]=in[1][14]; + out[1][15]=in[1][15];out[1][16]=in[1][16];out[1][17]=in[1][17]; + + + /* REORDERING FOR REST SWITCHED SHORT */ + for(sfb=3,sfb_start=sfBandIndex->s[3], + sfb_lines=sfBandIndex->s[4]-sfb_start; + sfb<13; + sfb++,sfb_start=sfBandIndex->s[sfb], + (sfb_lines=sfBandIndex->s[sfb+1]-sfb_start)) + { + for(int freq=0;freq<sfb_lines;freq++) + { + int src_line=sfb_start+(sfb_start<<1)+freq; + int des_line=src_line+(freq<<1); + out[0][des_line ]=in[0][src_line ]; + out[0][des_line+1]=in[0][src_line+sfb_lines ]; + out[0][des_line+2]=in[0][src_line+(sfb_lines<<1)]; + } + } +} + +inline void layer3reorder_2(int version,int frequency,REAL in[SBLIMIT][SSLIMIT], + REAL out[SBLIMIT][SSLIMIT]) +{ + SFBANDINDEX *sfBandIndex=&(sfBandIndextable[version][frequency]); + int sfb,sfb_start,sfb_lines; + + for(sfb=0,sfb_start=0,sfb_lines=sfBandIndex->s[1]; + sfb<13; + sfb++,sfb_start=sfBandIndex->s[sfb], + (sfb_lines=sfBandIndex->s[sfb+1]-sfb_start)) + { + for(int freq=0;freq<sfb_lines;freq++) + { + int src_line=sfb_start+(sfb_start<<1)+freq; + int des_line=src_line+(freq<<1); + + out[0][des_line ]=in[0][src_line ]; + out[0][des_line+1]=in[0][src_line+sfb_lines ]; + out[0][des_line+2]=in[0][src_line+(sfb_lines<<1)]; + } + } +} + + +inline void layer3antialias_1(REAL in[SBLIMIT][SSLIMIT]) +{ + for(int ss=0;ss<8;ss++) + { + REAL bu,bd; /* upper and lower butterfly inputs */ + + bu=in[0][17-ss];bd=in[1][ss]; + in[0][17-ss]=(bu*cs[ss])-(bd*ca[ss]); + in[1][ss] =(bd*cs[ss])+(bu*ca[ss]); + } +} + +inline +void layer3antialias_2(REAL in[SBLIMIT][SSLIMIT], + REAL out[SBLIMIT][SSLIMIT]) +{ + out[0][0]=in[0][0];out[0][1]=in[0][1]; + out[0][2]=in[0][2];out[0][3]=in[0][3]; + out[0][4]=in[0][4];out[0][5]=in[0][5]; + out[0][6]=in[0][6];out[0][7]=in[0][7]; + + for(int index=SSLIMIT;index<=(SBLIMIT-1)*SSLIMIT;index+=SSLIMIT) + { + for(int n=0;n<8;n++) + { + REAL bu,bd; + + bu=in[0][index-n-1];bd=in[0][index+n]; + out[0][index-n-1]=(bu*cs[n])-(bd*ca[n]); + out[0][index+n ]=(bd*cs[n])+(bu*ca[n]); + } + out[0][index-SSLIMIT+8]=in[0][index-SSLIMIT+8]; + out[0][index-SSLIMIT+9]=in[0][index-SSLIMIT+9]; + } + + out[31][ 8]=in[31][ 8];out[31][ 9]=in[31][ 9]; + out[31][10]=in[31][10];out[31][11]=in[31][11]; + out[31][12]=in[31][12];out[31][13]=in[31][13]; + out[31][14]=in[31][14];out[31][15]=in[31][15]; + out[31][16]=in[31][16];out[31][17]=in[31][17]; +} + +void Mpegtoraw::layer3reorderandantialias(int ch,int gr, + REAL in[SBLIMIT][SSLIMIT], + REAL out[SBLIMIT][SSLIMIT]) +{ + int version=mpegAudioHeader->getVersion(); + int frequency=mpegAudioHeader->getFrequency(); + int mpeg25=mpegAudioHeader->getLayer25(); + register layer3grinfo *gi=&(sideinfo.ch[ch].gr[gr]); + + if(gi->generalflag) { + if(gi->mixed_block_flag) { + layer3reorder_1 (mpeg25?2:version,frequency,in,out); // Not checked... + layer3antialias_1(out); + } + else { + layer3reorder_2(mpeg25?2:version,frequency,in,out); + } + } + else { + + layer3antialias_2(in,out); + + } +} + + +#include "dct36_12.cpp" +#include "window.cpp" + +void Mpegtoraw::layer3hybrid(int ch,int gr,REAL in[SBLIMIT][SSLIMIT], + REAL out[SSLIMIT][SBLIMIT]) +{ + layer3grinfo *gi=&(sideinfo.ch[ch].gr[gr]); + int bt1,bt2; + REAL *prev1,*prev2; + + prev1=prevblck[ch][currentprevblock][0]; + prev2=prevblck[ch][currentprevblock^1][0]; + + bt1 = gi->mixed_block_flag ? 0 : gi->block_type; + bt2 = gi->block_type; + + { + REAL *ci=(REAL *)in, + *co=(REAL *)out; + int i; + + if(lDownSample)i=(SBLIMIT/2)-2; + else i=SBLIMIT-2; + + + if(bt2==2) + { + if(!bt1) + { + dct36(ci,prev1,prev2,getSplayWindow(0),co); + ci+=SSLIMIT;prev1+=SSLIMIT;prev2+=SSLIMIT;co++; + dct36(ci,prev1,prev2,getSplayWindowINV(0),co); + } + else + { + dct12(ci,prev1,prev2,getSplayWindow(2),co); + ci+=SSLIMIT;prev1+=SSLIMIT;prev2+=SSLIMIT;co++; + dct12(ci,prev1,prev2,getSplayWindowINV(2),co); + } + + do{ + ci+=SSLIMIT;prev1+=SSLIMIT;prev2+=SSLIMIT;co++; + dct12(ci,prev1,prev2,getSplayWindow(2),co); + i--; + ci+=SSLIMIT;prev1+=SSLIMIT;prev2+=SSLIMIT;co++; + dct12(ci,prev1,prev2,getSplayWindowINV(2),co); + }while(--i); + } + else + { + dct36(ci,prev1,prev2,getSplayWindow(bt1),co); + ci+=SSLIMIT;prev1+=SSLIMIT;prev2+=SSLIMIT;co++; + dct36(ci,prev1,prev2,getSplayWindowINV(bt1),co); + + do + { + ci+=SSLIMIT;prev1+=SSLIMIT;prev2+=SSLIMIT;co++; + dct36(ci,prev1,prev2,getSplayWindow(bt2),co); + i--; + ci+=SSLIMIT;prev1+=SSLIMIT;prev2+=SSLIMIT;co++; + dct36(ci,prev1,prev2,getSplayWindowINV(bt2),co); + }while(--i); + } + } +} + +void Mpegtoraw::extractlayer3(void) { + int version=mpegAudioHeader->getVersion(); + int inputstereo=mpegAudioHeader->getInputstereo(); + int layer3slots=mpegAudioHeader->getLayer3slots(); + + if(version) { + extractlayer3_2(); + return; + } + + { + int main_data_end,flush_main; + int bytes_to_discard; + if (layer3getsideinfo() == false) { + return; + } + // read main data. + if(issync()) { + for(register int i=layer3slots;i>0;i--) { + bitwindow.putbyte(getbyte()); + } + } else { + // read main data. + for(register int i=layer3slots;i>0;i--) { + bitwindow.putbyte(getbits8()); + } + } + + main_data_end=bitwindow.gettotalbit()>>3;// of previous frame + if (main_data_end < 0) { + DEBUG_LAYER(printf("main_data_end < 0\n");) + return; + } + + if((flush_main=(bitwindow.gettotalbit() & 0x7))) { + bitwindow.forward(8-flush_main); + main_data_end++; + } + + bytes_to_discard=layer3framestart-(main_data_end+sideinfo.main_data_begin); + if(main_data_end>WINDOWSIZE) { + layer3framestart-=WINDOWSIZE; + bitwindow.rewind(WINDOWSIZE*8); + } + layer3framestart+=layer3slots; + bitwindow.wrap(); + if(bytes_to_discard<0) return; + bitwindow.forward(bytes_to_discard<<3); + } + for(int gr=0;gr<2;gr++) { + ATTR_ALIGN(64) union + { + int is [SBLIMIT][SSLIMIT]; + REAL hin [2][SBLIMIT][SSLIMIT]; + }b1; + ATTR_ALIGN(64) union + { + REAL ro [2][SBLIMIT][SSLIMIT]; + REAL lr [2][SBLIMIT][SSLIMIT]; + REAL hout [2][SSLIMIT][SBLIMIT]; + }b2; + + layer3part2start=bitwindow.gettotalbit(); + layer3getscalefactors (LS,gr); + + layer3huffmandecode (LS,gr ,b1.is); + layer3dequantizesample(LS,gr,b1.is,b2.ro[LS]); + //dump->dump(b2.ro[LS]); + + if(inputstereo) { + layer3part2start=bitwindow.gettotalbit(); + layer3getscalefactors (RS,gr); + layer3huffmandecode (RS,gr ,b1.is); + layer3dequantizesample(RS,gr,b1.is,b2.ro[RS]); + } + layer3fixtostereo(gr,b2.ro); // b2.ro -> b2.lr + currentprevblock^=1; + + + layer3reorderandantialias(LS,gr,b2.lr[LS],b1.hin[LS]); + //dump->dump(b1.hin[LS]); + layer3hybrid (LS,gr,b1.hin[LS],b2.hout[LS]); + //dump->dump(b2.hout[LS]); + + + + + if(lOutputStereo) { + layer3reorderandantialias(RS,gr,b2.lr[RS],b1.hin[RS]); + layer3hybrid (RS,gr,b1.hin[RS],b2.hout[RS]); + + } + synthesis->doMP3Synth(lDownSample,lOutputStereo,b2.hout); + } +} + +void Mpegtoraw::extractlayer3_2(void) { + int inputstereo=mpegAudioHeader->getInputstereo(); + int layer3slots=mpegAudioHeader->getLayer3slots(); + + { + int main_data_end,flush_main; + int bytes_to_discard; + if (layer3getsideinfo_2() == false) { + return; + } + // read main data. + if(issync()) { + for(register int i=layer3slots;i>0;i--) { + bitwindow.putbyte(getbyte()); + } + } + else { + // read main data. + for(register int i=layer3slots;i>0;i--) { + bitwindow.putbyte(getbits8()); + } + } + + //bitwindow.wrap(); + + main_data_end=bitwindow.gettotalbit()>>3;// of previous frame + if (main_data_end < 0) { + DEBUG_LAYER(printf("main_data_end < 0\n");) + return; + } + + if((flush_main=(bitwindow.gettotalbit() & 0x7))) { + bitwindow.forward(8-flush_main); + main_data_end++; + } + + bytes_to_discard=layer3framestart-(main_data_end+sideinfo.main_data_begin); + if(main_data_end>WINDOWSIZE) { + layer3framestart-=WINDOWSIZE; + bitwindow.rewind(WINDOWSIZE*8); + } + layer3framestart+=layer3slots; + + bitwindow.wrap(); + if(bytes_to_discard<0)return; + bitwindow.forward(bytes_to_discard<<3); + } + + //for(int gr=0;gr<2;gr++) { + ATTR_ALIGN(64) union + { + int is [SBLIMIT][SSLIMIT]; + REAL hin [2][SBLIMIT][SSLIMIT]; + }b1; + ATTR_ALIGN(64) union + { + REAL ro [2][SBLIMIT][SSLIMIT]; + REAL lr [2][SBLIMIT][SSLIMIT]; + REAL hout [2][SSLIMIT][SBLIMIT]; + }b2; + + + layer3part2start=bitwindow.gettotalbit(); + layer3getscalefactors_2(LS); + //dump->dump(&scalefactors[LS]); + + layer3huffmandecode (LS,0 ,b1.is); + //dump->dump(b1.is); + layer3dequantizesample (LS,0,b1.is,b2.ro[LS]); + + if(inputstereo) { + layer3part2start=bitwindow.gettotalbit(); + layer3getscalefactors_2(RS); + layer3huffmandecode (RS,0 ,b1.is); + layer3dequantizesample (RS,0,b1.is,b2.ro[RS]); + } + + layer3fixtostereo(0,b2.ro); // b2.ro -> b2.lr + currentprevblock^=1; + + layer3reorderandantialias(LS,0,b2.lr[LS],b1.hin[LS]); + layer3hybrid (LS,0,b1.hin[LS],b2.hout[LS]); + if(lOutputStereo) { + layer3reorderandantialias(RS,0,b2.lr[RS],b1.hin[RS]); + layer3hybrid (RS,0,b1.hin[RS],b2.hout[RS]); + } + synthesis->doMP3Synth(lDownSample,lOutputStereo,b2.hout); + + +} diff --git a/mpeglib/lib/splay/mpegsound.h b/mpeglib/lib/splay/mpegsound.h new file mode 100644 index 00000000..cd0c3571 --- /dev/null +++ b/mpeglib/lib/splay/mpegsound.h @@ -0,0 +1,248 @@ +// MPEG/WAVE Sound library + +// (C) 1997 by Woo-jae Jung + +// Mpegsound.h +// This is typeset for functions in MPEG/WAVE Sound library. +// Now, it's for only linux-pc-?86 + +/************************************/ +/* Include default library packages */ +/************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + + + +#include "mpegAudioStream.h" +#include "common.h" + +class Synthesis; +class AudioFrame; + + +#ifndef _L__SOUND__ +#define _L__SOUND__ + +#include "mpegAudioHeader.h" +#include "mpegAudioBitWindow.h" + + +//#define DEBUG_LAYER(x) x +#define DEBUG_LAYER(x) + + +/**************************/ +/* Define values for MPEG */ +/**************************/ +#define SCALEBLOCK 12 +#define MAXSUBBAND 32 +#define MAXCHANNEL 2 +#define RAWDATASIZE (2*2*2*32*SSLIMIT) + + + +// Huffmancode +#define HTN 34 + + + +#define MODE_MONO 0 +#define MODE_STEREO 1 + +/********************/ +/* Type definitions */ +/********************/ + +typedef struct { + bool generalflag; + unsigned int part2_3_length; + unsigned int big_values; + unsigned int global_gain; + unsigned int scalefac_compress; + unsigned int window_switching_flag; + unsigned int block_type; + unsigned int mixed_block_flag; + unsigned int table_select[3]; + unsigned int subblock_gain[3]; + unsigned int region0_count; + unsigned int region1_count; + unsigned int preflag; + unsigned int scalefac_scale; + unsigned int count1table_select; +}layer3grinfo; + +typedef struct { + unsigned main_data_begin; + unsigned private_bits; + struct { + unsigned scfsi[4]; + layer3grinfo gr[2]; + }ch[2]; +}layer3sideinfo; + +typedef struct { + int l[23]; /* [cb] */ + int s[3][13]; /* [window][cb] */ +}layer3scalefactor; /* [ch] */ + +typedef struct { + int tablename; + unsigned int xlen,ylen; + unsigned int linbits; + unsigned int treelen; + const unsigned int (*val)[2]; +}HUFFMANCODETABLE; + + + + + + + +class DCT; +class Dump; + +// Class for converting mpeg format to raw format +class Mpegtoraw { + /*****************************/ + /* Constant tables for layer */ + /*****************************/ +private: + static const int bitrate[2][3][15]; + static const int frequencies[2][3]; + static const REAL scalefactorstable[64]; + static const ATTR_ALIGN(64) HUFFMANCODETABLE ht[HTN]; + + + friend class HuffmanLookup; + + /*************************/ + /* MPEG header variables */ + /*************************/ + + // comes from constructor, decoder works on them + MpegAudioStream* mpegAudioStream; + MpegAudioHeader* mpegAudioHeader; + AudioFrame* audioFrame; + Dump* dump; + Synthesis* synthesis; + + /***************************************/ + /* Interface for setting music quality */ + /***************************************/ + + int lWantStereo; + int lOutputStereo; + int lDownSample; + +public: + Mpegtoraw(MpegAudioStream* mpegAudioStream, + MpegAudioHeader* mpegAudioHeader); + + + ~Mpegtoraw(); + int decode(AudioFrame* audioFrame); + + + void setStereo(int lStereo); + int getStereo(); + + void setDownSample(int lDownSample); + int getDownSample(); + + + +private: + void initialize(); + + + + /*****************************/ + /* Loading MPEG-Audio stream */ + /*****************************/ + + union + { + unsigned char store[4]; + unsigned int current; + }u; + + + int getbyte() { return mpegAudioStream->getbyte(); } + int getbits(int bits) { return mpegAudioStream->getbits(bits); } + int getbits9(int bits) { return mpegAudioStream->getbits9(bits); } + int getbits8() { return mpegAudioStream->getbits8(); } + int getbit() { return mpegAudioStream->getbit(); } + + + void sync() { mpegAudioStream->sync(); } + bool issync() { return mpegAudioStream->issync(); } + + + /********************/ + /* Global variables */ + /********************/ + + // optimisation from maplay12+ + // 0/1: nonzero for channel 0/1 2: max position for both + int nonzero[3]; + + // for Layer3 + + int layer3framestart; + int layer3part2start; + + ATTR_ALIGN(64) REAL prevblck[2][2][SBLIMIT][SSLIMIT]; + int currentprevblock; + ATTR_ALIGN(64) layer3sideinfo sideinfo; + ATTR_ALIGN(64) layer3scalefactor scalefactors[2]; + + ATTR_ALIGN(64) MpegAudioBitWindow bitwindow; + MpegAudioBitWindow lastValidBitwindow; + + int wgetbit(void); + int wgetbits9(int bits); + int wgetbits(int bits); + int wgetCanReadBits(); + + /*************************************/ + /* Decoding functions for each layer */ + /*************************************/ + + // Extractor + void extractlayer1(void); // MPEG-1 + void extractlayer2(void); + void extractlayer3(void); + void extractlayer3_2(void); // MPEG-2 + + + // Functions for layer 3 + void layer3initialize(void); + bool layer3getsideinfo(void); + bool layer3getsideinfo_2(void); + void layer3getscalefactors(int ch,int gr); + void layer3getscalefactors_2(int ch); + void layer3huffmandecode(int ch,int gr,int out[SBLIMIT][SSLIMIT]); + REAL layer3twopow2(int scale,int preflag,int pretab_offset,int l); + REAL layer3twopow2_1(int a,int b,int c); + void layer3dequantizesample(int ch,int gr,int in[SBLIMIT][SSLIMIT], + REAL out[SBLIMIT][SSLIMIT]); + void adjustNonZero(REAL in[2][SBLIMIT][SSLIMIT]); + void layer3fixtostereo(int gr,REAL in[2][SBLIMIT][SSLIMIT]); + void layer3reorderandantialias(int ch,int gr,REAL in[SBLIMIT][SSLIMIT], + REAL out[SBLIMIT][SSLIMIT]); + + void layer3hybrid(int ch,int gr,REAL in[SBLIMIT][SSLIMIT], + REAL out[SSLIMIT][SBLIMIT]); + + void huffmandecoder_1(const HUFFMANCODETABLE *h,int *x,int *y); + void huffmandecoder_2(const HUFFMANCODETABLE *h,int *x,int *y,int *v,int *w); + +}; + + + +#endif diff --git a/mpeglib/lib/splay/mpegtable.cpp b/mpeglib/lib/splay/mpegtable.cpp new file mode 100644 index 00000000..be539ddd --- /dev/null +++ b/mpeglib/lib/splay/mpegtable.cpp @@ -0,0 +1,35 @@ +/* MPEG/WAVE Sound library + + (C) 1997 by Jung woo-jae */ + +// Mpegtable.cc +// It has tables for MPEG layer 1, 2 and a part of layer 3 + + +#include "mpegsound.h" + + + +// Mpeg general table +const REAL Mpegtoraw::scalefactorstable[64] = +{ + 2.00000000000000, 1.58740105196820, 1.25992104989487, 1.00000000000000, + 0.79370052598410, 0.62996052494744, 0.50000000000000, 0.39685026299205, + 0.31498026247372, 0.25000000000000, 0.19842513149602, 0.15749013123686, + 0.12500000000000, 0.09921256574801, 0.07874506561843, 0.06250000000000, + 0.04960628287401, 0.03937253280921, 0.03125000000000, 0.02480314143700, + 0.01968626640461, 0.01562500000000, 0.01240157071850, 0.00984313320230, + 0.00781250000000, 0.00620078535925, 0.00492156660115, 0.00390625000000, + 0.00310039267963, 0.00246078330058, 0.00195312500000, 0.00155019633981, + 0.00123039165029, 0.00097656250000, 0.00077509816991, 0.00061519582514, + 0.00048828125000, 0.00038754908495, 0.00030759791257, 0.00024414062500, + 0.00019377454248, 0.00015379895629, 0.00012207031250, 0.00009688727124, + 0.00007689947814, 0.00006103515625, 0.00004844363562, 0.00003844973907, + 0.00003051757813, 0.00002422181781, 0.00001922486954, 0.00001525878906, + 0.00001211090890, 0.00000961243477, 0.00000762939453, 0.00000605545445, + 0.00000480621738, 0.00000381469727, 0.00000302772723, 0.00000240310869, + 0.00000190734863, 0.00000151386361, 0.00000120155435, 0.00000000000000 +}; + + + diff --git a/mpeglib/lib/splay/mpegtoraw.cpp b/mpeglib/lib/splay/mpegtoraw.cpp new file mode 100644 index 00000000..93143bbe --- /dev/null +++ b/mpeglib/lib/splay/mpegtoraw.cpp @@ -0,0 +1,127 @@ +/* MPEG/WAVE Sound library + + (C) 1997 by Jung woo-jae */ + +// Mpegtoraw.cc +// Server which get mpeg format and put raw format. + + +#include "mpegsound.h" +#include "synthesis.h" +#include "dump.h" +#include "../frame/audioFrame.h" + +#include <iostream> + +using namespace std; + +Mpegtoraw::Mpegtoraw(MpegAudioStream* mpegAudioStream, + MpegAudioHeader* mpegAudioHeader) { + + this->mpegAudioStream=mpegAudioStream; + this->mpegAudioHeader=mpegAudioHeader; + + this->lOutputStereo=true; + setStereo(true); + setDownSample(false); + + dump=new Dump(); + synthesis=new Synthesis(); + initialize(); + +} + +Mpegtoraw::~Mpegtoraw() { + + delete synthesis; + delete dump; +} + + + + + + + +void Mpegtoraw::setStereo(int flag) { + lWantStereo=flag; +} + +void Mpegtoraw::setDownSample(int flag) { + lDownSample=flag; +} + +int Mpegtoraw::getStereo() { + return lWantStereo; +} + +int Mpegtoraw::getDownSample() { + return lDownSample; +} + + + + + + + +// Convert mpeg to raw +// Mpeg headder class +void Mpegtoraw::initialize() { + + + + layer3initialize(); + + +} + + + + + +// Convert mpeg to raw +int Mpegtoraw::decode(AudioFrame* audioFrame) { + int back=true; + + this->audioFrame=audioFrame; + if (audioFrame->getSize() < RAWDATASIZE) { + cout << "audioFrame needs at least:"<<RAWDATASIZE<<" size"<<endl; + exit(0); + } + + audioFrame->clearrawdata(); + synthesis->clearrawdata(); + + int layer=mpegAudioHeader->getLayer(); + this->lOutputStereo=lWantStereo & mpegAudioHeader->getInputstereo(); + + if (mpegAudioHeader->getProtection()==false) { + mpegAudioStream->getbyte(); + mpegAudioStream->getbyte(); + } + switch(layer) { + case 3: + extractlayer3(); + break; + case 2: + extractlayer2(); + break; + case 1: + extractlayer1(); + break; + default: + cout << "unknown layer:"<<layer<<endl; + back=false; + } + + // + // Now put the frequencies/output etc.. in the frame + // + audioFrame->setFrameFormat(lOutputStereo, + mpegAudioHeader->getFrequencyHz()>>lDownSample); + + audioFrame->putFloatData(synthesis->getOutputData(),synthesis->getLen()); + return back; + +} diff --git a/mpeglib/lib/splay/op.h b/mpeglib/lib/splay/op.h new file mode 100644 index 00000000..a741e97b --- /dev/null +++ b/mpeglib/lib/splay/op.h @@ -0,0 +1,96 @@ +/* + unrolled operations, for better Pentium FPU scheduling + Copyright (C) 2001 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 __OP_H +#define __OP_H + +/** + The Pentium has two pipelined FPUs which makes it possible + to do two operations in one cycle. + (If you are lucky) + +*/ + +#define PTR_DIST (1024) + +#define OS r1=vp1[0] * dp[0]; \ + r2=vp1[PTR_DIST-0] * dp[0]; \ + dp++; + +#define XX1 vp1+=15;dp++; + +#define XX2 r1+=vp1[0] * dp[-1]; \ + r2+=vp1[PTR_DIST-0] * dp[-1]; + +#define OP_END(val) vp1-=val;dp+=val; + +#define OP_END_1(vVal,dVal) vp1+=(vVal-dVal),dp+=dVal + + +// this is OP_END(x);XX1; together: +#define OP_END_2(vVal) vp1+=(15-vVal),dp+=vVal+1 + + +// check this to test pipelining + +#define SCHEDULE1(op,r1,r2) r1;op;r2; +#define SCHEDULE2(op,r1,r2) op;r1;r2; + +#define SCHEDULE(a,b,c) SCHEDULE2(a,b,c); + + +#define OP r1+=vp1[-1] * dp[0]; \ + r2+=vp1[PTR_DIST-1] * dp[0]; + + + +#define OP2 SCHEDULE(OP ,r1+=vp1[-2] * dp[1] ,r2+=vp1[PTR_DIST-2] *dp[1]); +#define OP3 SCHEDULE(OP2 ,r1+=vp1[-3] * dp[2] ,r2+=vp1[PTR_DIST-3] *dp[2]); +#define OP4 SCHEDULE(OP3 ,r1+=vp1[-4] * dp[3] ,r2+=vp1[PTR_DIST-4] *dp[3]); +#define OP5 SCHEDULE(OP4 ,r1+=vp1[-5] * dp[4] ,r2+=vp1[PTR_DIST-5] *dp[4]); +#define OP6 SCHEDULE(OP5 ,r1+=vp1[-6] * dp[5] ,r2+=vp1[PTR_DIST-6] *dp[5]); +#define OP7 SCHEDULE(OP6 ,r1+=vp1[-7] * dp[6] ,r2+=vp1[PTR_DIST-7] *dp[6]); +#define OP8 SCHEDULE(OP7 ,r1+=vp1[-8] * dp[7] ,r2+=vp1[PTR_DIST-8] *dp[7]); +#define OP9 SCHEDULE(OP8 ,r1+=vp1[-9] * dp[8] ,r2+=vp1[PTR_DIST-9] *dp[8]); +#define OP10 SCHEDULE(OP9 ,r1+=vp1[-10] * dp[9] ,r2+=vp1[PTR_DIST-10] *dp[9]); +#define OP11 SCHEDULE(OP10,r1+=vp1[-11] * dp[10],r2+=vp1[PTR_DIST-11] *dp[10]); +#define OP12 SCHEDULE(OP11,r1+=vp1[-12] * dp[11],r2+=vp1[PTR_DIST-12] *dp[11]); +#define OP13 SCHEDULE(OP12,r1+=vp1[-13] * dp[12],r2+=vp1[PTR_DIST-13] *dp[12]); +#define OP14 SCHEDULE(OP13,r1+=vp1[-14] * dp[13],r2+=vp1[PTR_DIST-14] *dp[13]); +#define OP15 SCHEDULE(OP14,r1+=vp1[-15] * dp[14],r2+=vp1[PTR_DIST-15] *dp[14]); + + +/* +#define OP r1+=vp1[-1] * dp[0]; \ + r2+=vp2[-1] * dp[0]; + + + +#define OP2 SCHEDULE(OP ,r1+=vp1[-2] * dp[1] ,r2+=vp2[-2] * dp[1]); +#define OP3 SCHEDULE(OP2 ,r1+=vp1[-3] * dp[2] ,r2+=vp2[-3] * dp[2]); +#define OP4 SCHEDULE(OP3 ,r1+=vp1[-4] * dp[3] ,r2+=vp2[-4] * dp[3]); +#define OP5 SCHEDULE(OP4 ,r1+=vp1[-5] * dp[4] ,r2+=vp2[-5] * dp[4]); +#define OP6 SCHEDULE(OP5 ,r1+=vp1[-6] * dp[5] ,r2+=vp2[-6] * dp[5]); +#define OP7 SCHEDULE(OP6 ,r1+=vp1[-7] * dp[6] ,r2+=vp2[-7] * dp[6]); +#define OP8 SCHEDULE(OP7 ,r1+=vp1[-8] * dp[7] ,r2+=vp2[-8] * dp[7]); +#define OP9 SCHEDULE(OP8 ,r1+=vp1[-9] * dp[8] ,r2+=vp2[-9] * dp[8]); +#define OP10 SCHEDULE(OP9 ,r1+=vp1[-10] * dp[9] ,r2+=vp2[-10] * dp[9]); +#define OP11 SCHEDULE(OP10,r1+=vp1[-11] * dp[10],r2+=vp2[-11] * dp[10]); +#define OP12 SCHEDULE(OP11,r1+=vp1[-12] * dp[11],r2+=vp2[-12] * dp[11]); +#define OP13 SCHEDULE(OP12,r1+=vp1[-13] * dp[12],r2+=vp2[-13] * dp[12]); +#define OP14 SCHEDULE(OP13,r1+=vp1[-14] * dp[13],r2+=vp2[-14] * dp[13]); +#define OP15 SCHEDULE(OP14,r1+=vp1[-15] * dp[14],r2+=vp2[-15] * dp[14]); +*/ + +#endif diff --git a/mpeglib/lib/splay/sigsev.c b/mpeglib/lib/splay/sigsev.c new file mode 100644 index 00000000..906d8cb9 --- /dev/null +++ b/mpeglib/lib/splay/sigsev.c @@ -0,0 +1,29 @@ +/* + No SegFault: + + g++ -o sigsev.exe sigsevTest.cpp + + SegFault: + + g++ -o sigsev.exe -O6 sigsevTest.cpp + */ + +#include <stdio.h> +#undef __NO_MATH_INLINES // <<<< Add this line +#define __NO_MATH_INLINES 1 // <<<< and this. +#include <math.h> + + +int main() { + printf("hello Martin test->main\n"); + + //pow(6.0,3.0); + float value; + value=cos(double(0)); + printf("Wert: %f\n",value); + pow(6.0,3.0); + + printf("hi:\n"); + exit(0); +} + diff --git a/mpeglib/lib/splay/splayDecoder.cpp b/mpeglib/lib/splay/splayDecoder.cpp new file mode 100644 index 00000000..13d6de1b --- /dev/null +++ b/mpeglib/lib/splay/splayDecoder.cpp @@ -0,0 +1,73 @@ +/* + decoder interface for the splay mp3 decoder. + Copyright (C) 2001 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 + + */ + +#define _FROM_SOURCE +#include "dxHead.h" +#include "splayDecoder.h" +#include "mpegsound.h" + + + +SplayDecoder::SplayDecoder() { + header = new MpegAudioHeader(); + stream = new MpegAudioStream(); + server = new Mpegtoraw(stream,header); + + xHeadData=new XHEADDATA(); + xHeadData->toc=new unsigned char[101]; + dump=new Dump(); +} + + +SplayDecoder::~SplayDecoder() { + delete [] xHeadData->toc; + delete xHeadData; + + delete server; + delete header; + delete stream; + delete dump; +} + + + +int SplayDecoder::decode(unsigned char* ptr, int len,AudioFrame* dest) { + int back; + // fist setup the stream and the 4 bytes header info; + //dump->dump((char*)ptr,len); + if (header->parseHeader(ptr) == false) { + return false; + } + // maybe a Xing Header? + if (len >= 152+4) { + int lXing=GetXingHeader(xHeadData,(unsigned char*)ptr); + if (lXing) { + return false; + } + } + stream->setFrame(ptr+4,len-4); + back=server->decode(dest); + + return back; + +} + + +void SplayDecoder::config(const char* key,const char* val,void* ) { + if (strcmp(key,"2")==0) { + server->setDownSample(atoi(val)); + } + if (strcmp(key,"m")==0) { + server->setStereo(atoi(val)); + } +} + diff --git a/mpeglib/lib/splay/splayDecoder.h b/mpeglib/lib/splay/splayDecoder.h new file mode 100644 index 00000000..acbfdbfc --- /dev/null +++ b/mpeglib/lib/splay/splayDecoder.h @@ -0,0 +1,70 @@ +/* + decoder interface for the splay mp3 decoder. + Copyright (C) 2001 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 __SPLAYDECODER_H +#define __SPLAYDECODER_H + +// state definitions for splay decoder + +#define _SPLAY_RESET 0 +#define _SPLAY_EOF 1 +#define _SPLAY_FIRSTINIT 2 +#define _SPLAY_REINIT 3 +#define _SPLAY_DECODE 4 +#define _SPLAY_FRAME 5 + + +#include "../frame/audioFrame.h" +#include "dump.h" +#include <string.h> +#include <kdemacros.h> + +class Mpegtoraw; +class MpegAudioStream; +class MpegAudioHeader; + + +/** + The decoder interface. + The decoder expects an mpeg audio frame. + The call to decode is "atomic", after that you have + a PCMFrame to play. + +*/ + + + +class KDE_EXPORT SplayDecoder { + + MpegAudioStream* stream; + MpegAudioHeader* header; + Mpegtoraw* server; + Dump* dump; +#ifdef _FROM_SOURCE + XHEADDATA* xHeadData; +#else + void* xHeadData; +#endif + + + public: + SplayDecoder(); + ~SplayDecoder(); + + int decode(unsigned char* ptr, int len,AudioFrame* dest); + void config(const char* key,const char* val,void* ret); + +}; +#endif diff --git a/mpeglib/lib/splay/synth_Down.cpp b/mpeglib/lib/splay/synth_Down.cpp new file mode 100644 index 00000000..fbe3887b --- /dev/null +++ b/mpeglib/lib/splay/synth_Down.cpp @@ -0,0 +1,231 @@ +/* + downsample implementation + Copyright (C) 2001 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 "synthesis.h" +#include "dct64_down.cpp" + +#include <iostream> + +using namespace std; + + +void Synthesis::computebuffer_Down(REAL *fraction, + REAL buffer[2][CALCBUFFERSIZE]){ + REAL *out1,*out2; + + out1=buffer[currentcalcbuffer]+calcbufferoffset; + out2=buffer[currentcalcbuffer^1]+calcbufferoffset; + dct64_downsample(out1,out2,fraction); +} + + + +#define SAVE putraw(r); \ + dp+=16;vp+=15+(15-14) +#define OS r=*vp * *dp++ +#define XX vp+=15;r+=*vp * *dp++ +#define OP r+=*--vp * *dp++ + +inline void Synthesis::generatesingle_Down(void) +{ + int i; + register REAL r, *vp; + register const REAL *dp; + + i=32/2; + dp=filter; + vp=calcbuffer[LS][currentcalcbuffer]+calcbufferoffset; +// actual_v+actual_write_pos; + + switch (calcbufferoffset) + { + case 0:for(;i;i--,vp+=15){ + OS;XX;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 1:for(;i;i--,vp+=15){ + OS;OP;XX;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 2:for(;i;i--,vp+=15){ + OS;OP;OP;XX;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 3:for(;i;i--,vp+=15){ + OS;OP;OP;OP;XX;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 4:for(;i;i--,vp+=15){ + OS;OP;OP;OP;OP;XX;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 5:for(;i;i--,vp+=15){ + OS;OP;OP;OP;OP;OP;XX;OP;OP;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 6:for(;i;i--,vp+=15){ + OS;OP;OP;OP;OP;OP;OP;XX;OP;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 7:for(;i;i--,vp+=15){ + OS;OP;OP;OP;OP;OP;OP;OP;XX;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 8:for(;i;i--,vp+=15){ + OS;OP;OP;OP;OP;OP;OP;OP;OP;XX;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 9:for(;i;i--,vp+=15){ + OS;OP;OP;OP;OP;OP;OP;OP;OP;OP;XX;OP;OP;OP;OP;OP; + SAVE;}break; + case 10:for(;i;i--,vp+=15){ + OS;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;XX;OP;OP;OP;OP; + SAVE;}break; + case 11:for(;i;i--,vp+=15){ + OS;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;XX;OP;OP;OP; + SAVE;}break; + case 12:for(;i;i--,vp+=15){ + OS;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;XX;OP;OP; + SAVE;}break; + case 13:for(;i;i--,vp+=15){ + OS;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;XX;OP; + SAVE;}break; + case 14:for(;i;i--,vp+=15){ + OS;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;XX; + SAVE;}break; + case 15:for(;i;i--,vp+=31){ + OS;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + } +} + +#undef OS +#undef XX +#undef OP +#undef SAVE + +#define SAVE \ + putraw(r1); \ + putraw(r2); \ + dp+=16;vp1+=15+(15-14);vp2+=15+(15-14) +#define OS r1=*vp1 * *dp; \ + r2=*vp2 * *dp++ +#define XX vp1+=15;r1+=*vp1 * *dp; \ + vp2+=15;r2+=*vp2 * *dp++ +#define OP r1+=*--vp1 * *dp; \ + r2+=*--vp2 * *dp++ + + +inline void Synthesis::generate_Down(void) +{ + int i; + REAL r1,r2; + register REAL *vp1,*vp2; + register const REAL *dp; + + dp=filter; + vp1=calcbuffer[LS][currentcalcbuffer]+calcbufferoffset; + vp2=calcbuffer[RS][currentcalcbuffer]+calcbufferoffset; +// actual_v+actual_write_pos; + + i=32/2; + switch (calcbufferoffset) + { + case 0:for(;i;i--,vp1+=15,vp2+=15){ + OS;XX;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 1:for(;i;i--,vp1+=15,vp2+=15){ + OS;OP;XX;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 2:for(;i;i--,vp1+=15,vp2+=15){ + OS;OP;OP;XX;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 3:for(;i;i--,vp1+=15,vp2+=15){ + OS;OP;OP;OP;XX;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 4:for(;i;i--,vp1+=15,vp2+=15){ + OS;OP;OP;OP;OP;XX;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 5:for(;i;i--,vp1+=15,vp2+=15){ + OS;OP;OP;OP;OP;OP;XX;OP;OP;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 6:for(;i;i--,vp1+=15,vp2+=15){ + OS;OP;OP;OP;OP;OP;OP;XX;OP;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 7:for(;i;i--,vp1+=15,vp2+=15){ + OS;OP;OP;OP;OP;OP;OP;OP;XX;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 8:for(;i;i--,vp1+=15,vp2+=15){ + OS;OP;OP;OP;OP;OP;OP;OP;OP;XX;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 9:for(;i;i--,vp1+=15,vp2+=15){ + OS;OP;OP;OP;OP;OP;OP;OP;OP;OP;XX;OP;OP;OP;OP;OP; + SAVE;}break; + case 10:for(;i;i--,vp1+=15,vp2+=15){ + OS;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;XX;OP;OP;OP;OP; + SAVE;}break; + case 11:for(;i;i--,vp1+=15,vp2+=15){ + OS;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;XX;OP;OP;OP; + SAVE;}break; + case 12:for(;i;i--,vp1+=15,vp2+=15){ + OS;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;XX;OP;OP; + SAVE;}break; + case 13:for(;i;i--,vp1+=15,vp2+=15){ + OS;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;XX;OP; + SAVE;}break; + case 14:for(;i;i--,vp1+=15,vp2+=15){ + OS;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;XX; + SAVE;}break; + case 15:for(;i;i--,vp1+=31,vp2+=31){ + OS;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + } +} + + + +void Synthesis::synth_Down(int lOutputStereo,REAL *fractionL,REAL *fractionR) { + switch(lOutputStereo) { + case true: + computebuffer_Down(fractionL,calcbuffer[LS]); + computebuffer_Down(fractionR,calcbuffer[RS]); + generate_Down(); + nextOffset(); + break; + case false: + computebuffer_Down(fractionL,calcbuffer[LS]); + generatesingle_Down(); + nextOffset(); + break; + default: + cout << "unknown lOutputStereo in Synthesis::synth_Std"<<endl; + exit(0); + } +} + + +void Synthesis::synthMP3_Down(int lOutputStereo, + REAL hout [2][SSLIMIT][SBLIMIT]) { + int ss; + switch(lOutputStereo) { + case true: + for(ss=0;ss<SSLIMIT;ss++) { + computebuffer_Down(hout[LS][ss],calcbuffer[LS]); + computebuffer_Down(hout[RS][ss],calcbuffer[RS]); + generate_Down(); + nextOffset(); + } + break; + case false: + for(ss=0;ss<SSLIMIT;ss++) { + computebuffer_Down(hout[LS][ss],calcbuffer[LS]); + generatesingle_Down(); + nextOffset(); + } + break; + default: + cout << "unknown lOutputStereo in Synthesis::synth_Std"<<endl; + exit(0); + } +} diff --git a/mpeglib/lib/splay/synth_Std.cpp b/mpeglib/lib/splay/synth_Std.cpp new file mode 100644 index 00000000..6ea1d027 --- /dev/null +++ b/mpeglib/lib/splay/synth_Std.cpp @@ -0,0 +1,330 @@ +/* + std synth implementation + Copyright (C) 2001 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 "synthesis.h" + + + +#include "dct64.cpp" + +#include <iostream> + +using namespace std; + +inline void Synthesis::computebuffer_Std(REAL *fraction, + REAL buffer[2][CALCBUFFERSIZE]) { + REAL *out1,*out2; + out1=buffer[currentcalcbuffer]+calcbufferoffset; + out2=buffer[currentcalcbuffer^1]+calcbufferoffset; + dct64(out1,out2,fraction); +} + + +#define SAVE putraw(r); +#define OS r=*vp * *dp++ +#define XX vp+=15;r+=*vp * *dp++ +#define OP r+=*--vp * *dp++ + + +inline void Synthesis::generatesingle_Std(void) { + int i; + register REAL r, *vp; + register const REAL *dp; + + i=32; + dp=filter; + vp=calcbuffer[LS][currentcalcbuffer]+calcbufferoffset; +// actual_v+actual_write_pos; + + switch (calcbufferoffset) + { + case 0:for(;i;i--,vp+=15){ + OS;XX;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 1:for(;i;i--,vp+=15){ + OS;OP;XX;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 2:for(;i;i--,vp+=15){ + OS;OP;OP;XX;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 3:for(;i;i--,vp+=15){ + OS;OP;OP;OP;XX;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 4:for(;i;i--,vp+=15){ + OS;OP;OP;OP;OP;XX;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 5:for(;i;i--,vp+=15){ + OS;OP;OP;OP;OP;OP;XX;OP;OP;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 6:for(;i;i--,vp+=15){ + OS;OP;OP;OP;OP;OP;OP;XX;OP;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 7:for(;i;i--,vp+=15){ + OS;OP;OP;OP;OP;OP;OP;OP;XX;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 8:for(;i;i--,vp+=15){ + OS;OP;OP;OP;OP;OP;OP;OP;OP;XX;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 9:for(;i;i--,vp+=15){ + OS;OP;OP;OP;OP;OP;OP;OP;OP;OP;XX;OP;OP;OP;OP;OP; + SAVE;}break; + case 10:for(;i;i--,vp+=15){ + OS;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;XX;OP;OP;OP;OP; + SAVE;}break; + case 11:for(;i;i--,vp+=15){ + OS;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;XX;OP;OP;OP; + SAVE;}break; + case 12:for(;i;i--,vp+=15){ + OS;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;XX;OP;OP; + SAVE;}break; + case 13:for(;i;i--,vp+=15){ + OS;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;XX;OP; + SAVE;}break; + case 14:for(;i;i--,vp+=15){ + OS;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;XX; + SAVE;}break; + case 15:for(;i;i--,vp+=31){ + OS;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + } +} + +#undef OS +#undef XX +#undef OP +#undef SAVE + + +#define SAVE putraw(r1); putraw(r2); + +#define OS r1=*vp1 * *dp; \ + r2=*vp2 * *dp++ +#define XX vp1+=15;r1+=*vp1 * *dp; \ + vp2+=15;r2+=*vp2 * *dp++ +#define OP r1+=*--vp1 * *dp; \ + r2+=*--vp2 * *dp++ + +/* +inline void Synthesis::generate_old(void) +{ + int i; + REAL r1,r2; + register REAL *vp1,*vp2; + register const REAL *dp; + + dp=filter; + vp1=calcbuffer[LS][currentcalcbuffer]+calcbufferoffset; + vp2=calcbuffer[RS][currentcalcbuffer]+calcbufferoffset; +// actual_v+actual_write_pos; + + i=32; + switch (calcbufferoffset) + { + case 0:for(;i;i--,vp1+=15,vp2+=15){ + OS;XX;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 1:for(;i;i--,vp1+=15,vp2+=15){ + OS;OP;XX;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 2:for(;i;i--,vp1+=15,vp2+=15){ + OS;OP;OP;XX;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 3:for(;i;i--,vp1+=15,vp2+=15){ + OS;OP;OP;OP;XX;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 4:for(;i;i--,vp1+=15,vp2+=15){ + OS;OP;OP;OP;OP;XX;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 5:for(;i;i--,vp1+=15,vp2+=15){ + OS;OP;OP;OP;OP;OP;XX;OP;OP;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 6:for(;i;i--,vp1+=15,vp2+=15){ + OS;OP;OP;OP;OP;OP;OP;XX;OP;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 7:for(;i;i--,vp1+=15,vp2+=15){ + OS;OP;OP;OP;OP;OP;OP;OP;XX;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 8:for(;i;i--,vp1+=15,vp2+=15){ + OS;OP;OP;OP;OP;OP;OP;OP;OP;XX;OP;OP;OP;OP;OP;OP; + SAVE;}break; + case 9:for(;i;i--,vp1+=15,vp2+=15){ + OS;OP;OP;OP;OP;OP;OP;OP;OP;OP;XX;OP;OP;OP;OP;OP; + SAVE;}break; + case 10:for(;i;i--,vp1+=15,vp2+=15){ + OS;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;XX;OP;OP;OP;OP; + SAVE;}break; + case 11:for(;i;i--,vp1+=15,vp2+=15){ + OS;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;XX;OP;OP;OP; + SAVE;}break; + case 12:for(;i;i--,vp1+=15,vp2+=15){ + OS;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;XX;OP;OP; + SAVE;}break; + case 13:for(;i;i--,vp1+=15,vp2+=15){ + OS;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;XX;OP; + SAVE;}break; + case 14:for(;i;i--,vp1+=15,vp2+=15){ + OS;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;XX; + SAVE;}break; + case 15:for(;i;i--,vp1+=31,vp2+=31){ + OS;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP;OP; + SAVE;}break; + } +} +*/ +#undef OS +#undef XX +#undef OP +#undef SAVE + +#include "op.h" +#define SAVE putraw(r1); putraw(r2); + +inline void Synthesis::generate_Std(void) +{ + int i; + REAL r1,r2; + + register REAL *vp1; + register const REAL *dp; + + dp=filter; + vp1=calcbuffer[LS][currentcalcbuffer]+calcbufferoffset; + // we calculate cp2 from vp1 because they are both + // in the same array. code was: + // register REAL* vp2 + //vp2=calcbuffer[RS][currentcalcbuffer]+calcbufferoffset; + + i=32; + switch (calcbufferoffset) + { + case 0:for(;i;i--,OP_END_1(15,14)){ + OS;XX1;XX2;OP14; + SAVE;}break; + case 1:for(;i;i--,OP_END_1(15,13)){ + OS;OP;OP_END_2(1);XX2;OP13; + SAVE;}break; + case 2:for(;i;i--,OP_END_1(15,12)){ + OS;OP2;OP_END_2(2);XX2;OP12; + SAVE;}break; + case 3:for(;i;i--,OP_END_1(15,11)){ + OS;OP3;OP_END_2(3);XX2;OP11; + SAVE;}break; + case 4:for(;i;i--,OP_END_1(15,10)){ + OS;OP4;OP_END_2(4);XX2;OP10; + SAVE;}break; + case 5:for(;i;i--,OP_END_1(15,9)){ + OS;OP5;OP_END_2(5);XX2;OP9; + SAVE;}break; + case 6:for(;i;i--,OP_END_1(15,8)){ + OS;OP6;OP_END_2(6);XX2;OP8; + SAVE;}break; + case 7:for(;i;i--,OP_END_1(15,7)){ + OS;OP7;OP_END_2(7);XX2;OP7; + SAVE;}break; + case 8:for(;i;i--,OP_END_1(15,6)){ + OS;OP8;OP_END_2(8);XX2;OP6; + SAVE;}break; + case 9:for(;i;i--,OP_END_1(15,5)){ + OS;OP9;OP_END_2(9);XX2;OP5; + SAVE;}break; + case 10:for(;i;i--,OP_END_1(15,4)){ + OS;OP10;OP_END_2(10);XX2;OP4; + SAVE;}break; + case 11:for(;i;i--,OP_END_1(15,3)){ + OS;OP11;OP_END_2(11);XX2;OP3; + SAVE;}break; + case 12:for(;i;i--,OP_END_1(15,2)){ + OS;OP12;OP_END_2(12);XX2;OP2; + SAVE;}break; + case 13:for(;i;i--,OP_END_1(15,1)){ + OS;OP13;OP_END_2(13);XX2;OP; + SAVE;}break; + case 14:for(;i;i--,vp1+=15){ + OS;OP14;OP_END_2(14);XX2; + SAVE;}break; + case 15:for(;i;i--,OP_END_1(31,15)){ + OS;OP15; + SAVE;}break; + } +} +#undef OP_END_1 +#undef OP_END_2 +#undef OP +#undef OP1 +#undef OP2 +#undef OP3 +#undef OP4 +#undef OP5 +#undef OP6 +#undef OP7 +#undef OP8 +#undef OP9 +#undef OP10 +#undef OP11 +#undef OP12 +#undef OP13 +#undef OP14 +#undef OP15 +#undef OS +#undef XX1 +#undef XX2 +#undef SCHEDULE +#undef SCHEDULE1 +#undef SCHEDULE2 +#undef SAVE + +void Synthesis::synth_Std(int lOutputStereo,REAL *fractionL,REAL *fractionR) { + switch(lOutputStereo) { + case true: + computebuffer_Std(fractionL,calcbuffer[LS]); + computebuffer_Std(fractionR,calcbuffer[RS]); + generate_Std(); + nextOffset(); + break; + case false: + computebuffer_Std(fractionL,calcbuffer[LS]); + generatesingle_Std(); + nextOffset(); + break; + default: + cout << "unknown lOutputStereo in Synthesis::synth_Std"<<endl; + exit(0); + } +} + + +void Synthesis::synthMP3_Std(int lOutputStereo, + REAL hout [2][SSLIMIT][SBLIMIT]) { + int ss; + switch(lOutputStereo) { + case true: + for(ss=0;ss<SSLIMIT;ss++) { + computebuffer_Std(hout[LS][ss],calcbuffer[LS]); + computebuffer_Std(hout[RS][ss],calcbuffer[RS]); + generate_Std(); + nextOffset(); + } + break; + case false: + for(ss=0;ss<SSLIMIT;ss++) { + computebuffer_Std(hout[LS][ss],calcbuffer[LS]); + generatesingle_Std(); + nextOffset(); + } + break; + default: + cout << "unknown lOutputStereo in Synthesis::synth_Std"<<endl; + exit(0); + } +} diff --git a/mpeglib/lib/splay/synth_filter.cpp b/mpeglib/lib/splay/synth_filter.cpp new file mode 100644 index 00000000..47455288 --- /dev/null +++ b/mpeglib/lib/splay/synth_filter.cpp @@ -0,0 +1,147 @@ +/* + filer definition + Copyright (C) 2001 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 "synthesis.h" + + +ATTR_ALIGN(64) const REAL Synthesis::filter[512]= +{ + 0.000000000, -0.000442505, 0.003250122, -0.007003784, + 0.031082153, -0.078628540, 0.100311279, -0.572036743, + 1.144989014, 0.572036743, 0.100311279, 0.078628540, + 0.031082153, 0.007003784, 0.003250122, 0.000442505, + -0.000015259, -0.000473022, 0.003326416, -0.007919312, + 0.030517578, -0.084182739, 0.090927124, -0.600219727, + 1.144287109, 0.543823242, 0.108856201, 0.073059082, + 0.031478882, 0.006118774, 0.003173828, 0.000396729, + -0.000015259, -0.000534058, 0.003387451, -0.008865356, + 0.029785156, -0.089706421, 0.080688477, -0.628295898, + 1.142211914, 0.515609741, 0.116577148, 0.067520142, + 0.031738281, 0.005294800, 0.003082275, 0.000366211, + -0.000015259, -0.000579834, 0.003433228, -0.009841919, + 0.028884888, -0.095169067, 0.069595337, -0.656219482, + 1.138763428, 0.487472534, 0.123474121, 0.061996460, + 0.031845093, 0.004486084, 0.002990723, 0.000320435, + -0.000015259, -0.000625610, 0.003463745, -0.010848999, + 0.027801514, -0.100540161, 0.057617188, -0.683914185, + 1.133926392, 0.459472656, 0.129577637, 0.056533813, + 0.031814575, 0.003723145, 0.002899170, 0.000289917, + -0.000015259, -0.000686646, 0.003479004, -0.011886597, + 0.026535034, -0.105819702, 0.044784546, -0.711318970, + 1.127746582, 0.431655884, 0.134887695, 0.051132202, + 0.031661987, 0.003005981, 0.002792358, 0.000259399, + -0.000015259, -0.000747681, 0.003479004, -0.012939453, + 0.025085449, -0.110946655, 0.031082153, -0.738372803, + 1.120223999, 0.404083252, 0.139450073, 0.045837402, + 0.031387329, 0.002334595, 0.002685547, 0.000244141, + -0.000030518, -0.000808716, 0.003463745, -0.014022827, + 0.023422241, -0.115921021, 0.016510010, -0.765029907, + 1.111373901, 0.376800537, 0.143264771, 0.040634155, + 0.031005859, 0.001693726, 0.002578735, 0.000213623, + -0.000030518, -0.000885010, 0.003417969, -0.015121460, + 0.021575928, -0.120697021, 0.001068115, -0.791213989, + 1.101211548, 0.349868774, 0.146362305, 0.035552979, + 0.030532837, 0.001098633, 0.002456665, 0.000198364, + -0.000030518, -0.000961304, 0.003372192, -0.016235352, + 0.019531250, -0.125259399, -0.015228271, -0.816864014, + 1.089782715, 0.323318481, 0.148773193, 0.030609131, + 0.029937744, 0.000549316, 0.002349854, 0.000167847, + -0.000030518, -0.001037598, 0.003280640, -0.017349243, + 0.017257690, -0.129562378, -0.032379150, -0.841949463, + 1.077117920, 0.297210693, 0.150497437, 0.025817871, + 0.029281616, 0.000030518, 0.002243042, 0.000152588, + -0.000045776, -0.001113892, 0.003173828, -0.018463135, + 0.014801025, -0.133590698, -0.050354004, -0.866363525, + 1.063217163, 0.271591187, 0.151596069, 0.021179199, + 0.028533936, -0.000442505, 0.002120972, 0.000137329, + -0.000045776, -0.001205444, 0.003051758, -0.019577026, + 0.012115479, -0.137298584, -0.069168091, -0.890090942, + 1.048156738, 0.246505737, 0.152069092, 0.016708374, + 0.027725220, -0.000869751, 0.002014160, 0.000122070, + -0.000061035, -0.001296997, 0.002883911, -0.020690918, + 0.009231567, -0.140670776, -0.088775635, -0.913055420, + 1.031936646, 0.221984863, 0.151962280, 0.012420654, + 0.026840210, -0.001266479, 0.001907349, 0.000106812, + -0.000061035, -0.001388550, 0.002700806, -0.021789551, + 0.006134033, -0.143676758, -0.109161377, -0.935195923, + 1.014617920, 0.198059082, 0.151306152, 0.008316040, + 0.025909424, -0.001617432, 0.001785278, 0.000106812, + -0.000076294, -0.001480103, 0.002487183, -0.022857666, + 0.002822876, -0.146255493, -0.130310059, -0.956481934, + 0.996246338, 0.174789429, 0.150115967, 0.004394531, + 0.024932861, -0.001937866, 0.001693726, 0.000091553, + -0.000076294, -0.001586914, 0.002227783, -0.023910522, + -0.000686646, -0.148422241, -0.152206421, -0.976852417, + 0.976852417, 0.152206421, 0.148422241, 0.000686646, + 0.023910522, -0.002227783, 0.001586914, 0.000076294, + -0.000091553, -0.001693726, 0.001937866, -0.024932861, + -0.004394531, -0.150115967, -0.174789429, -0.996246338, + 0.956481934, 0.130310059, 0.146255493, -0.002822876, + 0.022857666, -0.002487183, 0.001480103, 0.000076294, + -0.000106812, -0.001785278, 0.001617432, -0.025909424, + -0.008316040, -0.151306152, -0.198059082, -1.014617920, + 0.935195923, 0.109161377, 0.143676758, -0.006134033, + 0.021789551, -0.002700806, 0.001388550, 0.000061035, + -0.000106812, -0.001907349, 0.001266479, -0.026840210, + -0.012420654, -0.151962280, -0.221984863, -1.031936646, + 0.913055420, 0.088775635, 0.140670776, -0.009231567, + 0.020690918, -0.002883911, 0.001296997, 0.000061035, + -0.000122070, -0.002014160, 0.000869751, -0.027725220, + -0.016708374, -0.152069092, -0.246505737, -1.048156738, + 0.890090942, 0.069168091, 0.137298584, -0.012115479, + 0.019577026, -0.003051758, 0.001205444, 0.000045776, + -0.000137329, -0.002120972, 0.000442505, -0.028533936, + -0.021179199, -0.151596069, -0.271591187, -1.063217163, + 0.866363525, 0.050354004, 0.133590698, -0.014801025, + 0.018463135, -0.003173828, 0.001113892, 0.000045776, + -0.000152588, -0.002243042, -0.000030518, -0.029281616, + -0.025817871, -0.150497437, -0.297210693, -1.077117920, + 0.841949463, 0.032379150, 0.129562378, -0.017257690, + 0.017349243, -0.003280640, 0.001037598, 0.000030518, + -0.000167847, -0.002349854, -0.000549316, -0.029937744, + -0.030609131, -0.148773193, -0.323318481, -1.089782715, + 0.816864014, 0.015228271, 0.125259399, -0.019531250, + 0.016235352, -0.003372192, 0.000961304, 0.000030518, + -0.000198364, -0.002456665, -0.001098633, -0.030532837, + -0.035552979, -0.146362305, -0.349868774, -1.101211548, + 0.791213989, -0.001068115, 0.120697021, -0.021575928, + 0.015121460, -0.003417969, 0.000885010, 0.000030518, + -0.000213623, -0.002578735, -0.001693726, -0.031005859, + -0.040634155, -0.143264771, -0.376800537, -1.111373901, + 0.765029907, -0.016510010, 0.115921021, -0.023422241, + 0.014022827, -0.003463745, 0.000808716, 0.000030518, + -0.000244141, -0.002685547, -0.002334595, -0.031387329, + -0.045837402, -0.139450073, -0.404083252, -1.120223999, + 0.738372803, -0.031082153, 0.110946655, -0.025085449, + 0.012939453, -0.003479004, 0.000747681, 0.000015259, + -0.000259399, -0.002792358, -0.003005981, -0.031661987, + -0.051132202, -0.134887695, -0.431655884, -1.127746582, + 0.711318970, -0.044784546, 0.105819702, -0.026535034, + 0.011886597, -0.003479004, 0.000686646, 0.000015259, + -0.000289917, -0.002899170, -0.003723145, -0.031814575, + -0.056533813, -0.129577637, -0.459472656, -1.133926392, + 0.683914185, -0.057617188, 0.100540161, -0.027801514, + 0.010848999, -0.003463745, 0.000625610, 0.000015259, + -0.000320435, -0.002990723, -0.004486084, -0.031845093, + -0.061996460, -0.123474121, -0.487472534, -1.138763428, + 0.656219482, -0.069595337, 0.095169067, -0.028884888, + 0.009841919, -0.003433228, 0.000579834, 0.000015259, + -0.000366211, -0.003082275, -0.005294800, -0.031738281, + -0.067520142, -0.116577148, -0.515609741, -1.142211914, + 0.628295898, -0.080688477, 0.089706421, -0.029785156, + 0.008865356, -0.003387451, 0.000534058, 0.000015259, + -0.000396729, -0.003173828, -0.006118774, -0.031478882, + -0.073059082, -0.108856201, -0.543823242, -1.144287109, + 0.600219727, -0.090927124, 0.084182739, -0.030517578, + 0.007919312, -0.003326416, 0.000473022, 0.000015259 +}; diff --git a/mpeglib/lib/splay/synthesis.cpp b/mpeglib/lib/splay/synthesis.cpp new file mode 100644 index 00000000..699037c9 --- /dev/null +++ b/mpeglib/lib/splay/synthesis.cpp @@ -0,0 +1,73 @@ +/* + header for synthesis + Copyright (C) 2001 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 "synthesis.h" + + +#include <iostream> + +using namespace std; + +Synthesis::Synthesis() { + + int i; + outpos=0; + calcbufferoffset=15; + currentcalcbuffer=0; + + for(i=CALCBUFFERSIZE-1;i>=0;i--) + calcbuffer[LS][0][i]=calcbuffer[LS][1][i]= + calcbuffer[RS][0][i]=calcbuffer[RS][1][i]=0.0; + + initialize_dct64(); + initialize_dct64_downsample(); +} + + +Synthesis::~Synthesis() { +} + + +void Synthesis::doSynth(int lDownSample,int lOutputStereo, + REAL *fractionL,REAL *fractionR) { + switch(lDownSample) { + case false: + synth_Std(lOutputStereo,fractionL,fractionR); + break; + case true: + synth_Down(lOutputStereo,fractionL,fractionR); + break; + default: + cout << "unknown downsample parameter"<<lDownSample<<endl; + exit(0); + } +} + + +void Synthesis::doMP3Synth(int lDownSample,int lOutputStereo, + REAL in[2][SSLIMIT][SBLIMIT]) { + + switch(lDownSample) { + case false: + synthMP3_Std(lOutputStereo,in); + break; + case true: + synthMP3_Down(lOutputStereo,in); + break; + default: + cout << "unknown downsample parameter:"<<lDownSample<<endl; + exit(0); + } +} + + diff --git a/mpeglib/lib/splay/synthesis.h b/mpeglib/lib/splay/synthesis.h new file mode 100644 index 00000000..801d658e --- /dev/null +++ b/mpeglib/lib/splay/synthesis.h @@ -0,0 +1,95 @@ +/* + header for synthesis + Copyright (C) 2001 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 __SYNTHESIS_H +#define __SYNTHESIS_H + +#include "common.h" +#include "dct.h" + +#define CALCBUFFERSIZE 512 +// AIX seems to have FRAMESIZE defined +#undef FRAMESIZE + +#define FRAMESIZE (2*2*2*32*18) + + +class Synthesis { + + // + // Subbandsynthesis two calcbuffers for every channel, and two channels. + // calcbufferL[0]=calcbuffer[0] + // calcbufferL[1]=calcbuffer[1] + // calcbufferR[0]=calcbuffer[2] + // calcbufferR[1]=calcbuffer[3] + ATTR_ALIGN(64) REAL calcbuffer[2][2][CALCBUFFERSIZE]; + ATTR_ALIGN(64) int currentcalcbuffer,calcbufferoffset; + static ATTR_ALIGN(64) const REAL filter[512]; + ATTR_ALIGN(64) REAL out[FRAMESIZE]; + int outpos; + + public: + Synthesis(); + ~Synthesis(); + + // mpeg1,2 + void doSynth(int lDownSample,int lOutputStereo, + REAL *fractionL,REAL *fractionR); + + void doMP3Synth(int lDownSample,int lOutputStereo, + REAL in[2][SSLIMIT][SBLIMIT]); + + // put mpeg to raw + inline void putraw(REAL val) { + out[outpos++]=val; + } + + inline REAL* getOutputData() { return out; } + inline void clearrawdata() { outpos=0; } + inline int getLen() { return outpos; } + + + private: + void synth_Down(int lOutputStereo,REAL *fractionL,REAL *fractionR); + void synth_Std(int lOutputStereo,REAL *fractionL,REAL *fractionR); + + void synthMP3_Down(int lOutputStereo,REAL hout [2][SSLIMIT][SBLIMIT]); + void synthMP3_Std(int lOutputStereo,REAL hout [2][SSLIMIT][SBLIMIT]); + + inline void nextOffset() { + calcbufferoffset++; + calcbufferoffset&=0xf; + /* + if (calcbufferoffset<15) { + calcbufferoffset++; + } else { + calcbufferoffset=0; + } + */ + currentcalcbuffer^=1; + } + + + void computebuffer_Std(REAL *fraction,REAL buffer[2][CALCBUFFERSIZE]); + void generate_Std(void); + void generatesingle_Std(void); + + void computebuffer_Down(REAL *fraction,REAL buffer[2][CALCBUFFERSIZE]); + void generate_Down(void); + void generatesingle_Down(void); + + +}; + +#endif diff --git a/mpeglib/lib/splay/window.cpp b/mpeglib/lib/splay/window.cpp new file mode 100644 index 00000000..b95dbdcf --- /dev/null +++ b/mpeglib/lib/splay/window.cpp @@ -0,0 +1,70 @@ +/* + wrapper for window functions + Copyright (C) 2001 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 "mpegsound.h" + + +static int windowInit=0; + +ATTR_ALIGN(64) REAL win[4][36]; +ATTR_ALIGN(64) REAL winINV[4][36]; + + +void initialize_win() { + if (windowInit==true) { + return; + } + windowInit=true; + + int i; + + for(i=0;i<18;i++) { + /* + win[0][i]=win[1][i]=0.5*sin(PI_72*(double)(2*i+1))/ + cos(PI_72*(double)(2*i+19)); + */ + win[0][i]=win[1][i]=0.5*sin(PI_72*(double)(2*(i+0)+1))/cos(MY_PI * (double) (2*(i+0) +19) / 72.0 ); + win[0][i+18] = win[3][i+18] = 0.5 * sin( MY_PI / 72.0 * (double) (2*(i+18)+1) ) / cos ( MY_PI * (double) (2*(i+18)+19) / 72.0 ); + } + /* + for(;i<36;i++) { + win[0][i]=win[3][i]=0.5*sin(PI_72*(double)(2*i+1))/cos(PI_72*(double)(2*i+19)); + + } + */ + for(i=0;i<6;i++) { + win[1][i+18]=0.5/cos(MY_PI*(double)(2*(i+18)+19)/72.0); + win[3][i+12]=0.5/cos(MY_PI*(double)(2*(i+12)+19)/72.0); + win[1][i+24]=0.5*sin(PI_24*(double)(2*i+13))/cos(MY_PI*(double)(2*(i+24)+19)/72.0); + win[1][i+30]=win[3][i]=0.0; + win[3][i+6 ]=0.5*sin(PI_24*(double)(2*i+1))/cos(MY_PI*(double)(2*(i+6)+19)/72.0); + } + for(i=0;i<12;i++) + win[2][i]=0.5*sin(PI_24*(double)(2*i+1))/cos(MY_PI*(double)(2*i+7)/24.0); + + int j; + + for(j=0;j<4;j++) { + int len[4] = { 36,36,12,36 }; + for(i=0;i<len[j];i+=2) + winINV[j][i] = + win[j][i]; + for(i=1;i<len[j];i+=2) + winINV[j][i] = - win[j][i]; + } + + +} + + +inline REAL* getSplayWindow(int nr) { return win[nr]; } +inline REAL* getSplayWindowINV(int nr) { return winINV[nr]; } diff --git a/mpeglib/lib/tplay/CHANGES b/mpeglib/lib/tplay/CHANGES new file mode 100644 index 00000000..aad2446d --- /dev/null +++ b/mpeglib/lib/tplay/CHANGES @@ -0,0 +1,154 @@ +Version 0.1, 2.4.1997: + + - the first released version + +5.4.1997: + + - audio sync added before changing parameters + +Version 0.2, 9.4.1997: + + - it was useless to start producer as a thread; + it was made that way just for historical reasons. + only consumer is threaded now. this may result + as more robust behaviour. + + - there are min and max sizes for block now. i'm + not sure yet what size for a block and the audio + buffer would be good. needs more research. + + - fill_buffer function. fills the audio buffer + before use. + +Version 0.2.1, 15.4.1997: + + - signal() seems to be a bad idea in a threaded + application like this. causes kernel oops in + the sound driver function audio_write (sometimes). + let's have faith on the kernel and remove it. + +Version 0.2.2, 17.4.1997 morning: + + - the last block was written from very wrong point. + + - block counting added. this makes stream ending + simpler and (hopefully) more robust. + + - first lines for handling underflow (buffer empty) + situation. + +Version 0.3, 17.4.1997 afternoon: + + - underflow handling should work now. + + - function buffer_usage added. returns buffer usage + in percents. nowhere used yet. + + - minimum block size increased to 16k. + +Version 0.3.1, 19.4.1997: + + - GNU style options. + + - option -v (or --version) added. + + - buffer usage option -u (or --usage) added. + +Version 0.4, 2.5.1997: + + - support for RIFF/WAVE (WAV) and Sun audio + (AU) files. + + - swap endianness flag -x (or --swap) added. + + - verbose mode flag -V (or --verbose) added. + + - force raw flag -r (or --raw) added. WAV- or + AU-file headers are ignored if this flag is set. + +Version 0.4.1, 3.5.1997: + + - sun header gives odd aligned starting point + for sample. temporary fix. + + - read_big_endian_long returned wrong value if + sampling rate was 44100. this caused tplay + not to work with that speed when playing sun + audio or wav file. fixed now. + +Version 0.4.2, 7.5.1997: + + - read_big_endian_long and similar functions: + parameter's type was char* and that was a bug. + changed to byte* (unsigned char *). conversion + should also be saner now. + + - force playing -f (or --force) flag added. this + makes tplay to ignore sound driver's results + when changing parameters. + +Version 0.4.3, 12.5.1997: + + - binary is statically linked to LinuxThreads + version 0.6 now. + + - print sun header comment if verbose is requested. + + - sun audio file's data stream starting pointer + is read and set from the header. + + - to avoid rounding errors when playing 16bit + and/or stereo (au or wav) sample, data section + is moved now to the beginning of buffer before + playing. + +Version 0.5, 23.10.1997: + + - set_audio_parameters() partly rewritten and + changes to open_audio(). + + - in some WAV-files, data-portion is not started + with 'data'-magic but 'INFO' instead. some + players don't even check that so tplay prints + just a warning message now if neither of these + magics exists. + +Version 0.5.1, 25.10.1997: + + - printing of buffer usage changed from producer + to consumer. this makes this silly feature a bit + more informative as it is still active after the + producer has stopped. underflow situation (when + the big buffer needs to be refilled) is also + possible to show now. + +Version 0.5.2, 9.5.1998: + + - Jerko Golubovic <jerko.golubovic@public.srce.hr> + kindly modified the code to support those soundcards + that may result slightly different sampling rate + than requested. he also provided RPM of tplay. + + - added -D (or --device=DEVICE) flag for setting + audio device to be used. + + - added feature to -B (or --buffer-size=SIZE) flag. + buffer size can be given in seconds now, too. + +Version 0.5.3, 11.5.1998: + + - rewrite of playing routine to support multiple + sound samples from command line. + +Version 0.5.4, 19.5.1998: + + - added -l (or --loop) flag to support looping sound + samples. + + - sun port. + +Version 0.5.5, 24.5.1998: + + - added environment variable TPLAYDEV, which sets the + audio device to be used. decoding of command line + options is moved from main() to another function. diff --git a/mpeglib/lib/tplay/Makefile.am b/mpeglib/lib/tplay/Makefile.am new file mode 100644 index 00000000..c83b25ea --- /dev/null +++ b/mpeglib/lib/tplay/Makefile.am @@ -0,0 +1,15 @@ +# libtplay - Makefile.am + + +EXTRA_DIST = CHANGES README + +INCLUDES = $(all_includes) + + +noinst_LTLIBRARIES = libtplay.la + +noinst_HEADERS = tplayfunctions.h + +libtplay_la_SOURCES = au.cpp \ + tplayfunctions.cpp wav.cpp + diff --git a/mpeglib/lib/tplay/README b/mpeglib/lib/tplay/README new file mode 100644 index 00000000..275d6a9f --- /dev/null +++ b/mpeglib/lib/tplay/README @@ -0,0 +1,95 @@ +This is a buffered audio player for Linux. POSIX-thread library is +used. This is still considered BETA software and may not work as +expected. Please mail me for bug reports, opinions or suggestions. + +This is primarily made for use with MPEG-decoders. They typically +consume lots of CPU-time and some kind of audio buffer is needed to +reduce cutting while writing to audio device. You can also play any +audio files with tplay or use it with any program that writes audio +data to standard out. + +RIFF/WAVE (WAV) and Sun audio (AU) file headers are recognized by +now. + +Binary: + +In the source tree there is a readily compiled binary that is build +under Linux/ELF 2.0.30 with libc 5.4.20 and LinuxThreads 0.6 (the +thread library is statically linked). + +Command line options: + + tplay [-hvVmuxrf] [-s Hz] [-b 8|16] [-B kilobytes] [filename] + + -h, --help Print help, then exit + -v, --version Print version, then exit + -V, --verbose Print useful information about the sample + -x, --swap Swap endianness + -r, --raw Force raw audio format. Ignore headers. + -f, --force Force playing with any parameters + -m, --mono Mono sample + -u, --usage Print buffer usage while playing + -s, --speed=SPEED Sample speed (Hz) + -b, --bytes=BYTES Bytes in a sample + -B, --buffer-size=SIZE Buffer size in (kB) + +Buffer size is defaulted to 512k. It is about 3 seconds CD audio +(44100Hz/sample, 16bytes, stereo). If filename is not given, standard +input is used. If -x (or --swap) flag is set, the byte order of +audio sample is swapped before playing. The default is Intel little- +endian which is mostly used in x86 machines. The world outside Intel +is big-endian. +Option -r (or --raw) forces tplay to handle the sample as an raw +PCM audio sample. Sun audio or WAV headers are ignored. + +Requirements: + + - Linux 2.0 or newer with audio card support + - POSIX thread library + - Audio card + +There are several POSIX thread libraries available. I used +LinuxThreads by Xavier Leroy (Xavier.Leroy@inria.fr). LinuxThreads +library use clone() that is provided by Linux 2.0 kernel. + +The code: + +tplay starts one thread, named consumer, that reads circular audio +buffer and writes it to audio device. The producer is a function that +runs in parallel with the consumer and its task is to read the sample +file or standard input and write this data to audio buffer to meet +consumer's needs. Usually, the buffer is full but on the times when +CPU-time is suddenly needed for other processes (usually: disk +read/write), the producer can't write fast enough and consumer can use +the buffer to keep audio stream uninterrupted. If the buffer is used +and the producer is still unable to feed it fast enough, underflow +situation is met and consumer waits for awhile (typically: one second) +for the producer to fill the buffer again. + +Building: + +If you want to link tplay with static libpthread library, edit +Makefile and uncomment preferred LIBS-setting there. Type: + + - make + - make install + - make install.man + +Thanks: + +Jerko Golubovic <jerko.golubovic@public.srce.hr> +Jukka Palviainen <oh3kjt@ele.tut.fi> + +TODO: + +Find out the best sizes for the audio buffer and one block. +Better documentation. +Better RIFF/WAVE checking. + +Ilkka Karvinen +ik@iki.fi + + + + + diff --git a/mpeglib/lib/tplay/au.cpp b/mpeglib/lib/tplay/au.cpp new file mode 100644 index 00000000..8880515f --- /dev/null +++ b/mpeglib/lib/tplay/au.cpp @@ -0,0 +1,100 @@ +/* + * tplay - buffered audio player + * + * (c) 1997 ilkka karvinen <ik@iki.fi> + * + * Copyright under the GNU GENERAL PUBLIC LICENSE + * (see the file COPYING in this directory) + * + * + * SunOS audio file header functions. + * Reference: http://www.wotsit.org + */ + +#include "tplayfunctions.h" + +/* read_au returns zero if Sun audio file format is found. */ +int read_au(struct info_struct* info,char * buffer) { + DWORD magic, start, end, encoding, speed, channels; + int bits; + + + /* If '.snd'-header exits, this should be an au-file */ + magic = read_big_endian_long(buffer); + if (magic != SUN_MAGIC) + return (1); + + start = read_big_endian_long(buffer + 0x04); + end = read_big_endian_long(buffer + 0x08); + encoding = read_big_endian_long(buffer + 0x0C); + speed = read_big_endian_long(buffer + 0x10); + channels = read_big_endian_long(buffer + 0x14); + +#ifdef DEBUG + printf("Sun audio file.\nspeed: %ld, start: %ld, end: %ld, \ +encoding: %X, channels: %ld\n", + speed, start, end, encoding, channels); + fflush(stdout); +#endif + + bits = DEFAULT_BITS; + switch (encoding) { + case 1: + die("8-bit ISDN u-law Sun audio file not supported"); + break; + case 2: + bits = 8; + break; + case 3: + bits = 16; + break; + case 4: + die("24-bit linear PCM Sun audio file not supported"); + break; + case 5: + die("32-bit linear PCM Sun audio file not supported"); + break; + case 6: + die("32-bit IEEE floating point Sun audio file not supported"); + break; + case 7: + die("64-bit IEEE floating point Sun audio file not supported"); + break; + case 23: + die("8-bit ISDN u-law compressed(G.721 ADPCM) Sun audio file \ +not supported"); + break; + default: + errdie("Unknown Sun audio file"); + break; + } + + info->filetype = SUN_FILE; + + /* Set audio parameters */ + info->speed = (int) speed; + info->bits = bits; + info->channels = (int) channels; + + if (info->verbose) { + printf("Sun audio file: %ld samples/s, %d bits, %d channel(s).\n", + info->speed, info->bits, info->channels); + /* + if ((comment_size = start - SUN_HDRSIZE) > 0) { + printf("Header info: "); + for (i = 0; i < comment_size; i++) + nice_fputc((int) buffer[SUN_HDRSIZE + i], stdout); + printf("\n"); + } + */ + } + + /* Move data to start from the beginning of the buffer. */ + /* This is to ensure the correct behaviour of rounding when 16bits */ + /* and/or stereo sample is to be played. */ + memmove(buffer, buffer + (start + 1), info->blocksize - start - 1); + + info->headerskip = (int) (start + 1); + + return (0); +} diff --git a/mpeglib/lib/tplay/tplayfunctions.cpp b/mpeglib/lib/tplay/tplayfunctions.cpp new file mode 100644 index 00000000..c105f4a2 --- /dev/null +++ b/mpeglib/lib/tplay/tplayfunctions.cpp @@ -0,0 +1,84 @@ +/* + * tplay - buffered audio player + * + * (c) 1997 ilkka karvinen <ik@iki.fi> + * + * Copyright under the GNU GENERAL PUBLIC LICENSE + * (see the file COPYING in this directory) + * + * + * common functions + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> + +#include "tplayfunctions.h" + +DWORD read_big_endian_long(char * buf) +{ + DWORD byte0, byte1, byte2, byte3; + unsigned char* buffer=(unsigned char*) buf; + + byte0 = (DWORD) buffer[0]; + byte1 = (DWORD) buffer[1]; + byte2 = (DWORD) buffer[2]; + byte3 = (DWORD) buffer[3]; + return (byte0 << 24 | byte1 << 16 | byte2 << 8 | byte3); +} + +void write_big_endian_long(char * buf, DWORD value) +{ + unsigned char* buffer=(unsigned char*) buf; + buffer[0] = (unsigned char) (value >> 24 & 0xFF); + buffer[1] = (unsigned char) (value >> 16 & 0xFF); + buffer[2] = (unsigned char) (value >> 8 & 0xFF); + buffer[3] = (unsigned char) (value & 0xFF); +} + +DWORD read_little_endian_long(char* buf) { + DWORD byte0, byte1, byte2, byte3; + unsigned char* buffer=(unsigned char*) buf; + + byte0 = (DWORD) buffer[0]; + byte1 = (DWORD) buffer[1]; + byte2 = (DWORD) buffer[2]; + byte3 = (DWORD) buffer[3]; + return (byte3 << 24 | byte2 << 16 | byte1 << 8 | byte0); +} + +WORD read_little_endian_word(char * buf) +{ + WORD byte0, byte1; + unsigned char* buffer=(unsigned char*) buf; + + byte0 = (WORD) buffer[0]; + byte1 = (WORD) buffer[1]; + return (byte1 << 8 | byte0); +} + +void errprintf(char *fmt,...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); +} + + + +void die(const char *str) +{ + fprintf(stderr, "%s: \n", str); + exit(-1); +} + +void errdie(const char *str) +{ + fprintf(stderr, "Error: %s\n", str); + exit(-1); +} + + + diff --git a/mpeglib/lib/tplay/tplayfunctions.h b/mpeglib/lib/tplay/tplayfunctions.h new file mode 100644 index 00000000..0c159847 --- /dev/null +++ b/mpeglib/lib/tplay/tplayfunctions.h @@ -0,0 +1,128 @@ +/* + * tplay - buffered audio player header file + * + * (c) 1997 ilkka karvinen <ik@iki.fi> + * + * Copyright under the GNU GENERAL PUBLIC LICENSE + * (see the file COPYING in this directory) + * + */ + +#ifndef __TPLAYCONTROL_H +#define __TPLAYCONTROL_H + +extern "C" { +#include <stdio.h> +#include <string.h> +} + +/* tplay version */ +#define MAJOR_VERSION 0 +#define MINOR_VERSION 5 +#define PATCHLEVEL 5 + +/* Default audio parameters */ +#define DEFAULT_BITS 16 +#define DEFAULT_SPEED 44100 +#define DEFAULT_CHANNELS 2 + +/* Audio memory pool. 512k is the default. */ +#define BUFFER_SIZE 0x80000 + +/* The minimum and maximum buffer block sizes. */ +#if 0 +#define MIN_BLOCK_SIZE 0x4000 /* 16k */ +#else +#define MIN_BLOCK_SIZE 4096 +#endif +#define MAX_BLOCK_SIZE 0x10000 /* 64k */ + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +/* The maximum retry count for buffer fill tries. */ +#define RETRY_COUNT 5 + +/* Magics. Little-endian. */ +#define RIFF_MAGIC 0x46464952 /* ASCII: 'RIFF' */ +#define WAVE_MAGIC 0x45564157 /* ASCII: 'WAVE' */ +#define DATA_MAGIC 0x61746164 /* ASCII: 'data' */ +#define INFO_MAGIC 0x4f464e49 /* ASCII: 'INFO' */ +#define SUN_MAGIC 0x2e736e64 /* ASCII: '.snd' */ + +/* Magics. Big-endian. */ +#define SUN_INV_MAGIC 0x646e732e /* ASCII: '.snd' */ + +/* Sun headersize */ +#define SUN_HDRSIZE 24 + +/* File types */ +#define UNKNOWN_FILE 0 +#define RIFF_FILE 1 +#define SUN_FILE 2 + +typedef unsigned long DWORD; +typedef unsigned short WORD; + +/* Circular buffer info structure of audio data blocks. */ +/* declared in tplay.c */ +struct info_struct { + char *buffer; /* the audio data */ + char *firstblock; /* pointer to the first block */ + int readblock, writeblock; /* reading and writing block number */ + long readcount, writecount; + int alldone; + int in_seconds; + double seconds; + int blocksize; /* size of one block */ + int buffer_size; /* size of the buffer */ + int number_of_blocks; + int last_block; /* -1 if not the last block */ + int bytes_on_last_block; + int overflow; + int underflow; + int swap; + int forceraw; + int force; + int filetype; + int headerskip; + int audioset; + int show_usage; + DWORD speed; + int channels; + int bits; + char *progname; + char *device; /* Audio device name */ + int loop; + int verbose; + int optind; +}; + +/* au.c */ + int read_au(struct info_struct* info, char * buffer); + +/* wav.c */ + int read_wav(struct info_struct* info, char * buffer); + +/* common.c */ + DWORD read_big_endian_long(char * buffer); + void write_big_endian_long(char * buffer, DWORD value); + DWORD read_little_endian_long(char * buffer); + WORD read_little_endian_word(char * buffer); + void errprintf(char *fmt,...); + void warning(char *str); + void warning2(char *str1, char *str2); + void die(const char *str); + void errdie(const char *str); + void open_audio(); + void set_audio_parameters(); + void sync_audio(void); + void reset_audio(void); + void post_audio(void); + void destroy_buffer(void); + void nice_fputc(int c, FILE * fp); + + +#endif diff --git a/mpeglib/lib/tplay/wav.cpp b/mpeglib/lib/tplay/wav.cpp new file mode 100644 index 00000000..ca284c37 --- /dev/null +++ b/mpeglib/lib/tplay/wav.cpp @@ -0,0 +1,91 @@ +/* + * tplay - buffered audio player + * + * (c) 1997 ilkka karvinen <ik@iki.fi> + * + * Copyright under the GNU GENERAL PUBLIC LICENSE + * (see the file COPYING in this directory) + * + * + * RIFF/WAVE file header checking. + * check_wav returns zero if RIFF/WAVE file format is found. + * Reference: http://www.wotsit.demon.co.uk/formats/wav/wav.txt + */ + +#include "tplayfunctions.h" + +#include <iostream> + +using namespace std; + +int read_wav(struct info_struct* info, char * buffer) { + WORD format, channels, bits; + DWORD magic, samples_per_second, length, data_length; + + magic = read_little_endian_long(buffer); + if (magic != RIFF_MAGIC) /* RIFF file? */ + return (1); + magic = read_little_endian_long(buffer + 0x08); + if (magic != WAVE_MAGIC) /* WAVE file? */ + return (1); + magic = read_little_endian_long(buffer + 0x24); + if ((magic != DATA_MAGIC) && (magic != INFO_MAGIC)) { /* data-portion there? */ + cout << "Unknown WAV-header magic. Continuing anyway."<<endl; + } + + length = read_little_endian_long(buffer + 0x10); + + /* Subchunk length should be 16 here */ + if (length != 16) + errdie("Unknown RIFF/WAVE header"); + + format = read_little_endian_word(buffer + 0x14); + + switch (format) { + case 0x0001: /* PCM format */ + break; + case 0x0101: /* mu-law */ + die("Mu-law RIFF/WAVE audio file not supported"); + break; + case 0x0102: /* a-law */ + die("A-law RIFF/WAVE audio file not supported"); + break; + case 0x0103: /* ADPCM */ + die("ADPCM RIFF/WAVE audio file not supported"); + break; + default: + errdie("Unknown RIFF/WAVE audio file format"); + break; + } + + info->filetype = RIFF_FILE; + + channels = read_little_endian_word(buffer + 0x16); + samples_per_second = read_little_endian_long(buffer + 0x18); + cout << "samples_per_second:"<<samples_per_second<<endl; + bits = read_little_endian_word(buffer + 0x22); + + if (bits == 12) + die("12 bits per sample not supported"); + + data_length = read_little_endian_long(buffer + 0x28); + + /* Set audio parameters */ + info->speed = (int) samples_per_second; + info->bits = (int) bits; + info->channels = (int) channels; + + if (info->verbose) + printf("RIFF/WAVE audio file: %ld samples/s, %d bits, %d channel(s).\n", + info->speed, info->bits, info->channels); + + /* Move data to start from the beginning of the buffer. */ + /* This is to ensure the correct behaviour of rounding when 16bits */ + /* and/or stereo sample is to be played. */ + memmove(buffer, buffer + 0x2c, info->blocksize - 0x2c); + + /* Save audio sample starting point */ + info->headerskip = 0x2c; + + return (0); +} diff --git a/mpeglib/lib/util/Makefile.am b/mpeglib/lib/util/Makefile.am new file mode 100644 index 00000000..c73de2cc --- /dev/null +++ b/mpeglib/lib/util/Makefile.am @@ -0,0 +1,61 @@ +# player - Makefile.am + +SUBDIRS = mmx abstract audio file render + + +INCLUDES = $(all_includes) + + + +THIS_EXTRALIBS = abstract/libutilabstract.la \ + audio/libaudio.la \ + file/libsimplefile.la \ + render/libutilrender.la \ + mmx/libmmx.la + + +noinst_LTLIBRARIES = libutil.la + +noinst_HEADERS = syncClockMPEG.h + +kmpgincludedir = $(includedir)/$(THIS_LIB_NAME)/util + +kmpginclude_HEADERS = timeStamp.h dynBuffer.h \ + timeStampArray.h syncClock.h timeWrapper.h + + + +libutil_la_SOURCES = timeStamp.cpp \ + timeStampArray.cpp \ + dynBuffer.cpp syncClock.cpp \ + syncClockMPEG.cpp timeWrapper.cpp + +libutil_la_LIBADD = $(THIS_EXTRALIBS) + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mpeglib/lib/util/abstract/Makefile.am b/mpeglib/lib/util/abstract/Makefile.am new file mode 100644 index 00000000..a5c49d6b --- /dev/null +++ b/mpeglib/lib/util/abstract/Makefile.am @@ -0,0 +1,14 @@ +# player - Makefile.am + + +INCLUDES = $(all_includes) + +noinst_LTLIBRARIES = libutilabstract.la + +kmpgincludedir = $(includedir)/$(THIS_LIB_NAME)/util/abstract + +kmpginclude_HEADERS = abs_thread.h threadQueue.h + + +libutilabstract_la_SOURCES = abs_thread_sdl.cpp threadQueue.cpp + diff --git a/mpeglib/lib/util/abstract/abs_thread.h b/mpeglib/lib/util/abstract/abs_thread.h new file mode 100644 index 00000000..f65445d8 --- /dev/null +++ b/mpeglib/lib/util/abstract/abs_thread.h @@ -0,0 +1,123 @@ +/* + abstraction for threads + 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 __ABS_THREAD_H +#define __ABS_THREAD_H + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/** + This passed alle pthread_xxx calls to this interface, thus + it can be easier replaced with other thread "layers" + + All posix pthread calls are conveterd to abs_thread. +*/ + +extern "C" { +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +} + +#define _ABS_BUSY EBUSY + +#ifndef SDL_WRAPPER +// definitions for direct pthread support +#include <pthread.h> + +typedef pthread_mutex_t abs_thread_mutex_t; +typedef pthread_cond_t abs_thread_cond_t; +typedef pthread_t abs_thread_t; + + + +#define abs_thread_cond_init(cond) pthread_cond_init(cond,NULL) +#define abs_thread_cond_destroy(cond) pthread_cond_destroy(cond) +#define abs_thread_cond_signal(cond) pthread_cond_signal(cond) +#define abs_thread_cond_wait(cond,mutex) pthread_cond_wait(cond,mutex) + +// CREATE / JOIN THREAD + +#define abs_thread_create(thread,func,arg) pthread_create(thread,NULL,func,arg) +#define abs_thread_join(th,thread_return) pthread_join(th,thread_return) + +// MUTEX FUNCTIONS + +#define abs_thread_mutex_lock(mutex) pthread_mutex_lock(mutex) +#define abs_thread_mutex_unlock(mutex) pthread_mutex_unlock(mutex) +#define abs_thread_mutex_init(mutex) pthread_mutex_init(mutex,NULL) +#define abs_thread_mutex_destroy(mutex) pthread_mutex_destroy(mutex) + +#endif +// not SDL_WRAPPER + +#ifdef SDL_WRAPPER + + +// SDL SUPPORT DISABLED + +#if defined WIN32 + #include <SDL_thread.h> + #include <SDL_mutex.h> +#else + #include <SDL/SDL_thread.h> + #include <SDL/SDL_mutex.h> +#endif + + +typedef SDL_mutex* abs_thread_mutex_t; +typedef SDL_cond* abs_thread_cond_t; +typedef SDL_Thread* abs_thread_t; + +// SIGNAL FUNCTIONS +// note we have _no_ cond attribut (not needed) +int abs_thread_cond_init(abs_thread_cond_t* cond); +int abs_thread_cond_destroy(abs_thread_cond_t *cond); + +int abs_thread_cond_signal(abs_thread_cond_t* cond); + +int abs_thread_cond_wait(abs_thread_cond_t* cond, + abs_thread_mutex_t *mutex); +// CREATE / JOIN THREAD +// Note: we have thread attribute +int abs_thread_create(abs_thread_t* thread, + void * (*start_routine)(void *), void * arg); + +int abs_thread_join(abs_thread_t th, + void **thread_return); + + +// MUTEX FUNCTIONS + +int abs_thread_mutex_lock(abs_thread_mutex_t *mutex); +int abs_thread_mutex_trylock(abs_thread_mutex_t *mutex); +int abs_thread_mutex_unlock(abs_thread_mutex_t *mutex); +// not attribute! +int abs_thread_mutex_init(abs_thread_mutex_t *mutex); + +int abs_thread_mutex_destroy(abs_thread_mutex_t *mutex); + + + +#endif +//SDL_WRAPPER + + + +#endif + + diff --git a/mpeglib/lib/util/abstract/abs_thread_sdl.cpp b/mpeglib/lib/util/abstract/abs_thread_sdl.cpp new file mode 100644 index 00000000..13c9ce6c --- /dev/null +++ b/mpeglib/lib/util/abstract/abs_thread_sdl.cpp @@ -0,0 +1,89 @@ +/* + abstraction for threads + 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 "abs_thread.h" + + +// START SDL + + +#ifdef SDL_WRAPPER + + + +int abs_thread_cond_init(abs_thread_cond_t* cond) { + *cond=SDL_CreateCond(); + return (*cond != NULL); +} + +int abs_thread_cond_destroy(abs_thread_cond_t *cond) { + SDL_DestroyCond(*cond); + return true; +} + + +int abs_thread_cond_signal(abs_thread_cond_t* cond) { + + return SDL_CondSignal(*cond); +} + + +int abs_thread_cond_wait(abs_thread_cond_t* cond, + abs_thread_mutex_t* mutex) { + SDL_CondWait(*cond,*mutex); + return true; +} + + +// CREATE / JOIN THREAD +int abs_thread_create(abs_thread_t* thread, + void * (*start_routine)(void *), void * arg) { + int (*func)(void *); + func=(int (*)(void *))start_routine; + *thread=SDL_CreateThread(func,arg); + return (*thread != NULL); +} + +int abs_thread_join(abs_thread_t th, + void **thread_return) { + SDL_WaitThread(th,(int*)*thread_return); + return true; +} + + +// MUTEX FUNCTIONS + +int abs_thread_mutex_lock(abs_thread_mutex_t *mutex) { + return SDL_LockMutex(*mutex); +} + + +int abs_thread_mutex_unlock(abs_thread_mutex_t *mutex) { + return SDL_UnlockMutex(*mutex); +} + + +int abs_thread_mutex_init(abs_thread_mutex_t *mutex) { + *mutex=SDL_CreateMutex(); + return true; +} + + +int abs_thread_mutex_destroy(abs_thread_mutex_t *mutex) { + SDL_DestroyMutex(*mutex); + return true; +} + + + +#endif diff --git a/mpeglib/lib/util/abstract/threadQueue.cpp b/mpeglib/lib/util/abstract/threadQueue.cpp new file mode 100644 index 00000000..1b130ba9 --- /dev/null +++ b/mpeglib/lib/util/abstract/threadQueue.cpp @@ -0,0 +1,108 @@ +/* + fifo waitqueue for threads.(Multi-in, single out) + 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 "threadQueue.h" + +#define _MAX_THREAD_IN_QUEUE 5 + +#include <iostream> + +using namespace std; + +// +// WaitThreadEntry class [START] +// + +WaitThreadEntry::WaitThreadEntry() { + abs_thread_cond_init(&waitCond); +} + + +WaitThreadEntry::~WaitThreadEntry() { + abs_thread_cond_destroy(&waitCond); +} + +// +// WaitThreadEntry class [END] +// + + +ThreadQueue::ThreadQueue() { + waitThreadEntries=new WaitThreadEntry* [_MAX_THREAD_IN_QUEUE]; + int i; + for(i=0;i<_MAX_THREAD_IN_QUEUE;i++) { + waitThreadEntries[i]=new WaitThreadEntry(); + } + abs_thread_mutex_init(&queueMut); + insertPos=0; + removePos=0; + size=0; +} + + +ThreadQueue::~ThreadQueue() { + abs_thread_mutex_lock(&queueMut); + if (size != 0) { + cout << "Aieee! Make sure that all threads are out of ThreadQueue"<<endl; + exit(0); + } + int i; + for(i=0;i<_MAX_THREAD_IN_QUEUE;i++) { + delete waitThreadEntries[i]; + } + delete [] waitThreadEntries; + abs_thread_mutex_unlock(&queueMut); + abs_thread_mutex_destroy(&queueMut); +} + + +void ThreadQueue::waitForExclusiveAccess() { + abs_thread_mutex_lock(&queueMut); + if (size == 0) { + abs_thread_mutex_unlock(&queueMut); + return; + } + // wait + size++; + if (size == _MAX_THREAD_IN_QUEUE) { + cout << "Aieee! ThreadQueue can only buffer:"<<_MAX_THREAD_IN_QUEUE<<endl; + exit(0); + } + abs_thread_cond_t* waitCond=&(waitThreadEntries[insertPos]->waitCond); + insertPos++; + // wrap counter + if (insertPos == _MAX_THREAD_IN_QUEUE) { + insertPos=0; + } + abs_thread_cond_wait(waitCond,&queueMut); + abs_thread_mutex_unlock(&queueMut); +} + + +void ThreadQueue::releaseExclusiveAccess() { + abs_thread_mutex_lock(&queueMut); + if (size == 0) { + abs_thread_mutex_unlock(&queueMut); + return; + } + // wake up next thread + abs_thread_cond_t* waitCond=&(waitThreadEntries[removePos]->waitCond); + removePos++; + // wrap counter + if (removePos == _MAX_THREAD_IN_QUEUE) { + removePos=0; + } + size--; + abs_thread_cond_signal(waitCond); + abs_thread_mutex_unlock(&queueMut); +} + diff --git a/mpeglib/lib/util/abstract/threadQueue.h b/mpeglib/lib/util/abstract/threadQueue.h new file mode 100644 index 00000000..4c650e21 --- /dev/null +++ b/mpeglib/lib/util/abstract/threadQueue.h @@ -0,0 +1,74 @@ +/* + fifo waitqueue for threads.(Multi-in, single out) + 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 __THREADQUEUE_H +#define __THREADQUEUE_H + + +#include "abs_thread.h" + +class WaitThreadEntry { + public: + WaitThreadEntry(); + ~WaitThreadEntry(); + + abs_thread_cond_t waitCond; +}; + +/** + This class can be used as a general purpuse wrapper to + make C++ classes thread safe. + Mpeglib uses for every decoder a single thread which + reads from the input and write to one output type (video/audio) + To make the input and output classes thread safe you have + two solutions. First you can try to do it in every class + itsself, this is much work and needs understanding of + threads or you can use this wrapper class. + Normally you don't need two threads in one class, only + for the audio/video sync this is necessary, but for + the inputstream (file,http,..) this not necessary. + For the output this is the same. + This class offers two methods. waitForExclusiceAcess() + and releaseExlusiveAcess. Internally the thread who + calls waitFor.. in enqueued (if it does not get the exclusive + access) the thread who have the exclusive access calls + sometimes release.. with then pass the exclusive access + to the next thread. + Why it is needed? + Because we access the input/output streams from different + threads. A user of mpeglib may want to set mpeg video + in fullscreen mode, this means two threads call + methods in the output classes including: closing windows, + resizing windows ... now this is safley possible when + the threadSafeInputStream / threadSafeoutputStream wrappers + are used, which forward the calls to the real classes. +*/ + +class ThreadQueue { + + abs_thread_mutex_t queueMut; + int insertPos; + int removePos; + int size; + WaitThreadEntry** waitThreadEntries; + + public: + ThreadQueue(); + ~ThreadQueue(); + + void waitForExclusiveAccess(); + void releaseExclusiveAccess(); + +}; + +#endif diff --git a/mpeglib/lib/util/audio/Makefile.am b/mpeglib/lib/util/audio/Makefile.am new file mode 100644 index 00000000..968d1d46 --- /dev/null +++ b/mpeglib/lib/util/audio/Makefile.am @@ -0,0 +1,18 @@ + +# ---- @OS_TYPE@/@ARCH_TYPE@ ---- + +INCLUDES = $(all_includes) + +EXTRA_DIST = audioIO_AIX.cpp audioIO_BeOS.cpp \ + audioIO_HPUX.cpp \ + audioIO_IRIX.cpp audioIO_Linux.cpp \ + audioIO_SunOS.cpp audioIO_SDL.cpp + +noinst_HEADERS = audioIO.h dspWrapper.h + +noinst_LTLIBRARIES = libaudio.la + +libaudio_la_SOURCES = audioIO.cpp dspWrapper.cpp + + + diff --git a/mpeglib/lib/util/audio/audioIO.cpp b/mpeglib/lib/util/audio/audioIO.cpp new file mode 100644 index 00000000..d066210f --- /dev/null +++ b/mpeglib/lib/util/audio/audioIO.cpp @@ -0,0 +1,49 @@ + + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + + +#ifdef SDL_WRAPPER + + #include "audioIO_SDL.cpp" + +// +// If native sound is defined compiled for that +// + +#else + + +#ifdef OS_AIX + #include "audioIO_AIX.cpp" +#endif + +#ifdef OS_Linux + #include "audioIO_Linux.cpp" +#endif + +#ifdef OS_BSD + #include "audioIO_Linux.cpp" +#endif + +#if defined(OS_IRIX) || defined(OS_IRIX64) + #include "audioIO_IRIX.cpp" +#endif + +#ifdef OS_HPUX + #include "audioIO_HPUX.cpp" +#endif + +#ifdef OS_SunOS + #include "audioIO_SunOS.cpp" +#endif + +#ifdef __BEOS__ + #include "audioIO_BeOS.cpp" +#endif + + +#endif diff --git a/mpeglib/lib/util/audio/audioIO.h b/mpeglib/lib/util/audio/audioIO.h new file mode 100644 index 00000000..41e1ceb2 --- /dev/null +++ b/mpeglib/lib/util/audio/audioIO.h @@ -0,0 +1,80 @@ + + +#ifndef __AUDIOIO_H +#define __AUDIOIO_H + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + + + +extern "C" { +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <stdlib.h> +} + +/* AUSUZ should be the amount of data your audio device will accept after it + * has said it is ready to receive data. ie when the device is ready + * for data it + * will accept it without blocking. It must also be a multiple of 128 + */ + +#ifdef OS_AIX + #define AUSIZ 32768 +#endif + +#ifdef OS_Linux + extern int AUSIZ; +#endif + +#ifdef OS_BSD + #define AUSIZ 32768 +#endif + +#if defined(OS_IRIX) || defined(OS_IRIX64) + #define AUSIZ 32768 +#endif + +#ifdef OS_HPUX + #define AUSIZ 4096 +#endif + +#ifdef OS_SunOS + #define AUSIZ 4096 +#endif + + +#ifdef DEBUG + #define DB(type,cmd) if (debugFlags.type) { cmd ; } +#else + #define DB(type,cmd) +#endif + + + + +//Prototypes: + +int audioConstruct(); +void audioDestruct(); + + + +int audioOpen(); +void audioClose(); +void audioInit(int sampleSize,int frequency, int stereo,int sign, int bigendian); + + +int mixerOpen(); +void mixerClose(); +void mixerSetVolume(int volumeLeft,int volumeRight); + +int audioWrite(char *buffer, int count); +int getAudioFd(); +int getAudioBufferSize(); + +#endif diff --git a/mpeglib/lib/util/audio/audioIO_AIX.cpp b/mpeglib/lib/util/audio/audioIO_AIX.cpp new file mode 100644 index 00000000..15316852 --- /dev/null +++ b/mpeglib/lib/util/audio/audioIO_AIX.cpp @@ -0,0 +1,533 @@ +/* + * AIX audio - griff@acm.org 02aug2000 + * tested on 43P 260 with builtin audio + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/time.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +/* A conflict within AIX 4.3.3 <sys/> headers and probably others as well. + * I guess nobody ever uses audio... Shame over AIX header files. */ +#include <sys/machine.h> +#undef BIG_ENDIAN +#include <sys/audio.h> + +static int audio_fd; + +static void debugUpdate( unsigned long& flags, long& bsize ); + +#ifndef AUDIO_BIG_ENDIAN +#define AUDIO_BIG_ENDIAN BIG_ENDIAN +#endif + + + +int audioConstruct() { + printf("audioConstruct AIX ********\n"); + audio_fd=-1; + return true; +} + + +void audioDestruct() { + +} + +int audioOpen() +{ + char devname[14]; + for ( int dev=0; dev<4; dev++ ) + { + for ( int chan=1; chan<8; chan++ ) + { + sprintf(devname,"/dev/paud%d/%d",dev,chan); + audio_fd = open (devname, O_WRONLY, 0); + if ( audio_fd >= 0 ) + { + return 1; + } + sprintf(devname,"/dev/baud%d/%d",dev,chan); + audio_fd = open (devname, O_WRONLY, 0); + if ( audio_fd >= 0 ) + { + return 1; + } + } + } + + fprintf(stderr, "Could not open AIX audio device, faking\n" ); + return 1; +} + +int getAudioBufferSize() +{ + audio_buffer paud_bufinfo; + + if( audio_fd < 0 ) return 1024*65; + + if ( ioctl(audio_fd, AUDIO_BUFFER, &paud_bufinfo) < 0 ) + { + perror("ioctl getAudioBufferSize using default"); + return 1024*65; + } + + /* + * Do you need the total capacity or the current capacity? + * This is the total capacity: + */ + return paud_bufinfo.write_buf_cap; + /* + * This is the current capacity: + * return (paud_bufinfo.write_buf_cap - paud_bufinfo.write_buf_size); + */ +} + +void audioInit(int sampleSize,int frequency, int stereo, int sign, int bigendian ) +{ + // int format; + int bytes_per_sample; + audio_init paud_init; + audio_buffer paud_bufinfo; + // audio_status paud_status; + audio_control paud_control; + audio_change paud_change; + + if( audio_fd < 0 ) return; + + /* + * We can't set the buffer size - just ask the device for the maximum + * that we can have. + */ + if ( ioctl(audio_fd, AUDIO_BUFFER, &paud_bufinfo) < 0 ) + { + perror("Couldn't get audio buffer information"); + return; + } + + /* + * Fields in the audio_init structure: + * + * Ignored by us: + * + * paud.loadpath[LOAD_PATH]; * DSP code to load, MWave chip only? + * paud.slot_number; * slot number of the adapter + * paud.device_id; * adapter identification number + * + * Input: + * + * paud.srate; * the sampling rate in Hz + * paud.bits_per_sample; * 8, 16, 32, ... + * paud.bsize; * block size for this rate + * paud.mode; * ADPCM, PCM, MU_LAW, A_LAW, SOURCE_MIX + * paud.channels; * 1=mono, 2=stereo + * paud.flags; * FIXED - fixed length data + * * LEFT_ALIGNED, RIGHT_ALIGNED (var len only) + * * TWOS_COMPLEMENT - 2's complement data + * * SIGNED - signed? comment seems wrong in sys/audio.h + * * BIG_ENDIAN + * paud.operation; * PLAY, RECORD + * + * Output: + * + * paud.flags; * PITCH - pitch is supported + * * INPUT - input is supported + * * OUTPUT - output is supported + * * MONITOR - monitor is supported + * * VOLUME - volume is supported + * * VOLUME_DELAY - volume delay is supported + * * BALANCE - balance is supported + * * BALANCE_DELAY - balance delay is supported + * * TREBLE - treble control is supported + * * BASS - bass control is supported + * * BESTFIT_PROVIDED - best fit returned + * * LOAD_CODE - DSP load needed + * paud.rc; * NO_PLAY - DSP code can't do play requests + * * NO_RECORD - DSP code can't do record requests + * * INVALID_REQUEST - request was invalid + * * CONFLICT - conflict with open's flags + * * OVERLOADED - out of DSP MIPS or memory + * paud.position_resolution; * smallest increment for position + */ + + paud_init.srate = frequency; + paud_init.mode = PCM; + paud_init.operation = PLAY; + paud_init.channels = (stereo?2:1); + + /* + * options in AIX: + * paud_init.bits_per_sample: 8 | 16 + * paud_init.flags: AUDIO_BIG_ENDIAN (not used here) + * SIGNED (always used here) + * TWOS_COMPLEMENT (always on for Linux dsp porting?) + * FIXED <- that's right for SDL + * or LEFT_ALIGNED <- that's right for mpeglib + * or RIGHT_ALIGNED + * paud_init.bsize: sample byte size, + * bits_per_sample * (stereo?2:1) - for SDL + * bits_per_sample * (stereo?2:1) * 2 - for mpeglib + */ + if ( sampleSize == 8 ) + { + /* AFMT_S8 in linux dsp */ + bytes_per_sample = 2; // why not 1 ? + paud_init.bits_per_sample = 8; + paud_init.flags = TWOS_COMPLEMENT | LEFT_ALIGNED; + } + else + { + /* AFMT_S16_LE in linux dsp */ + bytes_per_sample = 4; // why not 2 ? + paud_init.bits_per_sample = 16; + paud_init.flags = TWOS_COMPLEMENT | LEFT_ALIGNED; + } + if( sign ) paud_init.flags |= SIGNED; + if( bigendian ) paud_init.flags |= AUDIO_BIG_ENDIAN; + + paud_init.bsize = bytes_per_sample * (stereo?2:1); + +#if 0 + debugUpdate(paud_init.flags, paud_init.bsize); + + printf("CG: sampleSize = %d\n", sampleSize); + printf("CG: frequency = %d\n", frequency); + printf("CG: stereo = %s\n", (stereo)?"y":"n"); + printf("CG: mode = %s\n", "PCM"); + printf("CG: channels = %d\n", paud_init.channels); + printf("CG: bsize = %d\n", paud_init.bsize); + printf("CG: bits_per_sample = %d\n", paud_init.bits_per_sample); + printf("CG: flags & BIG_ENDIAN = %s\n", ((paud_init.flags&AUDIO_BIG_ENDIAN)?"y":"n")); + printf("CG: flags & SIGNED = %s\n", ((paud_init.flags&SIGNED)?"y":"n")); + printf("CG: flags & TWOS_COMPLEMENT = %s\n", ((paud_init.flags&TWOS_COMPLEMENT)?"y":"n")); + printf("CG: flags & FIXED = %s\n", ((paud_init.flags&FIXED)?"y":"n")); + printf("CG: flags & LEFT_ALIGNED = %s\n", ((paud_init.flags&LEFT_ALIGNED)?"y":"n")); + printf("CG: flags & RIGHT_ALIGNED = %s\n", ((paud_init.flags&RIGHT_ALIGNED)?"y":"n")); +#endif + + /* + * We know the buffer size and the max number of subsequent writes + * that can be pending. If more than one can pend, allow the application + * to do something like double buffering between our write buffer and + * the device's own buffer that we are filling with write() anyway. + * + * We can calculate the number of samples that fit into the audio + * device buffer if that is necessary: + * + * samples_capacity = paud_bufinfo.write_buf_cap + * / bytes_per_sample + * / (stereo?2:1); + * if ( paud_bufinfo.request_buf_cap != 1 ) samples_capacity /= 2; + */ + + /* + * The AIX paud device init can't modify the values of the audio_init + * structure that we pass to it. So we don't need any recalculation + * of this stuff and no reinit call as in linux SDL dsp and dma code. + * + * /dev/paud supports all of the encoding formats, so we don't need + * to do anything like reopening the device, either. + */ + if ( ioctl(audio_fd, AUDIO_INIT, &paud_init) < 0 ) + { + switch ( paud_init.rc ) + { + case 1 : + perror("Couldn't set audio format: DSP can't do play requests"); + return; + break; + case 2 : + perror("Couldn't set audio format: DSP can't do record requests"); + return; + break; + case 4 : + perror("Couldn't set audio format: request was invalid"); + return; + break; + case 5 : + perror("Couldn't set audio format: conflict with open's flags"); + return; + break; + case 6 : + perror("Couldn't set audio format: out of DSP MIPS or memory"); + return; + break; + default : + perror("Couldn't set audio format: not documented in sys/audio.h"); + return; + break; + } + } + + /* + * Set some parameters: full volume, first speaker that we can find. + * Ignore the other settings for now. + */ + paud_change.input = AUDIO_IGNORE; /* the new input source */ + paud_change.output = OUTPUT_1; + /* EXTERNAL_SPEAKER, + * INTERNAL_SPEAKER, + * OUTPUT_1 */ + paud_change.monitor = AUDIO_IGNORE; /* the new monitor state */ + paud_change.volume = 0x7fffffff; /* volume level [0-0x7fffffff] */ + paud_change.volume_delay = AUDIO_IGNORE; /* the new volume delay */ + paud_change.balance = 0x3fffffff; /* the new balance */ + paud_change.balance_delay = AUDIO_IGNORE; /* the new balance delay */ + paud_change.treble = AUDIO_IGNORE; /* the new treble state */ + paud_change.bass = AUDIO_IGNORE; /* the new bass state */ + paud_change.pitch = AUDIO_IGNORE; /* the new pitch state */ + + paud_control.ioctl_request = AUDIO_CHANGE; + paud_control.request_info = (char*)&paud_change; + if ( ioctl(audio_fd, AUDIO_CONTROL, &paud_control) < 0 ) + { + perror("Can't change audio display settings (ignoring)" ); + } + + /* + * Tell the device to expect data. Actual start will wait for + * the first write() call. + */ + paud_control.ioctl_request = AUDIO_START; + paud_control.position = 0; + if ( ioctl(audio_fd, AUDIO_CONTROL, &paud_control) < 0 ) + { + perror("Can't start audio play"); + return; + } +} + + +void audioSetVolume(int volume) +{ + long vol = (long)(volume/100.0) * 0x7fffffff; + if( audio_fd < 0 ) return; + + audio_control paud_control; + audio_change paud_change; + + paud_change.input = AUDIO_IGNORE; /* the new input source */ + paud_change.output = OUTPUT_1; /* EXTERNAL_SPEAKER,INTERNAL_SPEAKER, + OUTPUT_1 */ + paud_change.monitor = AUDIO_IGNORE; /* the new monitor state */ + paud_change.volume = vol; /* volume level [0-0x7fffffff] */ + paud_change.volume_delay = AUDIO_IGNORE; /* the new volume delay */ + paud_change.balance = AUDIO_IGNORE; /* the new balance */ + paud_change.balance_delay = AUDIO_IGNORE; /* the new balance delay */ + paud_change.treble = AUDIO_IGNORE; /* the new treble state */ + paud_change.bass = AUDIO_IGNORE; /* the new bass state */ + paud_change.pitch = AUDIO_IGNORE; /* the new pitch state */ + + paud_control.ioctl_request = AUDIO_CHANGE; + paud_control.request_info = (char*)&paud_change; + + if ( ioctl(audio_fd, AUDIO_CONTROL, &paud_control) < 0 ) + { + perror("Change audio volume failed"); + } +} + +void audioFlush() +{ + if( audio_fd < 0 ) return; + + if ( ioctl(audio_fd, AUDIO_WAIT, NULL) < 0 ) + { + perror("Flush audio buffers failed"); + } +} + +void audioClose() +{ + if( audio_fd < 0 ) return; + + if ( ioctl(audio_fd, AUDIO_WAIT, NULL) < 0 ) + { + perror("Flush audio buffers failed"); + } + close(audio_fd); +} + +int audioWrite(char *buffer, int count) +{ + int written = write(audio_fd, buffer, count); + if( written < count ) + { + return count; + } + + return written; +} + +int +getAudioFd() +{ + return audio_fd; +} + +int mixerOpen() +{ + return true; +} + +void mixerClose() +{ +} + +void mixerSetVolume(int leftVolume,int rightVolume) +{ + long balance; + + if( audio_fd < 0 ) return; + + balance = 2 * (leftVolume-rightVolume) / (leftVolume+rightVolume); + balance = 0x3fffffff + balance*0x3fffffff; + + audio_control paud_control; + audio_change paud_change; + + paud_change.input = AUDIO_IGNORE; /* the new input source */ + paud_change.output = OUTPUT_1; /* EXTERNAL_SPEAKER,INTERNAL_SPEAKER, + OUTPUT_1 */ + paud_change.monitor = AUDIO_IGNORE; /* the new monitor state */ + paud_change.volume = AUDIO_IGNORE; /* volume level [0-0x7fffffff] */ + paud_change.volume_delay = AUDIO_IGNORE; /* the new volume delay */ + paud_change.balance = balance; /* the new balance */ + paud_change.balance_delay = AUDIO_IGNORE; /* the new balance delay */ + paud_change.treble = AUDIO_IGNORE; /* the new treble state */ + paud_change.bass = AUDIO_IGNORE; /* the new bass state */ + paud_change.pitch = AUDIO_IGNORE; /* the new pitch state */ + + paud_control.ioctl_request = AUDIO_CHANGE; + paud_control.request_info = (char*)&paud_change; + + if ( ioctl(audio_fd, AUDIO_CONTROL, &paud_control) < 0 ) + { + perror("Change audio volume failed"); + } +} + +static void debugUpdate( unsigned long& flags, long& bsize ) +{ + const char* g; + + g = getenv("AUDIO_BIG_ENDIAN"); + if ( g ) + { + int i = atoi(g); + if ( i == 1 ) + { + flags |= AUDIO_BIG_ENDIAN; + } + else if ( i == 0 ) + { + flags &= ~AUDIO_BIG_ENDIAN; + } + else + { + printf("CG: bad AUDIO_BIG_ENDIAN env variable %s\n", g); + } + } + + g = getenv("SIGNED"); + if ( g ) + { + int i = atoi(g); + if ( i == 1 ) + { + flags |= SIGNED; + } + else if ( i == 0 ) + { + flags &= ~SIGNED; + } + else + { + printf("CG: bad SIGNED env variable %s\n", g); + } + } + + g = getenv("TWOS_COMPLEMENT"); + if ( g ) + { + int i = atoi(g); + if ( i == 1 ) + { + flags |= TWOS_COMPLEMENT; + } + else if ( i == 0 ) + { + flags &= ~TWOS_COMPLEMENT; + } + else + { + printf("CG: bad TWOS_COMPLEMENT env variable %s\n", g); + } + } + + g = getenv("FIXED"); + if ( g ) + { + int i = atoi(g); + if ( i == 1 ) + { + flags |= FIXED; + } + else if ( i == 0 ) + { + flags &= ~FIXED; + } + else + { + printf("CG: bad FIXED env variable %s\n", g); + } + } + + g = getenv("LEFT_ALIGNED"); + if ( g ) + { + int i = atoi(g); + if ( i == 1 ) + { + flags |= LEFT_ALIGNED; + } + else if ( i == 0 ) + { + flags &= ~LEFT_ALIGNED; + } + else + { + printf("CG: bad LEFT_ALIGNED env variable %s\n", g); + } + } + + g = getenv("RIGHT_ALIGNED"); + if ( g ) + { + int i = atoi(g); + if ( i == 1 ) + { + flags |= RIGHT_ALIGNED; + } + else if ( i == 0 ) + { + flags &= ~RIGHT_ALIGNED; + } + else + { + printf("CG: bad RIGHT_ALIGNED env variable %s\n", g); + } + } + + g = getenv("BSIZE"); + if ( g ) + { + bsize = atoi(g); + } +} + diff --git a/mpeglib/lib/util/audio/audioIO_BeOS.cpp b/mpeglib/lib/util/audio/audioIO_BeOS.cpp new file mode 100644 index 00000000..ae4cf5a1 --- /dev/null +++ b/mpeglib/lib/util/audio/audioIO_BeOS.cpp @@ -0,0 +1,227 @@ +// +// BeOS code for amp-0.7.4, (C) 1997 Andy Lo A Foe +// + + +#include <MediaKit.h> +#include <KernelKit.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "transform.h" +#include "audioIO.h" +#include "audio.h" + +// Define the streambuf size here. streambuf is used +// as a simple fit buffer. + +#define STREAMBUF_SIZE (32*1152) + +long bytes_in_streambuf; + +// streambuf definition and base indicator + +BSubscriber *the_sub; +BDACStream *the_stream; + +sem_id ok_to_read; +sem_id ok_to_write; + + +char streambuf[STREAMBUF_SIZE]; +char *readbase; + +static int au_vol = 100; + +// Define our own printout function since we are +// first writing in the streambuf (not needed, I think, +// but I don't know if the DACStream accepts a buffer +// size of 1152. Try it... + +void printout(void) +{ +if (A_WRITE_TO_FILE) { +#ifndef NO_BYTE_SWAPPING +int i,j; +short *ptr; + + if (nch==2) { + ptr=(short*)stereo_samples; + i=j=32 * 18 * 2; + } else { + ptr=(short*)mono_samples; + i=j=32 * 18; + } + + for (;i>=0;--i) + ptr[i] = ptr[i] << 8 | ptr[i] >> 8; +#endif + + if (nch==2) + fwrite(stereo_samples,1,sizeof stereo_samples,out_file); + else + fwrite(mono_samples,1,sizeof mono_samples,out_file); +} + + + if (A_AUDIO_PLAY) { + static char au_buf[STREAMBUF_SIZE]; + static int au_ptr =0, avail = 0; + static int num_smp; + static char *readbase = &au_buf[0]; + + // Write amount of samples to copy somewhere + num_smp = (nch == 2 ? sizeof stereo_samples : sizeof mono_samples); + + // Copy samples in the fit buffer + memcpy(au_buf+au_ptr,(nch == 2 ? (char *)stereo_samples : (char *)mono_samples), + num_smp); + + // Increase fit buffer pointer and available sample count + au_ptr+=num_smp; + avail+=num_smp; + + if (avail >= 4096) { // Are there enough smps to feed the stream? + audioWrite((char*)readbase,4096); // Feed it! + readbase+=4096; // Increase readbase + avail-=4096; // Decrease avail smps count + if (au_ptr == STREAMBUF_SIZE) { // At end of fit buffer? + au_ptr=0; // Reset all pointers + readbase=&au_buf[0]; + } + } + } + +} + + +// Fake Buffer functions, just to keep the sources clean, +// buffer.c should not be included in the link process... + +int AUDIO_BUFFER_SIZE; + +int +audioBufferOpen(int frequency, int stereo, int volume) +{ + audioOpen(frequency, stereo, volume); +} + + +inline void +audioBufferWrite(char *buf,int bytes) +{ + audioWrite(buf, bytes); +} + + +void +audioBufferClose() +{ + audioClose(); +} + + +int audioRead(char *buffer, int count) +{ + //printf("acquiring ok_to_read (%d bytes)\n", count); + if (acquire_sem(ok_to_read)==B_NO_ERROR) { + for (register int i=0; i < count;i++) { + *(buffer++)+=*(readbase++); + } + bytes_in_streambuf-=count; + + if (bytes_in_streambuf <= 0) { + release_sem(ok_to_write); + bytes_in_streambuf = 0; + } else { + release_sem(ok_to_read); + } + } + return (0); +} + + +bool stream_func(void *arg, char *buf, size_t count, void *header) +{ + audioRead(buf, count); + return TRUE; +} + +void audioOpen() { + readbase = &streambuf[0]; + + bytes_in_streambuf = 0; + + the_sub = new BSubscriber("amp DAC writer"); + the_stream = new BDACStream(); + + the_sub->Subscribe(the_stream); + + the_stream->SetSamplingRate(frequency); + + // Create semaphores + ok_to_read = create_sem(0, "read sem"); + ok_to_write = create_sem(1, "write sem"); + +} + +void audioInit(int sampleSize,int frequency, int stereo) +{ + + // Initialize the streambuf + bytes_in_streambuf = 0; + memset(&streambuf, 0, STREAMBUF_SIZE); + + + // Enter the stream + the_sub->EnterStream(NULL, TRUE, NULL, stream_func, NULL, TRUE); +} + + +void audioSetVolume(int volume) +{ + if (volume > 128) // This allows for a modest volume boost + volume = 128; + au_vol = volume; +} + + +void audioClose() +{ + the_sub->ExitStream(TRUE); + the_sub->Unsubscribe(); + + delete_sem(ok_to_read); + delete_sem(ok_to_write); + + delete the_sub; + delete the_stream; +} + + +// audioWrite is called from the player thread + +int audioWrite(char *buffer, int count) +{ + //printf("acquiring ok_to_write (%d bytes)\n", count); + if(acquire_sem(ok_to_write)==B_NO_ERROR) + { + memcpy(&streambuf, buffer, count); + + if (au_vol != 100) { // Handle volume scaling here + short *b=(short *)&streambuf; + for (int i=0; i < count/2; i++) { + int v=((int)b[i]*au_vol)/100; + b[i]=(v>32767) ? 32767 : ((v<-32768) ? -32768 : v); + } + } + + bytes_in_streambuf = count; + readbase = &streambuf[0]; + + release_sem(ok_to_read); + } + return 0; +} + diff --git a/mpeglib/lib/util/audio/audioIO_HPUX.cpp b/mpeglib/lib/util/audio/audioIO_HPUX.cpp new file mode 100644 index 00000000..ae07a148 --- /dev/null +++ b/mpeglib/lib/util/audio/audioIO_HPUX.cpp @@ -0,0 +1,190 @@ +/* this file is a part of amp software, (C) tomislav uzelac 1996,1997 + + Origional code by: Lutz Vieweg + Modified by: + * Andrew Richards - moved code from audio.c + + */ + + +#include <sys/audio.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <sys/lock.h> +#include <unistd.h> +#include <stdio.h> +#include "audioIO.h" + +/* declare these static to effectively isolate the audio device */ + +static int audio_fd; + + +/* audioOpen() */ +/* should open the audio device, perform any special initialization */ +/* Set the frequency, no of channels and volume. Volume is only set if */ +/* it is not -1 */ + +void audioOpen() { + if ((audio_fd = open("/dev/audio",O_RDWR))==-1) + die(" unable to open the audio device\n"); + + DB(audio, msg("Audio device opened on %d\n",audio_fd); ) + } + + +void +audioInit(int sampleSize,int frequency, int stereo) +{ + int flags; + int failed = 0; + int volume=100; + + if ((flags = fcntl (audio_fd, F_GETFL, 0)) < 0) { + die("unable to set non-blocking mode for /dev/audio\n"); + } + flags |= O_NDELAY; + if (fcntl (audio_fd, F_SETFL, flags) < 0) { + die("unable to set non-blocking mode for /dev/audio\n"); + } + + if ( ioctl(audio_fd, AUDIO_SET_DATA_FORMAT, AUDIO_FORMAT_LINEAR16BIT) < 0 || + ioctl(audio_fd, AUDIO_SET_CHANNELS, stereo ? 2 : 1) < 0 || + ioctl(audio_fd, AUDIO_SET_OUTPUT, AUDIO_OUT_SPEAKER | AUDIO_OUT_HEADPHONE + | AUDIO_OUT_LINE) < 0 || + ioctl(audio_fd, AUDIO_SET_SAMPLE_RATE, frequency) < 0) { + failed = -1; + } + if (volume != -1) { + struct audio_describe description; + struct audio_gains gains; + float fvolume = (float)volume / 100.0f; + if (ioctl(audio_fd, AUDIO_DESCRIBE, &description)) { + failed = -1; + } + if (ioctl (audio_fd, AUDIO_GET_GAINS, &gains)) { + failed = -1; + } + + gains.transmit_gain = (int)((float)description.min_transmit_gain + + (float)(description.max_transmit_gain + - description.min_transmit_gain) + * fvolume); + + /* gains.monitor_gain = description.min_monitor_gain; */ /* don't monitor ! */ + + if (ioctl (audio_fd, AUDIO_SET_GAINS, &gains)) { + failed = -1; + } + } + + if (ioctl(audio_fd, AUDIO_SET_TXBUFSIZE, 4096 * 8)) { + failed = -1; + } + if (failed) + die(" unable to setup /dev/audio\n"); +} + + +/* audioSetVolume - only code this if your system can change the volume while */ +/* playing. sets the output volume 0-100 */ + +void +audioSetVolume(int volume) +{ + struct audio_describe description; + struct audio_gains gains; + int failed = 0; + float fvolume = ((float)volume) / 100.0f; + if (ioctl(audio_fd, AUDIO_DESCRIBE, &description)) { + failed = -1; + } + if (ioctl (audio_fd, AUDIO_GET_GAINS, &gains)) { + failed = -1; +} + + gains.transmit_gain = (int)((float)description.min_transmit_gain + + (float)(description.max_transmit_gain + - description.min_transmit_gain) + * fvolume); + if (ioctl (audio_fd, AUDIO_SET_GAINS, &gains)) { + failed = -1; + } + + /* could evaluate "failed" here - but who cares? */ + + DB(audio, msg("volume set to %d%%\n",volume); ) + +} + +/* audioFlush() */ +/* should flush the audio device */ + +inline void +audioFlush() +{ + DB(audio, msg("audio: flush %d\n",audio_fd) ); +} + + +/* audioClose() */ +/* should close the audio device and perform any special shutdown */ + +void +audioClose() +{ + close(audio_fd); + DB(audio, msg("audio: closed %d\n",audio_fd) ); +} + + +/* audioWrite */ +/* writes count bytes from buffer to the audio device */ +/* returns the number of bytes actually written */ + +int audioWrite(char *buffer, int count) +{ + DB(audio, msg("audio: Writing %d bytes to audio descriptor %d\n",count,getAudioFd()) ); + return(write(audio_fd,buffer,count)); +} + + +/* Let buffer.c have the audio descriptor so it can select on it. This means */ +/* that the program is dependent on an file descriptor to work. Should really */ +/* move the select's etc (with inlines of course) in here so that this is the */ +/* ONLY file which has hardware dependent audio stuff in it */ + +int +getAudioFd() +{ + return(audio_fd); +} + +/* + Try to set the priority of this process to a value which + allows us to play without buffering, thus saving memory + and avoiding cache-misses. + If we cannot get any priority high enough to allow for + undisturbed replay (because we don't have sufficient + privilege), return a zero, otherwise, return a one. +*/ +int audioSetPriority(void) { + + /* try to lock process in physical memory, just ignore if this fails */ + plock(PROCSHLIBLOCK); + + /* try to set a realtime-priority of 64 */ + if (-1 != rtprio(0, 64)) { + DB(audio, msg("using real-time priority\n"); ) + return 1; + } + + /* try to set a nice-level of -20 */ + if (-1 != nice(-20)) { + DB(audio, msg("using nice-level -20\n"); ) + return 1; + } + + DB(audio, msg("using buffered output\n"); ) + return 0; /* need to use a buffer */ +} diff --git a/mpeglib/lib/util/audio/audioIO_IRIX.cpp b/mpeglib/lib/util/audio/audioIO_IRIX.cpp new file mode 100644 index 00000000..8498a487 --- /dev/null +++ b/mpeglib/lib/util/audio/audioIO_IRIX.cpp @@ -0,0 +1,157 @@ +/* this file is a part of amp software, (C) tomislav uzelac 1996,1997 + + Origional code by: Karl Anders Oygard + Modified by: + * Andrew Richards - moved code from audio.c + + */ +#include <assert.h> +#include <unistd.h> +#include <stdio.h> +#include <dmedia/audio.h> +#include "audioIO.h" + +/* declare these static to effectively isolate the audio device */ + +static ALport audioport; +static ALconfig audioconfig; + + +/* audioOpen() */ +/* should open the audio device, perform any special initialization */ +/* Set the frequency, no of channels and volume. Volume is only set if */ +/* it is not -1 */ + + +void audioOpen() { + printf("sorry. The audio part for irix must be fixed. \n"); +} + +void +audioInit(int sampleSize,int frequency, int stereo) +{ + ALconfig audioconfig; + audioconfig = ALnewconfig(); + + if (!audioconfig) + die("out of memory\n"); + else { + long pvbuf[] = { AL_OUTPUT_COUNT, 0, AL_MONITOR_CTL, 0, AL_OUTPUT_RATE, 0}; + + if (ALgetparams(AL_DEFAULT_DEVICE, pvbuf, 6) < 0) + if (oserror() == AL_BAD_DEVICE_ACCESS) + die("couldn't access audio device\n"); + + if (pvbuf[1] == 0 && pvbuf[3] == AL_MONITOR_OFF) { + long al_params[] = { AL_OUTPUT_RATE, 0}; + + al_params[1] = frequency; + ALsetparams(AL_DEFAULT_DEVICE, al_params, 2); + } else + if (pvbuf[5] != frequency) + die("audio device is already in use with wrong sample output rate\n"); + + /* ALsetsampfmt(audioconfig, AL_SAMPFMT_TWOSCOMP); this is the default */ + /* ALsetwidth(audioconfig, AL_SAMPLE_16); this is the default */ + + if (!stereo) ALsetchannels(audioconfig, AL_MONO); + /* else ALsetchannels(audioconfig, AL_STEREO); this is the default */ + + ALsetqueuesize(audioconfig, AUSIZ * 2); + + audioport = ALopenport("amp", "w", audioconfig); + if (audioport == (ALport) 0) { + switch (oserror()) { + case AL_BAD_NO_PORTS: + die("system is out of ports\n"); + + case AL_BAD_DEVICE_ACCESS: + die("couldn't access audio device\n"); + + case AL_BAD_OUT_OF_MEM: + die("out of memory\n"); + } + exit(-1); + } + ALsetfillpoint(audioport, AUSIZ); + } +} + + +/* audioSetVolume - only code this if your system can change the volume while */ +/* playing. sets the output volume 0-100 */ + +void +audioSetVolume(int volume) +{ + long al_params[] = { AL_LEFT_SPEAKER_GAIN, 0, AL_RIGHT_SPEAKER_GAIN, 0}; + + al_params[1] = al_params[3] = volume * 100 / 255; + + ALsetparams(AL_DEFAULT_DEVICE, al_params, 4); +} + + +/* audioFlush() */ +/* should flush the audio device */ + +void +audioFlush() +{ + DB(audio, msg("audio: flush %d\n",audio_fd) ); +} + + +/* audioClose() */ +/* should close the audio device and perform any special shutdown */ + +void +audioClose() +{ +int write_fd; + + /* wait for all samples to be played */ + + write_fd = ALgetfd(audioport); + if (write_fd >= 0) { + fd_set write_fds; + + FD_ZERO(&write_fds); + FD_SET(write_fd, &write_fds); + + ALsetfillpoint(audioport, AUSIZ * 2); + select(write_fd + 1, NULL, &write_fds, NULL, NULL); + } + + /* now close it */ + + ALcloseport(audioport); + DB(audio, msg("audio: closed %d\n",audio_fd) ); +} + + +/* audioWrite */ +/* writes count bytes from buffer to the audio device */ +/* returns the number of bytes actually written */ + +int audioWrite(char *buffer, int count) +{ + if (ALwritesamps(audioport, buffer, count / 2) == 0) { + ALsetfillpoint(audioport, AUSIZ); + return(count); + } else + return 0; +} + +/* Let buffer.c have the audio descriptor so it can select on it. This + means that the program is dependent on an file descriptor to + work. Should really move the select's etc (with inlines of course) in + here so that this is the ONLY file which has hardware dependent audio + stuff in it. */ + +int +getAudioFd() +{ + return ALgetfd(audioport); +} + diff --git a/mpeglib/lib/util/audio/audioIO_Linux.cpp b/mpeglib/lib/util/audio/audioIO_Linux.cpp new file mode 100644 index 00000000..5ca9231c --- /dev/null +++ b/mpeglib/lib/util/audio/audioIO_Linux.cpp @@ -0,0 +1,220 @@ +/* this file is a part of amp software, (C) tomislav uzelac 1996,1997 + + Origional code by: tomislav uzelac + Modified by: + * Dan Nelson - BSD mods. + * Andrew Richards - moved code from audio.c and added mixer support etc + * Martin Vogt + */ + +/* Support for Linux and BSD sound devices */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> +#include "audioIO.h" +#include <stdlib.h> +#include <stdio.h> + +// +// Why all these different system cannot make a standard where this +// soundcard.h file is ? +// +#if defined(HAVE_SYS_SOUNDCARD_H) + #undef AUSIZ + #undef HAVE_SYS_SOUNDCARD_H + #include <sys/soundcard.h> +#elif defined(HAVE_MACHINE_SOUNDCARD_H) + #undef AUSIZ + #include <machine/soundcard.h> +#elif defined(__NetBSD__) + #undef AUSIZ + #include <soundcard.h> +#else + // fallback: + #include <linux/soundcard.h> +#endif + + +/* optimal fragment size */ + +int AUSIZ = 0; + +// declare these static to effectively isolate the audio device + +static int audio_fd; +static int mixer_fd; +static int volumeIoctl; + + + +int audioConstruct() { + audio_fd=-1; + mixer_fd=-1; + return true; +} + + +void audioDestruct() { + +} + + + +/* + should open the audio device, perform any special initialization +*/ +int audioOpen() { + audio_fd = open ("/dev/dsp", O_WRONLY, 0); + if (audio_fd < 0) { + perror("Unable to open the audio"); + } + + // Ok here something important if your programm forks: + if (audio_fd > 0) { + if (fcntl(audio_fd,F_SETFD,true) < 0) { + perror("fcntl socket");exit(1); + } + } + + return (audio_fd > 0); +} + +inline void audioFlush() { + if (ioctl(audio_fd, SNDCTL_DSP_RESET, 0) == -1) + perror("Unable to reset audio device\n"); +} + +/* + should close the audio device and perform any special shutdown +*/ +void audioClose() { + audioFlush(); + if (close(audio_fd) < 0) { + perror("error close audiodevice:"); + } +} + + +void audioInit(int sampleSize,int frequency, int stereo, int sign, int big) { + if( sign == 0 ) + { + fprintf(stderr, + "%s, %d: expecting signed audio data, " + "initialized unsigned (ignored)\n", + __FILE__, __LINE__ ); + } + if( big != 0 ) + { + fprintf(stderr, + "%s, %d: expecting little endian audio data, " + "initialized big endian (ignored)\n", + __FILE__, __LINE__ ); + } + + int play_format=AFMT_S16_LE; + + if (sampleSize == 8) { + play_format=AFMT_S8; + } + ioctl(audio_fd,SNDCTL_DSP_RESET,NULL); + + if (ioctl(audio_fd, SNDCTL_DSP_SETFMT,&play_format) < 0) { + perror("Unable to set required audio format\n"); + } + + /* Set 1 or 2 channels */ + stereo=(stereo ? 1 : 0); + + if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo) < 0) { + perror("Unable to set stereo/mono\n"); + exit(0); + } + + /* Set the output frequency */ + if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &frequency) < 0) { + perror("Unable to set frequency"); + exit(0); + } + + if (ioctl(audio_fd, SNDCTL_DSP_GETBLKSIZE, &AUSIZ) == -1) { + perror("Unable to get fragment size\n"); + exit(0); + } +} + + +int getAudioBufferSize() { + struct audio_buf_info buf_info; + int buf=1024*65; + if (ioctl(audio_fd,SNDCTL_DSP_GETOSPACE,&buf_info) == -1) { + perror("ioctl getAudioBufferSize using default"); + } else { + buf=buf_info.bytes; + } + return buf; +} + + +int mixerOpen() { + int supportedMixers; + + if ((mixer_fd=open("/dev/mixer",O_RDWR)) == -1) { + perror("Unable to open mixer device"); + } + + // Ok here something important if your programm forks: + if (mixer_fd > 0) { + if (fcntl(mixer_fd,F_SETFD,true) < 0) { + perror("fcntl socket");exit(1); + } + } + + if (ioctl(mixer_fd, SOUND_MIXER_READ_DEVMASK, &supportedMixers) == -1){ + perror("Unable to get mixer info assuming master volume"); + volumeIoctl=SOUND_MIXER_WRITE_VOLUME; + } else { + if ((supportedMixers & SOUND_MASK_PCM) != 0) + volumeIoctl=SOUND_MIXER_WRITE_PCM; + else + volumeIoctl=0; + } + + return (mixer_fd > 0); +} + + +void mixerClose() { + if (mixer_fd != -1) { + close(mixer_fd); + } +} + +/* + only code this if your system can change the volume while + playing +*/ +void mixerSetVolume(int leftVolume,int rightVolume) { + int volume; + + volume=leftVolume+(rightVolume<<8); + if ((mixer_fd != -1) && (volumeIoctl!=0)) { + if (ioctl(mixer_fd, volumeIoctl, &volume) < 0) { + perror("Unable to set sound volume"); + } + } +} + + + +int audioWrite(char *buffer, int count) { + return(write(audio_fd,buffer,count)); +} + + +int getAudioFd() { + return(audio_fd); +} diff --git a/mpeglib/lib/util/audio/audioIO_SDL.cpp b/mpeglib/lib/util/audio/audioIO_SDL.cpp new file mode 100644 index 00000000..782fa388 --- /dev/null +++ b/mpeglib/lib/util/audio/audioIO_SDL.cpp @@ -0,0 +1,164 @@ +/* + audio wrapper for SDL + 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 "../../input/bufferInputStream.h" +#include <assert.h> +#include <iostream.h> +#if defined WIN32 +#include <SDL.h> +#include <SDL_audio.h> +#else +#include <SDL/SDL.h> +#include <SDL/SDL_audio.h> +#endif + +//static SDL_AudioSpec actual; +static BufferInputStream* audioRing; +static TimeStamp* dummy; +static int lOpen=false; + + + +int audioConstruct() { + cout << "audioConstruct ********* SDL"<<endl; + if ( SDL_Init(SDL_INIT_AUDIO) < 0 ) { + fprintf(stderr, "Warning: Couldn't init SDL audio: %s\n", + SDL_GetError()); + exit(0); + } + atexit(SDL_Quit); + audioRing=new BufferInputStream(1024*65,1024*8,"audioSDL"); + audioRing->open("audioSDL"); + dummy=new TimeStamp(); + lOpen=false; + return true; +} + + +void audioDestruct() { + delete audioRing; + delete dummy; +} + + + + +int audioOpen() { + return true; +} + + +void audioClose() { + lOpen=false; + SDL_CloseAudio(); +} + + +void audioCallback(void *, Uint8 *stream, int len) { + char* startPtr; + TimeStamp* start; + int bytePos; + + int read=audioRing->readRemote(&startPtr,len); + SDL_MixAudio(stream, (Uint8*) startPtr, read, SDL_MIX_MAXVOLUME); + + audioRing->forwardReadPtr(read); + // dequeue time stamps + bytePos=audioRing->getBytePosition(); + start=audioRing->getTimeStamp(bytePos); + +} + + + +void audioInit(int sampleSize,int frequency, int stereo, int sign, int big) { + if( sign == 0 ) + { + fprintf(stderr, + "%s, %d: expecting signed audio data, " + "initialized unsigned (ignored)\n", + __FILE__, __LINE__ ); + } + if( big != 0 ) + { + fprintf(stderr, + "%s, %d: expecting little endian audio data, " + "initialized big endian (ignored)\n", + __FILE__, __LINE__ ); + } + + cout << "SDL audioInit: " + << " sampleSize:"<<sampleSize + << " frequency:"<<frequency + << " stereo:"<<stereo<<endl; + if (lOpen==true) { + cout << "SDL is buggy, because open != init -> return"<<endl; + return; + } + lOpen=true; + SDL_AudioSpec wanted; + //SDL_AudioSpec actual; + if (sampleSize == 16) { + wanted.format= AUDIO_S16LSB; + } else { + wanted.format= AUDIO_S8; + } + + wanted.freq=frequency; + wanted.channels=stereo+1; + wanted.samples = 1024; + wanted.callback = audioCallback; + wanted.userdata = NULL; + + int err=SDL_OpenAudio(&wanted, NULL); + if (err != 0) { + cout << "SDL_OpenAudio not ok"<<endl; + cout << "error is:"<<SDL_GetError()<<endl; + exit(0); + } + SDL_PauseAudio(0); + +} + + +int mixerOpen() { + return true; +} + + +void mixerClose() { +} + + +void mixerSetVolume(int volumeLeft,int volumeRight) { + cout << "volumeLeft:"<<volumeLeft + << " volumeRight:"<<volumeRight<<endl; +} + + +int audioWrite(char *buffer, int count) { + + audioRing->write(buffer,count,dummy); + + + return count; +} + + +int getAudioFd() { + return false; +} + + +int getAudioBufferSize() { + int buf=1024*65; + return buf; +} diff --git a/mpeglib/lib/util/audio/audioIO_SunOS.cpp b/mpeglib/lib/util/audio/audioIO_SunOS.cpp new file mode 100644 index 00000000..4e9958a1 --- /dev/null +++ b/mpeglib/lib/util/audio/audioIO_SunOS.cpp @@ -0,0 +1,167 @@ +/* this file is a part of amp software, (C) tomislav uzelac 1996,1997 + + Origional code by: tomislav uzelac + Modified by: + * Andrew Richards - moved code from audio.c + * Jim Crumley - ported some code from other audioIO_'s + + */ + +#include <sys/types.h> +#include <sys/stropts.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> +#include <sys/audioio.h> +#include "audioIO.h" +#include <iostream.h> + +/* declare these static to effectively isolate the audio device */ + +static int audio_fd; +static audio_info_t auinfo; + + +int audioConstruct(){ + audio_fd=-1; + return true; +} + +void audioDestruct() { + +} + + +/* audioOpen() */ +/* should open the audio device and perform any special initialization */ +/* returns the file descriptior of the audio device */ + +int audioOpen() { + AUDIO_INITINFO(&auinfo); + + if ((audio_fd = open("/dev/audio",O_RDWR))==-1) { + perror("unable to open the audio device"); + } + // Ok here something important if your programm forks: + if (audio_fd > 0) { + if (fcntl(audio_fd,F_SETFD,true) < 0) { + perror("fcntl socket");exit(1); + } + } + + DB(audio, msg("Audio device opened on %d\n",audio_fd) ); + return (audio_fd > 0); +} + +/* audioFlush() */ +/* should flush the audio device */ + +inline void audioFlush() { + DB(audio, msg("audio: flush %d\n",audio_fd) ); +} + + +/* audioClose() */ +/* should close the audio device and perform any special shutdown */ + +void audioClose() { + close(audio_fd); +} + + +/** + Audio init assumes that the audiodevice is open. It initializes + it to the given values +*/ + +void audioInit(int sampleSize ,int frequency, int stereo,int sign, int big){ + + if (ioctl(audio_fd,AUDIO_GETINFO,&auinfo)<0) + perror("Unable to get audio info"); + + auinfo.play.precision=sampleSize; + auinfo.play.encoding=AUDIO_ENCODING_LINEAR; + auinfo.play.channels=(stereo ? 2 : 1); + DB(audio, msg("setting sample rate to %d Hz",frequency) ); + auinfo.play.sample_rate=frequency; + if (ioctl(audio_fd,AUDIO_SETINFO,&auinfo)<0) + perror("Unable to set audio info"); + +} + +/* + only code this if your system can change the volume while + playing +*/ + + +int getAudioBufferSize() { + int buf; + if (ioctl(audio_fd,AUDIO_GETINFO,&auinfo) == -1) { + perror("ioctl getAudioBufferSize using default"); + buf=1024*65; + } else { + buf=auinfo.play.buffer_size; + } + return buf; +} + + +void mixerSetVolume(int leftVolume,int rightVolume) { + int volume; + + volume=(leftVolume+rightVolume)/2; + auinfo.play.gain=(volume*255)/100; + + // now normalize to values 0...32 + leftVolume=(32*leftVolume)/100; + rightVolume=(32*rightVolume)/100; + + // eg : leftVolume=32, rightVolume=32 => balance=32 + // eg : leftVolume=0, rightVolume=32 => balance=64 + // eg : leftVolume=32, rightVolume=0 => balance=0 + + //cout << "leftVolume:"<<leftVolume<<endl; + //cout << "rightVolume:"<<rightVolume<<endl; + int balance=leftVolume-rightVolume+32; + //cout << "balance:"<<balance<<endl; + //someone should fix the volume on solaris + balance=0; + + auinfo.play.balance=(uchar_t)balance; + if (ioctl(audio_fd,AUDIO_SETINFO,&auinfo)<0) + perror("Unable to set sound volume"); +} + + + + +int mixerOpen() { + return true; +} + +void mixerClose() { +} + + + + +/* audioWrite */ +/* writes count bytes from buffer to the audio device */ +/* returns the number of bytes actually written */ + +int audioWrite(char *buffer, int count) +{ + return(write(audio_fd,buffer,count)); +} + +/* Let buffer.c have the audio descriptor so it can select on it. This means */ +/* that the program is dependent on an file descriptor to work. Should really */ +/* move the select's etc (with inlines of course) in here so that this is the */ +/* ONLY file which has hardware dependent audio stuff in it */ + +int +getAudioFd() +{ + return(audio_fd); +} diff --git a/mpeglib/lib/util/audio/dspWrapper.cpp b/mpeglib/lib/util/audio/dspWrapper.cpp new file mode 100644 index 00000000..cd9afa57 --- /dev/null +++ b/mpeglib/lib/util/audio/dspWrapper.cpp @@ -0,0 +1,193 @@ +/* + a wrapper for the audioDevice. + Copyright (C) 1998 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 "dspWrapper.h" +#include "audioIO.h" + + +#include "../../frame/pcmFrame.h" +#include "../../frame/floatFrame.h" + +#include <iostream> + +using namespace std; + +DSPWrapper::DSPWrapper() { + currentFormat=new PCMFrame(0); + lopenDevice=false; + lopenMixer=false; + + audioConstruct(); +} + +DSPWrapper::~DSPWrapper() { + if (lopenDevice) { + audioClose(); + } + if (lopenMixer) { + mixerClose(); + } + audioDestruct(); + delete currentFormat; +} + + +int DSPWrapper::isOpenDevice() { + return lopenDevice; +} + +int DSPWrapper::openDevice() { + if (lopenDevice==true) { + return true; + } + lopenDevice=audioOpen(); + return lopenDevice; +} + +int DSPWrapper::closeDevice() { + if (isOpenDevice() == true) { + audioClose(); + currentFormat->setFrameFormat(-1,-1); + lopenDevice=false; + } + return true; +} + + +int DSPWrapper::isOpenMixer() { + return lopenMixer; +} + + +int DSPWrapper::getAudioBufferSize() { + return ::getAudioBufferSize(); +} + + +int DSPWrapper::openMixer() { + lopenMixer=mixerOpen(); + return lopenMixer; +} + +int DSPWrapper::closeMixer() { + if (isOpenMixer() == true) { + mixerClose(); + lopenMixer=false; + } + return true; +} + + +int DSPWrapper::audioPlay(char *buf, int len) { + return audioWrite(buf,len); +} + +int DSPWrapper::audioSetup(int stereo,int sampleSize,int lSigned, + int lBigEndian,int freq) { + + + if (isOpenDevice()==false) { + cout << "device not open"<<endl; + exit(-1); + } + /* + cout << "sampleSize:"<<sampleSize<<endl; + cout << "freq:"<<freq<<endl; + cout << "stereo:"<<stereo<<endl; + cout << "lSigned:"<<lSigned<<endl; + cout << "lBigEndian:"<<lBigEndian<<endl; + */ + audioInit(sampleSize,freq,stereo,lSigned,lBigEndian); + if (currentFormat->getSampleSize() != sampleSize) { + cout << "FIXME: pcmFrame with sampleSize:"<<sampleSize<<endl; + } + currentFormat->setFrameFormat(stereo,freq); + return true; +} + +int DSPWrapper::audioSetup(AudioFrame* audioFrame) { + if (audioFrame == NULL) { + cout << "audioFrame NULL: DSPWrapper:audioSetup"<<endl; + exit(0); + } + if(audioFrame->isFormatEqual(currentFormat)==false) { + audioSetup(audioFrame->getStereo(),audioFrame->getSampleSize(), + audioFrame->getSigned(),audioFrame->getBigEndian(), + audioFrame->getFrequenceHZ()); + } + return true; +} + + +int DSPWrapper::audioPlay(PCMFrame* pcmFrame) { + if (pcmFrame == NULL) { + cout << "pcmFrame NULL: DSPWrapper:audioPlay"<<endl; + exit(0); + } + if(pcmFrame->isFormatEqual(currentFormat)==false) { + audioSetup(pcmFrame->getStereo(),pcmFrame->getSampleSize(), + pcmFrame->getSigned(),pcmFrame->getBigEndian(), + pcmFrame->getFrequenceHZ()); + } + int len=pcmFrame->getLen()*2; + int played=audioPlay((char*)pcmFrame->getData(),len); + return (len == played); +} + + +// +// Misuse our internal currentFormat for the float->int conversion. +// + +int DSPWrapper::audioPlay(FloatFrame* floatFrame) { + if (floatFrame == NULL) { + cout << "floatFrame NULL: DSPWrapper:audioPlay"<<endl; + exit(0); + } + if(floatFrame->isFormatEqual(currentFormat)==false) { + audioSetup(floatFrame->getStereo(),floatFrame->getSampleSize(), + floatFrame->getSigned(),floatFrame->getBigEndian(), + floatFrame->getFrequenceHZ()); + } + + int tmpLen=currentFormat->getLen(); + if (tmpLen < floatFrame->getLen()) { + delete currentFormat; + currentFormat=new PCMFrame(floatFrame->getLen()); + floatFrame->copyFormat(currentFormat); + } + currentFormat->clearrawdata(); + currentFormat->putFloatData(floatFrame->getData(),floatFrame->getLen()); + return audioPlay(currentFormat); +} + +void DSPWrapper::audioFlush() { + closeDevice(); +} + + +void DSPWrapper::setVolume(float leftPercent,float rightPercent) { + if (isOpenMixer()) { + mixerSetVolume((int)leftPercent,(int)rightPercent); + } else { + cout << "cannot set Mixer settings:not open!"<<endl; + } +} + + +void DSPWrapper::print() { + cout<<"lopenDevice:"<<lopenDevice<<endl; + cout<<"lopenMixer:"<<lopenMixer<<endl; + currentFormat->print("currentFormat"); + +} diff --git a/mpeglib/lib/util/audio/dspWrapper.h b/mpeglib/lib/util/audio/dspWrapper.h new file mode 100644 index 00000000..f323096d --- /dev/null +++ b/mpeglib/lib/util/audio/dspWrapper.h @@ -0,0 +1,75 @@ +/* + a wrapper for the audioDevice. + Copyright (C) 1998 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 _DSPWRAPPER_H +#define _DSPWRAPPER_H + +class AudioFrame; +class PCMFrame; +class FloatFrame; +#include <kdemacros.h> + +/** + This class wraps the platform specific /dev/dsp implementation. + The only unusal thing is, that it supports each order of + init/open. + i) you can first init the device and the open + ii) you can first open the device and the init it + The implementation takes care that the calls are forwarded + in the right order to the /dev/dsp implementation. + (means: before the init it, we need to open it) + But a caller can do it in both orders. +*/ + +class KDE_EXPORT DSPWrapper { + + int lopenDevice; + int lopenMixer; + PCMFrame* currentFormat; + + + public: + DSPWrapper(); + ~DSPWrapper(); + + int openDevice(); + int closeDevice(); + int isOpenDevice(); + + int openMixer(); + int closeMixer(); + int isOpenMixer(); + + int getAudioBufferSize(); + void setVolume(float leftPercent,float rightPercent); + + int audioSetup(int stereo,int sampleSize,int lSigned, + int lBigEndian,int freq); + int audioSetup(AudioFrame* audioFrame); + + int audioPlay(char *buffer, int size); + int audioPlay(PCMFrame* pcmFrame); + int audioPlay(FloatFrame* floatFrame); + void audioFlush(); + + int isEqual(int samplesize,int speed,int stereo,int lSigned,int lBigEndian); + int write(char* buf,int len); + void print(); +}; + +#endif + + + + diff --git a/mpeglib/lib/util/dynBuffer.cpp b/mpeglib/lib/util/dynBuffer.cpp new file mode 100644 index 00000000..c93d5381 --- /dev/null +++ b/mpeglib/lib/util/dynBuffer.cpp @@ -0,0 +1,166 @@ +/* + This class implements a dynamic string buffer + Copyright (C) 1998 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 "dynBuffer.h" + +#include <iostream> + +using namespace std; + + +DynBuffer::DynBuffer(int size) { + nSize=size; + msg=(char*) malloc(sizeof(char)*(nSize+1)); + msg[nSize]='\0'; + clear(); + +} + + +DynBuffer::~DynBuffer() { + free (msg); +} + + +void DynBuffer::clear() { + msg[0]='\0'; +} + +void DynBuffer::append(int value) { + DynBuffer buf(30); + sprintf(buf.getData(),"%d",value); + append(buf.getData()); +} + + + + +void DynBuffer::append(char* appendMsg) { + if (appendMsg == msg) { + cout << "cannot append to self"<<endl; + exit(0); + } + char* appendPos=getAppendPos(); + int nlen=strlen(appendMsg); + if (appendPos == NULL) return; + + append(appendMsg,nlen); +} + + +void DynBuffer::append(const char* appendMsg) { + append((char*)appendMsg); +} + + +void DynBuffer::append(char* buffer,int buflen) { + int nlen=len(); + int nBedarf; + if (buffer == msg) { + cout << "cannot append to self"<<endl; + exit(0); + } + if (buflen+nlen <= nSize) { + char* appendPos=getAppendPos(); + strncpy(appendPos,buffer,buflen); + appendPos[buflen]='\0'; + return; + } + nBedarf=(nlen+buflen)-nSize; + grow(nBedarf); + append(buffer,buflen); +} + +char* DynBuffer::getAppendPos() { + int i; + // this Array has nSize+1 entries! + // and it *is* granted that msg[nSize]=0; (think so) + for (i=0;i<=nSize;i++) { + if (msg[i] == '\0') return &(msg[i]); + } + // should never reach this point + return NULL; +} + + +void DynBuffer::setData(char* msg) { + if (strlen(msg) == 0) { + clear(); + return; + } + clear(); + append(msg); +} + +char* DynBuffer::getData() { + return msg; +} + + +int DynBuffer::len() { + return strlen(msg); +} + +int DynBuffer::getSize() { + return nSize; +} + +void DynBuffer::grow(int size) { + int i; + int newSize=nSize+size; + char* tmp=(char*) malloc(sizeof(char)*(newSize+1)); + tmp[newSize]='\0'; + for(i=0;i<=nSize;i++) { + tmp[i]=msg[i]; + } + + nSize=newSize; + free(msg); + msg=tmp; + +} + + +int DynBuffer::find(char zeichen) { + int i; + int nlen=len(); + for(i=0;i<nlen;i++) { + if (msg[i] == zeichen) return i; + } + return -1; +} + + + +void DynBuffer::forward(int bytes) { + int i; + int aktPos; + int nlen=len(); + if (bytes > nlen) { + bytes=nlen; + } + i=0; + aktPos=bytes; + while(aktPos <= nlen) { + msg[i]=msg[aktPos]; + i++; + aktPos++; + } +} + + + +void DynBuffer::print() { + printf("DynBuffer:%s\n",msg); +} diff --git a/mpeglib/lib/util/dynBuffer.h b/mpeglib/lib/util/dynBuffer.h new file mode 100644 index 00000000..7ba99d42 --- /dev/null +++ b/mpeglib/lib/util/dynBuffer.h @@ -0,0 +1,63 @@ +/* + This class implements a static string buffer + Copyright (C) 1998 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 __DYNBUFFER_H +#define __DYNBUFFER_H + + +extern "C" { +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + } + +class DynBuffer { + + char* msg; + int nSize; + + public: + DynBuffer(int size); + ~DynBuffer(); + + void clear(); + void append(int value); // appends values as string + void append(char* msg); + void append(const char* msg); + + void append(char* buffer,int buflen); + + int find(char zeichen); + int len(); + + void setData(char* msg); + char* getData(); + + int getSize(); + void grow(int size); + + void forward(int bytes); + void print(); + private: + char* getAppendPos(); + void read(FILE stream); + +}; + + +#endif + + + diff --git a/mpeglib/lib/util/file/Makefile.am b/mpeglib/lib/util/file/Makefile.am new file mode 100644 index 00000000..96b16fff --- /dev/null +++ b/mpeglib/lib/util/file/Makefile.am @@ -0,0 +1,25 @@ +# libsplay - Makefile.am + + +INCLUDES = $(all_includes) + +noinst_LTLIBRARIES = libsimplefile.la + +noinst_HEADERS = fileAccess.h + +kmpgincludedir = $(includedir)/$(THIS_LIB_NAME)/util/file + +kmpginclude_HEADERS = fileAccess.h + + +libsimplefile_la_SOURCES = fileAccess.cpp + + + + + + + + + + diff --git a/mpeglib/lib/util/file/fileAccess.cpp b/mpeglib/lib/util/file/fileAccess.cpp new file mode 100644 index 00000000..8eab864f --- /dev/null +++ b/mpeglib/lib/util/file/fileAccess.cpp @@ -0,0 +1,95 @@ +/* + simple file access interface. + Copyright (C) 2001 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 "fileAccess.h" + + +FileAccess::FileAccess() { + file=NULL; + length=0; +} + + +FileAccess::~FileAccess() { + close(); +} + + +int FileAccess::open(const char* path) { + close(); + file=fopen(path,"rb"); + length=calcByteLength(); + return (file != NULL); +} + + +void FileAccess::close() { + if (file != NULL) { + fclose(file); + file=NULL; + length=0; + } +} + + +int FileAccess::read(char* dest,int len) { + int back=0; + if (file != NULL) { + back=fread(dest,1,len,file); + } else { + printf("FileAccess::read not open\n"); + } + return back; +} + +int FileAccess::eof() { + int back=true; + if (file != NULL) { + back=feof(file); + } + return back; +} + + +int FileAccess::seek(long pos) { + if (file == NULL) { + return -1; + } + return fseek(file,pos,SEEK_SET); +} + + +long FileAccess::getBytePosition() { + if (file == NULL) { + return 0; + } + return ftell(file); +} + + +long FileAccess::getByteLength() { + return length; +} + +long FileAccess::calcByteLength() { + if (file == NULL) { + return 0; + } + long pos=getBytePosition(); + fseek(file,0,SEEK_END); + long back=getBytePosition(); + fseek(file,pos,SEEK_SET); + return back; +} + diff --git a/mpeglib/lib/util/file/fileAccess.h b/mpeglib/lib/util/file/fileAccess.h new file mode 100644 index 00000000..d9bf9e2e --- /dev/null +++ b/mpeglib/lib/util/file/fileAccess.h @@ -0,0 +1,46 @@ +/* + simple file access interface. + Copyright (C) 2001 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 __FILEACCESS_H +#define __FILEACCESS_H + + +#include "stdio.h" + +/** + Extension to the normal "read" function. + This interface is useful for the AudioInfo. +*/ + +class FileAccess { + + FILE* file; + long length; + + public: + FileAccess(); + virtual ~FileAccess(); + + virtual int open(const char* file); + virtual void close(); + virtual int read(char* dest,int len); + virtual int eof(); + virtual int seek(long pos); + virtual long getBytePosition(); + virtual long getByteLength(); + + private: + long calcByteLength(); + +}; +#endif + diff --git a/mpeglib/lib/util/mmx/Makefile.am b/mpeglib/lib/util/mmx/Makefile.am new file mode 100644 index 00000000..ce8875e0 --- /dev/null +++ b/mpeglib/lib/util/mmx/Makefile.am @@ -0,0 +1,46 @@ +# ---- @OS_TYPE@/@ARCH_TYPE@ ---- + +# For cpu_accel compile we cannot have ansi +# (I dont have debugged why) + +INCLUDES = $(all_includes) + +noinst_LTLIBRARIES = libmmx.la +noinst_HEADERS = + +kmpgincludedir = $(includedir)/$(THIS_LIB_NAME)/util/mmx + +kmpginclude_HEADERS = mmx.h mmx_asm.h mm_accel.h + +libmmx_la_SOURCES = cpu_accel.c mmx.c + +AM_ASFLAGS = $(DEFS) $(DEFAULT_INCLUDES) $(all_includes) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mpeglib/lib/util/mmx/attribute.h b/mpeglib/lib/util/mmx/attribute.h new file mode 100644 index 00000000..4dfd3e1e --- /dev/null +++ b/mpeglib/lib/util/mmx/attribute.h @@ -0,0 +1,33 @@ +/* + align attribut definition (g++) + Copyright (C) 2001 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 __ATTRIBUTE_H +#define __ATTRIBUTE_H + + + +#include "vidi/vidi_config.h" + + +/* use gcc attribs to align critical data structures */ + +#ifdef ATTRIBUTE_ALIGNED_MAX +#define ATTR_ALIGN(align) __attribute__ \ + ((__aligned__ ((ATTRIBUTE_ALIGNED_MAX <align) ? \ + ATTRIBUTE_ALIGNED_MAX : align))) +#else +#define ATTR_ALIGN(align) +#endif + + +#endif diff --git a/mpeglib/lib/util/mmx/cpu_accel.c b/mpeglib/lib/util/mmx/cpu_accel.c new file mode 100644 index 00000000..8f138308 --- /dev/null +++ b/mpeglib/lib/util/mmx/cpu_accel.c @@ -0,0 +1,162 @@ +/* + * cpu_accel.c + * Copyright (C) 2000-2001 Michel Lespinasse <walken@zoy.org> + * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca> + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * See http://libmpeg2.sourceforge.net/ for updates. + * + * mpeg2dec 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; either version 2 of the License, or + * (at your option) any later version. + * + * mpeg2dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#if defined(MMX_SUPPORT) || defined(INTEL) +#define ARCH_X86 1 +#endif + +#include <inttypes.h> + +#include "mm_accel.h" + +#ifdef ARCH_X86 +static uint32_t arch_accel (void) +{ + uint32_t eax, ebx, ecx, edx; + int AMD; + uint32_t caps; + +#ifndef PIC +#define cpuid(op,eax,ebx,ecx,edx) \ + __asm__ ("cpuid" \ + : "=a" (eax), \ + "=b" (ebx), \ + "=c" (ecx), \ + "=d" (edx) \ + : "a" (op) \ + : "cc") +#else /* PIC version : save ebx */ +#define cpuid(op,eax,ebx,ecx,edx) \ + __asm__ ("pushl %%ebx\n\t" \ + "cpuid\n\t" \ + "movl %%ebx,%1\n\t" \ + "popl %%ebx" \ + : "=a" (eax), \ + "=r" (ebx), \ + "=c" (ecx), \ + "=d" (edx) \ + : "a" (op) \ + : "cc") +#endif + + __asm__ ("pushfl\n\t" + "pushfl\n\t" + "popl %0\n\t" + "movl %0,%1\n\t" + "xorl $0x200000,%0\n\t" + "pushl %0\n\t" + "popfl\n\t" + "pushfl\n\t" + "popl %0\n\t" + "popfl" + : "=r" (eax), + "=r" (ebx) + : + : "cc"); + + if (eax == ebx) /* no cpuid */ + return 0; + + cpuid (0x00000000, eax, ebx, ecx, edx); + if (!eax) /* vendor string only */ + return 0; + + AMD = (ebx == 0x68747541) && (ecx == 0x444d4163) && (edx == 0x69746e65); + + cpuid (0x00000001, eax, ebx, ecx, edx); + if (! (edx & 0x00800000)) /* no MMX */ + return 0; + + caps = MM_ACCEL_X86_MMX; + if (edx & 0x02000000) /* SSE - identical to AMD MMX extensions */ + caps = MM_ACCEL_X86_MMX | MM_ACCEL_X86_MMXEXT; + + cpuid (0x80000000, eax, ebx, ecx, edx); + if (eax < 0x80000001) /* no extended capabilities */ + return caps; + + cpuid (0x80000001, eax, ebx, ecx, edx); + + if (edx & 0x80000000) + caps |= MM_ACCEL_X86_3DNOW; + + if (AMD && (edx & 0x00400000)) /* AMD MMX extensions */ + caps |= MM_ACCEL_X86_MMXEXT; + + return caps; +} +#endif /* ARCH_X86 */ + +#ifdef ARCH_PPC +#include <signal.h> +#include <setjmp.h> + +static sigjmp_buf jmpbuf; +static volatile sig_atomic_t canjump = 0; + +static RETSIGTYPE sigill_handler (int sig) +{ + if (!canjump) { + signal (sig, SIG_DFL); + raise (sig); + } + + canjump = 0; + siglongjmp (jmpbuf, 1); +} + +static uint32_t arch_accel (void) +{ + signal (SIGILL, sigill_handler); + if (sigsetjmp (jmpbuf, 1)) { + signal (SIGILL, SIG_DFL); + return 0; + } + + canjump = 1; + + __asm__ volatile ("mtspr 256,%0" :: "r" (-1)); + + signal (SIGILL, SIG_DFL); + return MM_ACCEL_PPC_ALTIVEC; +} +#endif /* ARCH_PPC */ + +uint32_t mm_accel (void) +{ +#if defined (ARCH_X86) || defined (ARCH_PPC) + static int got_accel = 0; + static uint32_t accel; + + if (!got_accel) { + got_accel = 1; + accel = arch_accel (); + } + + return accel; +#else + return 0; +#endif +} diff --git a/mpeglib/lib/util/mmx/mm_accel.h b/mpeglib/lib/util/mmx/mm_accel.h new file mode 100644 index 00000000..e0690804 --- /dev/null +++ b/mpeglib/lib/util/mmx/mm_accel.h @@ -0,0 +1,58 @@ +/* + * mm_accel.h + * Copyright (C) 2000-2001 Michel Lespinasse <walken@zoy.org> + * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca> + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * See http://libmpeg2.sourceforge.net/ for updates. + * + * mpeg2dec 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; either version 2 of the License, or + * (at your option) any later version. + * + * mpeg2dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef MM_ACCEL_H +#define MM_ACCEL_H + +#include <inttypes.h> + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +/* generic accelerations */ +#define MM_ACCEL_MLIB 0x00000001 + +/* x86 accelerations */ +#define MM_ACCEL_X86_MMX 0x80000000 +#define MM_ACCEL_X86_3DNOW 0x40000000 +#define MM_ACCEL_X86_MMXEXT 0x20000000 + +/* powerpc accelerations */ +#define MM_ACCEL_PPC_ALTIVEC 0x80000000 + +/* detailed SIMD info */ +uint32_t mm_accel (void); + +/* true if MMX support */ +int mm_support(); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif +/* MM_ACCEL_H */ diff --git a/mpeglib/lib/util/mmx/mmx.c b/mpeglib/lib/util/mmx/mmx.c new file mode 100644 index 00000000..4ac3d6b8 --- /dev/null +++ b/mpeglib/lib/util/mmx/mmx.c @@ -0,0 +1,73 @@ +/* + wrapper for MMX calls + 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 "mmx.h" + +static int mmSupport=-1; + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if defined(MMX_SUPPORT) || defined(INTEL) +#define HAVE_ACCEL +#endif + + +#ifndef HAVE_ACCEL +int emms() { + printf("urgs! emms() never should happen\n"); + exit(0); +} + +int mm_support() { + return 0; +} + +#endif + + +#ifdef HAVE_ACCEL +#include <inttypes.h> +#include "mm_accel.h" + + + + +int emms() { + __asm__ ("emms"); + return 1; +} + + +int mm_support() { + + int val; + + if (mmSupport == -1) { + + val=mm_accel(); + if (val & MM_ACCEL_X86_MMX) { + mmSupport=1; + } else { + mmSupport=0; + } + + } + /* Return */ + return(mmSupport); +} + + +#endif diff --git a/mpeglib/lib/util/mmx/mmx.h b/mpeglib/lib/util/mmx/mmx.h new file mode 100644 index 00000000..c4b8340d --- /dev/null +++ b/mpeglib/lib/util/mmx/mmx.h @@ -0,0 +1,26 @@ + + + +#ifndef __MMX_H +#define __MMX_H + + +#include <stdio.h> +#include <stdlib.h> + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +extern int emms(); +extern int mm_support(); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif diff --git a/mpeglib/lib/util/mmx/mmx_asm.h b/mpeglib/lib/util/mmx/mmx_asm.h new file mode 100644 index 00000000..8717eff5 --- /dev/null +++ b/mpeglib/lib/util/mmx/mmx_asm.h @@ -0,0 +1,258 @@ +/* + * mmx.h + * Copyright (C) 1997-2001 H. Dietz and R. Fisher + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * + * mpeg2dec 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; either version 2 of the License, or + * (at your option) any later version. + * + */ + +/* + * The type of an value that fits in an MMX register (note that long + * long constant values MUST be suffixed by LL and unsigned long long + * values by ULL, lest they be truncated by the compiler) + */ + +#ifndef __MMX_ASM_H +#define __MMX_ASM_H + +#include "attribute.h" + + +typedef union { + long long q; /* Quadword (64-bit) value */ + unsigned long long uq; /* Unsigned Quadword */ + int d[2]; /* 2 Doubleword (32-bit) values */ + unsigned int ud[2]; /* 2 Unsigned Doubleword */ + short w[4]; /* 4 Word (16-bit) values */ + unsigned short uw[4]; /* 4 Unsigned Word */ + char b[8]; /* 8 Byte (8-bit) values */ + unsigned char ub[8]; /* 8 Unsigned Byte */ + float s[2]; /* Single-precision (32-bit) value */ +} ATTR_ALIGN(8) mmx_t; /* On an 8-byte (64-bit) boundary */ + + +#define mmx_i2r(op,imm,reg) \ + __asm__ __volatile__ (#op " %0, %%" #reg \ + : /* nothing */ \ + : "X" (imm) ) + +#define mmx_m2r(op,mem,reg) \ + __asm__ __volatile__ (#op " %0, %%" #reg \ + : /* nothing */ \ + : "X" (mem)) + +#define mmx_r2m(op,reg,mem) \ + __asm__ __volatile__ (#op " %%" #reg ", %0" \ + : "=X" (mem) \ + : /* nothing */ ) + +#define mmx_r2r(op,regs,regd) \ + __asm__ __volatile__ (#op " %" #regs ", %" #regd) + + +#define emms() __asm__ __volatile__ ("emms") + +#define movd_m2r(var,reg) mmx_m2r (movd, var, reg) +#define movd_r2m(reg,var) mmx_r2m (movd, reg, var) +#define movd_r2r(regs,regd) mmx_r2r (movd, regs, regd) + +#define movq_m2r(var,reg) mmx_m2r (movq, var, reg) +#define movq_r2m(reg,var) mmx_r2m (movq, reg, var) +#define movq_r2r(regs,regd) mmx_r2r (movq, regs, regd) + +#define packssdw_m2r(var,reg) mmx_m2r (packssdw, var, reg) +#define packssdw_r2r(regs,regd) mmx_r2r (packssdw, regs, regd) +#define packsswb_m2r(var,reg) mmx_m2r (packsswb, var, reg) +#define packsswb_r2r(regs,regd) mmx_r2r (packsswb, regs, regd) + +#define packuswb_m2r(var,reg) mmx_m2r (packuswb, var, reg) +#define packuswb_r2r(regs,regd) mmx_r2r (packuswb, regs, regd) + +#define paddb_m2r(var,reg) mmx_m2r (paddb, var, reg) +#define paddb_r2r(regs,regd) mmx_r2r (paddb, regs, regd) +#define paddd_m2r(var,reg) mmx_m2r (paddd, var, reg) +#define paddd_r2r(regs,regd) mmx_r2r (paddd, regs, regd) +#define paddw_m2r(var,reg) mmx_m2r (paddw, var, reg) +#define paddw_r2r(regs,regd) mmx_r2r (paddw, regs, regd) + +#define paddsb_m2r(var,reg) mmx_m2r (paddsb, var, reg) +#define paddsb_r2r(regs,regd) mmx_r2r (paddsb, regs, regd) +#define paddsw_m2r(var,reg) mmx_m2r (paddsw, var, reg) +#define paddsw_r2r(regs,regd) mmx_r2r (paddsw, regs, regd) + +#define paddusb_m2r(var,reg) mmx_m2r (paddusb, var, reg) +#define paddusb_r2r(regs,regd) mmx_r2r (paddusb, regs, regd) +#define paddusw_m2r(var,reg) mmx_m2r (paddusw, var, reg) +#define paddusw_r2r(regs,regd) mmx_r2r (paddusw, regs, regd) + +#define pand_m2r(var,reg) mmx_m2r (pand, var, reg) +#define pand_r2r(regs,regd) mmx_r2r (pand, regs, regd) + +#define pandn_m2r(var,reg) mmx_m2r (pandn, var, reg) +#define pandn_r2r(regs,regd) mmx_r2r (pandn, regs, regd) + +#define pcmpeqb_m2r(var,reg) mmx_m2r (pcmpeqb, var, reg) +#define pcmpeqb_r2r(regs,regd) mmx_r2r (pcmpeqb, regs, regd) +#define pcmpeqd_m2r(var,reg) mmx_m2r (pcmpeqd, var, reg) +#define pcmpeqd_r2r(regs,regd) mmx_r2r (pcmpeqd, regs, regd) +#define pcmpeqw_m2r(var,reg) mmx_m2r (pcmpeqw, var, reg) +#define pcmpeqw_r2r(regs,regd) mmx_r2r (pcmpeqw, regs, regd) + +#define pcmpgtb_m2r(var,reg) mmx_m2r (pcmpgtb, var, reg) +#define pcmpgtb_r2r(regs,regd) mmx_r2r (pcmpgtb, regs, regd) +#define pcmpgtd_m2r(var,reg) mmx_m2r (pcmpgtd, var, reg) +#define pcmpgtd_r2r(regs,regd) mmx_r2r (pcmpgtd, regs, regd) +#define pcmpgtw_m2r(var,reg) mmx_m2r (pcmpgtw, var, reg) +#define pcmpgtw_r2r(regs,regd) mmx_r2r (pcmpgtw, regs, regd) + +#define pmaddwd_m2r(var,reg) mmx_m2r (pmaddwd, var, reg) +#define pmaddwd_r2r(regs,regd) mmx_r2r (pmaddwd, regs, regd) + +#define pmulhw_m2r(var,reg) mmx_m2r (pmulhw, var, reg) +#define pmulhw_r2r(regs,regd) mmx_r2r (pmulhw, regs, regd) + +#define pmullw_m2r(var,reg) mmx_m2r (pmullw, var, reg) +#define pmullw_r2r(regs,regd) mmx_r2r (pmullw, regs, regd) + +#define por_m2r(var,reg) mmx_m2r (por, var, reg) +#define por_r2r(regs,regd) mmx_r2r (por, regs, regd) + +#define pslld_i2r(imm,reg) mmx_i2r (pslld, imm, reg) +#define pslld_m2r(var,reg) mmx_m2r (pslld, var, reg) +#define pslld_r2r(regs,regd) mmx_r2r (pslld, regs, regd) +#define psllq_i2r(imm,reg) mmx_i2r (psllq, imm, reg) +#define psllq_m2r(var,reg) mmx_m2r (psllq, var, reg) +#define psllq_r2r(regs,regd) mmx_r2r (psllq, regs, regd) +#define psllw_i2r(imm,reg) mmx_i2r (psllw, imm, reg) +#define psllw_m2r(var,reg) mmx_m2r (psllw, var, reg) +#define psllw_r2r(regs,regd) mmx_r2r (psllw, regs, regd) + +#define psrad_i2r(imm,reg) mmx_i2r (psrad, imm, reg) +#define psrad_m2r(var,reg) mmx_m2r (psrad, var, reg) +#define psrad_r2r(regs,regd) mmx_r2r (psrad, regs, regd) +#define psraw_i2r(imm,reg) mmx_i2r (psraw, imm, reg) +#define psraw_m2r(var,reg) mmx_m2r (psraw, var, reg) +#define psraw_r2r(regs,regd) mmx_r2r (psraw, regs, regd) + +#define psrld_i2r(imm,reg) mmx_i2r (psrld, imm, reg) +#define psrld_m2r(var,reg) mmx_m2r (psrld, var, reg) +#define psrld_r2r(regs,regd) mmx_r2r (psrld, regs, regd) +#define psrlq_i2r(imm,reg) mmx_i2r (psrlq, imm, reg) +#define psrlq_m2r(var,reg) mmx_m2r (psrlq, var, reg) +#define psrlq_r2r(regs,regd) mmx_r2r (psrlq, regs, regd) +#define psrlw_i2r(imm,reg) mmx_i2r (psrlw, imm, reg) +#define psrlw_m2r(var,reg) mmx_m2r (psrlw, var, reg) +#define psrlw_r2r(regs,regd) mmx_r2r (psrlw, regs, regd) + +#define psubb_m2r(var,reg) mmx_m2r (psubb, var, reg) +#define psubb_r2r(regs,regd) mmx_r2r (psubb, regs, regd) +#define psubd_m2r(var,reg) mmx_m2r (psubd, var, reg) +#define psubd_r2r(regs,regd) mmx_r2r (psubd, regs, regd) +#define psubw_m2r(var,reg) mmx_m2r (psubw, var, reg) +#define psubw_r2r(regs,regd) mmx_r2r (psubw, regs, regd) + +#define psubsb_m2r(var,reg) mmx_m2r (psubsb, var, reg) +#define psubsb_r2r(regs,regd) mmx_r2r (psubsb, regs, regd) +#define psubsw_m2r(var,reg) mmx_m2r (psubsw, var, reg) +#define psubsw_r2r(regs,regd) mmx_r2r (psubsw, regs, regd) + +#define psubusb_m2r(var,reg) mmx_m2r (psubusb, var, reg) +#define psubusb_r2r(regs,regd) mmx_r2r (psubusb, regs, regd) +#define psubusw_m2r(var,reg) mmx_m2r (psubusw, var, reg) +#define psubusw_r2r(regs,regd) mmx_r2r (psubusw, regs, regd) + +#define punpckhbw_m2r(var,reg) mmx_m2r (punpckhbw, var, reg) +#define punpckhbw_r2r(regs,regd) mmx_r2r (punpckhbw, regs, regd) +#define punpckhdq_m2r(var,reg) mmx_m2r (punpckhdq, var, reg) +#define punpckhdq_r2r(regs,regd) mmx_r2r (punpckhdq, regs, regd) +#define punpckhwd_m2r(var,reg) mmx_m2r (punpckhwd, var, reg) +#define punpckhwd_r2r(regs,regd) mmx_r2r (punpckhwd, regs, regd) + +#define punpcklbw_m2r(var,reg) mmx_m2r (punpcklbw, var, reg) +#define punpcklbw_r2r(regs,regd) mmx_r2r (punpcklbw, regs, regd) +#define punpckldq_m2r(var,reg) mmx_m2r (punpckldq, var, reg) +#define punpckldq_r2r(regs,regd) mmx_r2r (punpckldq, regs, regd) +#define punpcklwd_m2r(var,reg) mmx_m2r (punpcklwd, var, reg) +#define punpcklwd_r2r(regs,regd) mmx_r2r (punpcklwd, regs, regd) + +#define pxor_m2r(var,reg) mmx_m2r (pxor, var, reg) +#define pxor_r2r(regs,regd) mmx_r2r (pxor, regs, regd) + + +/* 3DNOW extensions */ + +#define pavgusb_m2r(var,reg) mmx_m2r (pavgusb, var, reg) +#define pavgusb_r2r(regs,regd) mmx_r2r (pavgusb, regs, regd) + + +/* AMD MMX extensions - also available in intel SSE */ + + +#define mmx_m2ri(op,mem,reg,imm) \ + __asm__ __volatile__ (#op " %1, %0, %%" #reg \ + : /* nothing */ \ + : "X" (mem), "X" (imm)) +#define mmx_r2ri(op,regs,regd,imm) \ + __asm__ __volatile__ (#op " %0, %%" #regs ", %%" #regd \ + : /* nothing */ \ + : "X" (imm) ) + +#define mmx_fetch(mem,hint) \ + __asm__ __volatile__ ("prefetch" #hint " %0" \ + : /* nothing */ \ + : "X" (mem)) + + +#define maskmovq(regs,maskreg) mmx_r2ri (maskmovq, regs, maskreg) + +#define movntq_r2m(mmreg,var) mmx_r2m (movntq, mmreg, var) + +#define pavgb_m2r(var,reg) mmx_m2r (pavgb, var, reg) +#define pavgb_r2r(regs,regd) mmx_r2r (pavgb, regs, regd) +#define pavgw_m2r(var,reg) mmx_m2r (pavgw, var, reg) +#define pavgw_r2r(regs,regd) mmx_r2r (pavgw, regs, regd) + +#define pextrw_r2r(mmreg,reg,imm) mmx_r2ri (pextrw, mmreg, reg, imm) + +#define pinsrw_r2r(reg,mmreg,imm) mmx_r2ri (pinsrw, reg, mmreg, imm) + +#define pmaxsw_m2r(var,reg) mmx_m2r (pmaxsw, var, reg) +#define pmaxsw_r2r(regs,regd) mmx_r2r (pmaxsw, regs, regd) + +#define pmaxub_m2r(var,reg) mmx_m2r (pmaxub, var, reg) +#define pmaxub_r2r(regs,regd) mmx_r2r (pmaxub, regs, regd) + +#define pminsw_m2r(var,reg) mmx_m2r (pminsw, var, reg) +#define pminsw_r2r(regs,regd) mmx_r2r (pminsw, regs, regd) + +#define pminub_m2r(var,reg) mmx_m2r (pminub, var, reg) +#define pminub_r2r(regs,regd) mmx_r2r (pminub, regs, regd) + +#define pmovmskb(mmreg,reg) \ + __asm__ __volatile__ ("movmskps %" #mmreg ", %" #reg) + +#define pmulhuw_m2r(var,reg) mmx_m2r (pmulhuw, var, reg) +#define pmulhuw_r2r(regs,regd) mmx_r2r (pmulhuw, regs, regd) + +#define prefetcht0(mem) mmx_fetch (mem, t0) +#define prefetcht1(mem) mmx_fetch (mem, t1) +#define prefetcht2(mem) mmx_fetch (mem, t2) +#define prefetchnta(mem) mmx_fetch (mem, nta) + +#define psadbw_m2r(var,reg) mmx_m2r (psadbw, var, reg) +#define psadbw_r2r(regs,regd) mmx_r2r (psadbw, regs, regd) + +#define pshufw_m2r(var,reg,imm) mmx_m2ri(pshufw, var, reg, imm) +#define pshufw_r2r(regs,regd,imm) mmx_r2ri(pshufw, regs, regd, imm) + +#define sfence() __asm__ __volatile__ ("sfence\n\t") + + +#endif + + diff --git a/mpeglib/lib/util/render/Makefile.am b/mpeglib/lib/util/render/Makefile.am new file mode 100644 index 00000000..24bc691f --- /dev/null +++ b/mpeglib/lib/util/render/Makefile.am @@ -0,0 +1,59 @@ +# player - Makefile.am + +SUBDIRS = dither dither2YUV x11 sdl + +INCLUDES = $(all_includes) + +THIS_EXTRALIBS = dither/libdither.la \ + dither2YUV/libdivxutil_dither.la \ + x11/libutilx11.la + + +noinst_LTLIBRARIES = libutilrender.la + +noinst_HEADERS = imageBase.h \ + renderMachine.h surface.h + + +kmpgincludedir = $(includedir)/$(THIS_LIB_NAME)/util/render + +kmpginclude_HEADERS = yuvPicture.h pictureArray.h + + +libutilrender_la_SOURCES = yuvPicture.cpp imageBase.cpp \ + renderMachine.cpp surface.cpp \ + pictureArray.cpp + +libutilrender_la_LIBADD = $(THIS_EXTRALIBS) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mpeglib/lib/util/render/dither/Makefile.am b/mpeglib/lib/util/render/dither/Makefile.am new file mode 100644 index 00000000..166d5ca3 --- /dev/null +++ b/mpeglib/lib/util/render/dither/Makefile.am @@ -0,0 +1,40 @@ +# liboutplugin - Makefile.am + +INCLUDES = $(all_includes) + +EXTRA_DIST = ditherDef.h ditherMMX.h \ + ditherer_mmx16.cpp dither32mmx.cpp + +noinst_LTLIBRARIES = libdither.la + +noinst_HEADERS = ditherWrapper.h \ + dither8Bit.h colorTable8Bit.h \ + colorTableHighBit.h dither16Bit.h \ + dither32Bit.h ditherRGB_flipped.h \ + ditherRGB.h + +libdither_la_SOURCES = ditherWrapper.cpp \ + dither8Bit.cpp \ + colorTable8Bit.cpp colorTableHighBit.cpp \ + dither16Bit.cpp dither32Bit.cpp \ + ditherRGB_flipped.cpp ditherRGB.cpp \ + ditherer_mmx16.cpp dither32mmx.cpp + + + + + + + + + + + + + + + + + + + diff --git a/mpeglib/lib/util/render/dither/colorTable8Bit.cpp b/mpeglib/lib/util/render/dither/colorTable8Bit.cpp new file mode 100644 index 00000000..57c533de --- /dev/null +++ b/mpeglib/lib/util/render/dither/colorTable8Bit.cpp @@ -0,0 +1,147 @@ +/* + colorTables for 8 Bit depth + 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 "colorTable8Bit.h" + + +ColorTable8Bit::ColorTable8Bit() { + + lum_values = new int[LUM_RANGE]; + cr_values = new int[CR_RANGE]; + cb_values = new int[CB_RANGE]; + + + /* We can exploit cache by allocating contiguous blocks */ + + colortab = new TABTYPE[5*256]; + + Cr_r_tab = &colortab[0*256]; + Cr_g_tab = &colortab[1*256]; + Cb_g_tab = &colortab[2*256]; + Cb_b_tab = &colortab[3*256]; + L_tab = &colortab[4*256]; + + init8BitColor(); +} + + +ColorTable8Bit::~ColorTable8Bit() { + delete lum_values; + delete cr_values; + delete cb_values; + delete colortab; +} + + +void ColorTable8Bit::init8BitColor() { + int i; + + + + for (i=0; i<LUM_RANGE; i++) { + lum_values[i] = ((i * 256) / (LUM_RANGE)) + (256/(LUM_RANGE*2)); + L_tab[i] = lum_values[i]; + if (gammaCorrectFlag) { + L_tab[i] = GAMMA_CORRECTION(L_tab[i]); + } + + } + + + for (i=0; i<CR_RANGE; i++) { + register double tmp; + if (chromaCorrectFlag) { + tmp = ((i * 256) / (CR_RANGE)) + (256/(CR_RANGE*2)); + Cr_r_tab[i]=(TABTYPE) ((0.419/0.299)*CHROMA_CORRECTION128D(tmp-128.0)); + Cr_g_tab[i]=(TABTYPE) (-(0.299/0.419)*CHROMA_CORRECTION128D(tmp-128.0)); + cr_values[i] = CHROMA_CORRECTION256(tmp); + } else { + tmp = ((i * 256) / (CR_RANGE)) + (256/(CR_RANGE*2)); + Cr_r_tab[i] = (TABTYPE) ((0.419/0.299) * (tmp - 128.0)); + Cr_g_tab[i] = (TABTYPE) (-(0.299/0.419) * (tmp - 128.0)); + cr_values[i] = (int) tmp; + } + } + + + for (i=0; i<CB_RANGE; i++) { + register double tmp; + if (chromaCorrectFlag) { + tmp = ((i * 256) / (CB_RANGE)) + (256/(CB_RANGE*2)); + Cb_g_tab[i]=(TABTYPE) (-(0.114/0.331)*CHROMA_CORRECTION128D(tmp-128.0)); + Cb_b_tab[i]=(TABTYPE) ((0.587/0.331)*CHROMA_CORRECTION128D(tmp-128.0)); + cb_values[i] = CHROMA_CORRECTION256(tmp); + } else { + tmp = ((i * 256) / (CB_RANGE)) + (256/(CB_RANGE*2)); + Cb_g_tab[i] = (TABTYPE) (-(0.114/0.331) * (tmp - 128.0)); + Cb_b_tab[i] = (TABTYPE) ((0.587/0.331) * (tmp - 128.0)); + cb_values[i] = (int) tmp; + } + } +} + + + +/* + *-------------------------------------------------------------- + * + * ConvertColor -- + * + * Given a l, cr, cb tuple, converts it to r,g,b. + * + * Results: + * r,g,b values returned in pointers passed as parameters. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ +void ColorTable8Bit::ConvertColor(unsigned int l, unsigned int cr, + unsigned int cb, unsigned char* r, + unsigned char* g, unsigned char* b) { + + double fl, fr, fg, fb; + + /* + * Old method w/o lookup table + * + * fl = 1.164*(((double) l)-16.0); + * fcr = ((double) cr) - 128.0; + * fcb = ((double) cb) - 128.0; + * + * fr = fl + (1.366 * fcr); + * fg = fl - (0.700 * fcr) - (0.334 * fcb); + * fb = fl + (1.732 * fcb); + */ + + fl = L_tab[l]; + + fr = fl + Cr_r_tab[cr]; + fg = fl + Cr_g_tab[cr] + Cb_g_tab[cb]; + fb = fl + Cb_b_tab[cb]; + + if (fr < 0.0) fr = 0.0; + else if (fr > 255.0) fr = 255.0; + + if (fg < 0.0) fg = 0.0; + else if (fg > 255.0) fg = 255.0; + + if (fb < 0.0) fb = 0.0; + else if (fb > 255.0) fb = 255.0; + + *r = (unsigned char) fr; + *g = (unsigned char) fg; + *b = (unsigned char) fb; + +} diff --git a/mpeglib/lib/util/render/dither/colorTable8Bit.h b/mpeglib/lib/util/render/dither/colorTable8Bit.h new file mode 100644 index 00000000..6d873d1d --- /dev/null +++ b/mpeglib/lib/util/render/dither/colorTable8Bit.h @@ -0,0 +1,57 @@ +/* + colorTables for 8 Bit depth + 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 __COLORTABLE8BIT_H +#define __COLORTABLE8BIT_H + +#include "ditherDef.h" + + +class ColorTable8Bit { + + // Arrays holding quantized value ranged for lum, cr, and cb. + // (used for 8 Bit) + + int* lum_values; + int* cr_values; + int* cb_values; + + + + + TABTYPE *L_tab; + TABTYPE *Cr_r_tab; + TABTYPE *Cr_g_tab; + TABTYPE *Cb_g_tab; + TABTYPE *Cb_b_tab; + TABTYPE *colortab; + + + public: + ColorTable8Bit(); + ~ColorTable8Bit(); + + inline int* getLumValues() { return lum_values; } + inline int* getCrValues() { return cr_values; } + inline int* getCbValues() { return cb_values; } + + void ConvertColor(unsigned int l, unsigned int cr, unsigned int cb, + unsigned char* r, unsigned char* g, unsigned char* b); + + + private: + void init8BitColor(); + + +}; +#endif diff --git a/mpeglib/lib/util/render/dither/colorTableHighBit.cpp b/mpeglib/lib/util/render/dither/colorTableHighBit.cpp new file mode 100644 index 00000000..171f4e97 --- /dev/null +++ b/mpeglib/lib/util/render/dither/colorTableHighBit.cpp @@ -0,0 +1,248 @@ +/* + colorTables for 16,32 Bit depth + 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 "colorTableHighBit.h" + +//#define INTERPOLATE + + +/* + * Erik Corry's multi-byte dither routines. + * + * The basic idea is that the Init generates all the necessary tables. + * The tables incorporate the information about the layout of pixels + * in the XImage, so that it should be able to cope with 15-bit, 16-bit + * 24-bit (non-packed) and 32-bit (10-11 bits per color!) screens. + * At present it cannot cope with 24-bit packed mode, since this involves + * getting down to byte level again. It is assumed that the bits for each + * color are contiguous in the longword. + * + * Writing to memory is done in shorts or ints. (Unfortunately, short is not + * very fast on Alpha, so there is room for improvement here). There is no + * dither time check for overflow - instead the tables have slack at + * each end. This is likely to be faster than an 'if' test as many modern + * architectures are really bad at ifs. Potentially, each '&&' causes a + * pipeline flush! + * + * There is no shifting and fixed point arithmetic, as I really doubt you + * can see the difference, and it costs. This may be just my bias, since I + * heard that Intel is really bad at shifting. + */ + + +/* + * How many 1 bits are there in the PIXVALword. + * Low performance, do not call often. + */ +static int number_of_bits_set(unsigned PIXVAL a) { + if(!a) return 0; + if(a & 1) return 1 + number_of_bits_set(a >> 1); + return(number_of_bits_set(a >> 1)); +} + + + +/* + * How many 0 bits are there at most significant end of PIXVALword. + * Low performance, do not call often. + */ +static int free_bits_at_top(unsigned PIXVAL a) { + /* assume char is 8 bits */ + if(!a) return sizeof(unsigned PIXVAL) * 8; + /* assume twos complement */ + if(((PIXVAL)a) < 0l) return 0; + return 1 + free_bits_at_top ( a << 1); +} + +/* + * How many 0 bits are there at least significant end of PIXVALword. + * Low performance, do not call often. + */ +static int free_bits_at_bottom(unsigned PIXVAL a) { + /* assume char is 8 bits */ + if(!a) return sizeof(unsigned PIXVAL) * 8; + if(((PIXVAL)a) & 1l) return 0; + return 1 + free_bits_at_bottom ( a >> 1); +} + + + +ColorTableHighBit::ColorTableHighBit(int bpp,unsigned int redMask, + unsigned int greenMask, + unsigned int blueMask) { + this->bpp=bpp; + this->redMask=redMask; + this->greenMask=greenMask; + this->blueMask=blueMask; + + colortab = new TABTYPE[5*256]; + + Cr_r_tab = &colortab[0*256]; + Cr_g_tab = &colortab[1*256]; + Cb_g_tab = &colortab[2*256]; + Cb_b_tab = &colortab[3*256]; + L_tab = &colortab[4*256]; + + rgb_2_pix = new PIXVAL [3*768]; + + r_2_pix_alloc = &rgb_2_pix[0*768]; + g_2_pix_alloc = &rgb_2_pix[1*768]; + b_2_pix_alloc = &rgb_2_pix[2*768]; + + initHighColor(bpp>=24,redMask,greenMask,blueMask); + +} + + +ColorTableHighBit::~ColorTableHighBit() { + delete colortab; + delete rgb_2_pix; +} + +/* + *-------------------------------------------------------------- + * + * InitColor16Dither -- + * + * To get rid of the multiply and other conversions in color + * dither, we use a lookup table. + * + * Results: + * None. + * + * Side effects: + * The lookup tables are initialized. + * + *-------------------------------------------------------------- + */ + +void ColorTableHighBit::initHighColor(int thirty2,unsigned int redMask, + unsigned int greenMask, + unsigned int blueMask) { + + unsigned PIXVAL red_mask = redMask; + unsigned PIXVAL green_mask =greenMask; + unsigned PIXVAL blue_mask = blueMask; + + int CR, CB, i; + + + for (i=0; i<256; i++) { + L_tab[i] = i; + if (gammaCorrectFlag) { + L_tab[i] = (TABTYPE)GAMMA_CORRECTION(i); + } + + CB = CR = i; + + if (chromaCorrectFlag) { + CB -= 128; + CB = CHROMA_CORRECTION128(CB); + CR -= 128; + CR = CHROMA_CORRECTION128(CR); + } else { + CB -= 128; CR -= 128; + } +/* was + Cr_r_tab[i] = 1.596 * CR; + Cr_g_tab[i] = -0.813 * CR; + Cb_g_tab[i] = -0.391 * CB; + Cb_b_tab[i] = 2.018 * CB; + but they were just messed up. + Then was (_Video Deymstified_): + Cr_r_tab[i] = 1.366 * CR; + Cr_g_tab[i] = -0.700 * CR; + Cb_g_tab[i] = -0.334 * CB; + Cb_b_tab[i] = 1.732 * CB; + but really should be: + (from ITU-R BT.470-2 System B, G and SMPTE 170M ) +*/ + Cr_r_tab[i] = (TABTYPE) ( (0.419/0.299) * CR ); + Cr_g_tab[i] = (TABTYPE) ( -(0.299/0.419) * CR ); + Cb_g_tab[i] = (TABTYPE) ( -(0.114/0.331) * CB ); + Cb_b_tab[i] = (TABTYPE) ( (0.587/0.331) * CB ); + +/* + though you could argue for: + SMPTE 240M + Cr_r_tab[i] = (0.445/0.212) * CR; + Cr_g_tab[i] = -(0.212/0.445) * CR; + Cb_g_tab[i] = -(0.087/0.384) * CB; + Cb_b_tab[i] = (0.701/0.384) * CB; + FCC + Cr_r_tab[i] = (0.421/0.30) * CR; + Cr_g_tab[i] = -(0.30/0.421) * CR; + Cb_g_tab[i] = -(0.11/0.331) * CB; + Cb_b_tab[i] = (0.59/0.331) * CB; + ITU-R BT.709 + Cr_r_tab[i] = (0.454/0.2125) * CR; + Cr_g_tab[i] = -(0.2125/0.454) * CR; + Cb_g_tab[i] = -(0.0721/0.386) * CB; + Cb_b_tab[i] = (0.7154/0.386) * CB; +*/ + } + + /* + * Set up entries 0-255 in rgb-to-pixel value tables. + */ + for (i = 0; i < 256; i++) { + r_2_pix_alloc[i + 256] = i >> (8 - number_of_bits_set(red_mask)); + r_2_pix_alloc[i + 256] <<= free_bits_at_bottom(red_mask); + g_2_pix_alloc[i + 256] = i >> (8 - number_of_bits_set(green_mask)); + g_2_pix_alloc[i + 256] <<= free_bits_at_bottom(green_mask); + b_2_pix_alloc[i + 256] = i >> (8 - number_of_bits_set(blue_mask)); + b_2_pix_alloc[i + 256] <<= free_bits_at_bottom(blue_mask); + /* + * If we have 16-bit output depth, then we double the value + * in the top word. This means that we can write out both + * pixels in the pixel doubling mode with one op. It is + * harmless in the normal case as storing a 32-bit value + * through a short pointer will lose the top bits anyway. + * A similar optimisation for Alpha for 64 bit has been + * prepared for, but is not yet implemented. + */ + if(!thirty2) { + r_2_pix_alloc[i + 256] |= (r_2_pix_alloc[i + 256]) << 16; + g_2_pix_alloc[i + 256] |= (g_2_pix_alloc[i + 256]) << 16; + b_2_pix_alloc[i + 256] |= (b_2_pix_alloc[i + 256]) << 16; + + } +#ifdef SIXTYFOUR_BIT + if(thirty2) { + + r_2_pix_alloc[i + 256] |= (r_2_pix_alloc[i + 256]) << 32; + g_2_pix_alloc[i + 256] |= (g_2_pix_alloc[i + 256]) << 32; + b_2_pix_alloc[i + 256] |= (b_2_pix_alloc[i + 256]) << 32; + + } +#endif + } + + /* + * Spread out the values we have to the rest of the array so that + * we do not need to check for overflow. + */ + for (i = 0; i < 256; i++) { + r_2_pix_alloc[i] = r_2_pix_alloc[256]; + r_2_pix_alloc[i+ 512] = r_2_pix_alloc[511]; + g_2_pix_alloc[i] = g_2_pix_alloc[256]; + g_2_pix_alloc[i+ 512] = g_2_pix_alloc[511]; + b_2_pix_alloc[i] = b_2_pix_alloc[256]; + b_2_pix_alloc[i+ 512] = b_2_pix_alloc[511]; + } + + r_2_pix = r_2_pix_alloc + 256; + g_2_pix = g_2_pix_alloc + 256; + b_2_pix = b_2_pix_alloc + 256; +} diff --git a/mpeglib/lib/util/render/dither/colorTableHighBit.h b/mpeglib/lib/util/render/dither/colorTableHighBit.h new file mode 100644 index 00000000..9945414d --- /dev/null +++ b/mpeglib/lib/util/render/dither/colorTableHighBit.h @@ -0,0 +1,73 @@ +/* + colorTables for 16,32 Bit depth + 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 __COLORTABLEHIGHBIT_H +#define __COLORTABLEHIGHBIT_H + +#include "ditherDef.h" + + + + +class ColorTableHighBit { + + TABTYPE *L_tab; + TABTYPE *Cr_r_tab; + TABTYPE *Cr_g_tab; + TABTYPE *Cb_g_tab; + TABTYPE *Cb_b_tab; + TABTYPE *colortab; + + + PIXVAL *r_2_pix; + PIXVAL *g_2_pix; + PIXVAL *b_2_pix; + PIXVAL *rgb_2_pix; + + PIXVAL *r_2_pix_alloc; + PIXVAL *g_2_pix_alloc; + PIXVAL *b_2_pix_alloc; + + + + // init stuff + int bpp; + // colorMask + unsigned int redMask; + unsigned int greenMask; + unsigned int blueMask; + + public: + ColorTableHighBit(int bpp,unsigned int redMask, + unsigned int greenMask,unsigned int blueMask); + ~ColorTableHighBit(); + + inline TABTYPE* getL_tab() { return L_tab ; } + inline TABTYPE* getCr_r_tab() { return Cr_r_tab ; } + inline TABTYPE* getCr_g_tab() { return Cr_g_tab ; } + inline TABTYPE* getCb_g_tab() { return Cb_g_tab ; } + inline TABTYPE* getCb_b_tab() { return Cb_b_tab ; } + + + inline PIXVAL* getr_2_pix() { return r_2_pix ; } + inline PIXVAL* getg_2_pix() { return g_2_pix ; } + inline PIXVAL* getb_2_pix() { return b_2_pix ; } + + + + private: + void initHighColor(int thirty2,unsigned int redMask, + unsigned int greenMask,unsigned int blueMask); + +}; +#endif diff --git a/mpeglib/lib/util/render/dither/dither16Bit.cpp b/mpeglib/lib/util/render/dither/dither16Bit.cpp new file mode 100644 index 00000000..0a843ee9 --- /dev/null +++ b/mpeglib/lib/util/render/dither/dither16Bit.cpp @@ -0,0 +1,300 @@ +/* + dither 16 bit depth yuv images + 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 "dither16Bit.h" + + +Dither16Bit::Dither16Bit(unsigned int redMask, + unsigned int greenMask,unsigned int blueMask) { + + + colorTableHighBit=new ColorTableHighBit(16,redMask,greenMask,blueMask); + L_tab=colorTableHighBit->getL_tab(); + Cr_r_tab=colorTableHighBit->getCr_r_tab(); + Cr_g_tab=colorTableHighBit->getCr_g_tab(); + Cb_g_tab=colorTableHighBit->getCb_g_tab(); + Cb_b_tab=colorTableHighBit->getCb_b_tab(); + + r_2_pix=colorTableHighBit->getr_2_pix(); + g_2_pix=colorTableHighBit->getg_2_pix(); + b_2_pix=colorTableHighBit->getb_2_pix(); + +} + + +Dither16Bit::~Dither16Bit() { + delete colorTableHighBit; +} + + +/* + *-------------------------------------------------------------- + * + * Color16DitherImage -- + * + * Converts image into 16 bit color. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +void Dither16Bit::ditherImageColor16(unsigned char* lum, + unsigned char* cr, + unsigned char* cb, + unsigned char* out, + int rows, + int cols, + int offset) { + + int L, CR, CB; + unsigned short *row1, *row2; + unsigned char *lum2; + int x, y; + int cr_r; + int cr_g; + int cb_g; + int cb_b; + int cols_2 = cols/2; + + row1 = (unsigned short *)out; + row2=row1+cols_2+cols_2+offset; // start of second row + + offset=2*offset+cols_2+cols_2; + + lum2 = lum + cols_2 + cols_2; + + + for (y=0; y<rows; y+=2) { + for (x=0; x<cols_2; x++) { + int R, G, B; + + CR = *cr++; + CB = *cb++; + cr_r = Cr_r_tab[CR]; + cr_g = Cr_g_tab[CR]; + cb_g = Cb_g_tab[CB]; + cb_b = Cb_b_tab[CB]; + + L = L_tab[(int) *lum++]; + + R = L + cr_r; + G = L + cr_g + cb_g; + B = L + cb_b; + + *row1++ = (r_2_pix[R] | g_2_pix[G] | b_2_pix[B]); + + +#ifdef INTERPOLATE + if(x != cols_2 - 1) { + CR = (CR + *cr) >> 1; + CB = (CB + *cb) >> 1; + cr_r = Cr_r_tab[CR]; + cr_g = Cr_g_tab[CR]; + cb_g = Cb_g_tab[CB]; + cb_b = Cb_b_tab[CB]; + } +#endif + + L = L_tab[(int) *lum++]; + + R = L + cr_r; + G = L + cr_g + cb_g; + B = L + cb_b; + + *row1++ = (r_2_pix[R] | g_2_pix[G] | b_2_pix[B]); + + /* + * Now, do second row. + */ +#ifdef INTERPOLATE + if(y != rows - 2) { + CR = (CR + *(cr + cols_2 - 1)) >> 1; + CB = (CB + *(cb + cols_2 - 1)) >> 1; + cr_r = Cr_r_tab[CR]; + cr_g = Cr_g_tab[CR]; + cb_g = Cb_g_tab[CB]; + cb_b = Cb_b_tab[CB]; + } +#endif + + L = L_tab[(int) *lum2++]; + R = L + cr_r; + G = L + cr_g + cb_g; + B = L + cb_b; + + *row2++ = (r_2_pix[R] | g_2_pix[G] | b_2_pix[B]); + + L = L_tab[(int) *lum2++]; + R = L + cr_r; + G = L + cr_g + cb_g; + B = L + cb_b; + + *row2++ = (r_2_pix[R] | g_2_pix[G] | b_2_pix[B]); + } + /* + * These values are at the start of the next line, (due + * to the ++'s above),but they need to be at the start + * of the line after that. + */ + lum += cols_2 + cols_2; + lum2 += cols_2 + cols_2; + row1 += offset; + row2 += offset; + } +} + + +/* + * Erik Corry's pixel doubling routines for 15/16/24/32 bit screens. + */ + + +/* + *-------------------------------------------------------------- + * + * Twox2Color16DitherImage -- + * + * Converts image into 16 bit color at double size. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +/* + * In this function I make use of a nasty trick. The tables have the lower + * 16 bits replicated in the upper 16. This means I can write ints and get + * the horisontal doubling for free (almost). + */ + +void Dither16Bit::ditherImageTwox2Color16(unsigned char* lum, + unsigned char* cr, + unsigned char* cb, + unsigned char* out, + int rows, + int cols, + int mod) { + int L, CR, CB; + unsigned int *row1 = (unsigned int *)out; + unsigned int *row2 = row1 + cols + mod/2; + unsigned int *row3 = row2 + cols + mod/2; + unsigned int *row4 = row3 + cols + mod/2; + unsigned char *lum2; + int x, y; + int cr_r; + int cr_g; + int cb_g; + int cb_b; + int cols_2 = cols/2; + + lum2 = lum + cols_2 + cols_2; + for (y=0; y<rows; y+=2) { + for (x=0; x<cols_2; x++) { + int R, G, B; + int t; + + CR = *cr++; + CB = *cb++; + cr_r = Cr_r_tab[CR]; + cr_g = Cr_g_tab[CR]; + cb_g = Cb_g_tab[CB]; + cb_b = Cb_b_tab[CB]; + + L = L_tab[(int) *lum++]; + + R = L + cr_r; + G = L + cr_g + cb_g; + B = L + cb_b; + + t = (r_2_pix[R] | g_2_pix[G] | b_2_pix[B]); + row1[0] = t; + row1++; + row2[0] = t; + row2++; + + // INTERPOLATE + if(x != cols_2 - 1) { + CR = (CR + *cr) >> 1; + CB = (CB + *cb) >> 1; + cr_r = Cr_r_tab[CR]; + cr_g = Cr_g_tab[CR]; + cb_g = Cb_g_tab[CB]; + cb_b = Cb_b_tab[CB]; + } + // end + + L = L_tab[(int) *lum++]; + + R = L + cr_r; + G = L + cr_g + cb_g; + B = L + cb_b; + + t = (r_2_pix[R] | g_2_pix[G] | b_2_pix[B]); + row1[0] = t; + row1++; + row2[0] = t; + row2++; + + /* + * Now, do second row. + */ + // INTERPOLATE + if(y != rows - 2) { + CR = (CR + *(cr + cols_2 - 1)) >> 1; + CB = (CB + *(cb + cols_2 - 1)) >> 1; + cr_r = Cr_r_tab[CR]; + cr_g = Cr_g_tab[CR]; + cb_g = Cb_g_tab[CB]; + cb_b = Cb_b_tab[CB]; + } + // end + + L = L_tab[(int) *lum2++]; + R = L + cr_r; + G = L + cr_g + cb_g; + B = L + cb_b; + + t = (r_2_pix[R] | g_2_pix[G] | b_2_pix[B]); + row3[0] = t; + row3++; + row4[0] = t; + row4++; + + L = L_tab[(int) *lum2++]; + R = L + cr_r; + G = L + cr_g + cb_g; + B = L + cb_b; + + t = (r_2_pix[R] | g_2_pix[G] | b_2_pix[B]); + row3[0] = t; + row3++; + row4[0] = t; + row4++; + } + lum += cols_2 + cols_2; + lum2 += cols_2 + cols_2; + row1 += 6 * cols_2 + 2*mod; + row3 += 6 * cols_2 + 2*mod; + row2 += 6 * cols_2 + 2*mod; + row4 += 6 * cols_2 + 2*mod; + } +} diff --git a/mpeglib/lib/util/render/dither/dither16Bit.h b/mpeglib/lib/util/render/dither/dither16Bit.h new file mode 100644 index 00000000..2e47c01c --- /dev/null +++ b/mpeglib/lib/util/render/dither/dither16Bit.h @@ -0,0 +1,55 @@ +/* + dither 16 bit depth yuv images + 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 __DITHER16Bit_H +#define __DITHER16Bit_H + +#include "colorTableHighBit.h" + +class Dither16Bit { + + ColorTableHighBit* colorTableHighBit; + + TABTYPE *L_tab; + TABTYPE *Cr_r_tab; + TABTYPE *Cr_g_tab; + TABTYPE *Cb_g_tab; + TABTYPE *Cb_b_tab; + + PIXVAL *r_2_pix; + PIXVAL *g_2_pix; + PIXVAL *b_2_pix; + + public: + Dither16Bit(unsigned int redMask, + unsigned int greenMask,unsigned int blueMask); + ~Dither16Bit(); + + void ditherImageColor16(unsigned char* lum, + unsigned char* cr, + unsigned char* cb, + unsigned char* out, + int rows, + int cols, + int offset); + + void ditherImageTwox2Color16(unsigned char* lum, + unsigned char* cr, + unsigned char* cb, + unsigned char* out, + int rows, + int cols, + int mod); + +}; + +#endif diff --git a/mpeglib/lib/util/render/dither/dither32Bit.cpp b/mpeglib/lib/util/render/dither/dither32Bit.cpp new file mode 100644 index 00000000..61a1d2dc --- /dev/null +++ b/mpeglib/lib/util/render/dither/dither32Bit.cpp @@ -0,0 +1,253 @@ +/* + dither 32 bit depth yuv images + 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 "dither32Bit.h" + + +#define doRow(row,Lum) *row++=(local_r_2_pix[Lum] | \ + local_g_2_pix[Lum] | local_b_2_pix[Lum]) + + +Dither32Bit::Dither32Bit(unsigned int redMask, + unsigned int greenMask,unsigned int blueMask) { + + + colorTableHighBit=new ColorTableHighBit(32,redMask,greenMask,blueMask); + L_tab=colorTableHighBit->getL_tab(); + Cr_r_tab=colorTableHighBit->getCr_r_tab(); + Cr_g_tab=colorTableHighBit->getCr_g_tab(); + Cb_g_tab=colorTableHighBit->getCb_g_tab(); + Cb_b_tab=colorTableHighBit->getCb_b_tab(); + + r_2_pix=colorTableHighBit->getr_2_pix(); + g_2_pix=colorTableHighBit->getg_2_pix(); + b_2_pix=colorTableHighBit->getb_2_pix(); + +} + + +Dither32Bit::~Dither32Bit() { + delete colorTableHighBit; +} + + +void Dither32Bit::ditherImageColor32(unsigned char* lum, + unsigned char* cr, + unsigned char* cb, + unsigned char* out, + int rows, + int cols, + int mod) { + + int L; + int n; + int rowWork; + int colWork; + + unsigned int *row1, *row2; + unsigned char *lum2; + PIXVAL* local_r_2_pix; + PIXVAL* local_g_2_pix; + PIXVAL* local_b_2_pix; + + row1 = (unsigned int *)out; + + row2 = row1+cols+mod; + lum2 = lum+cols; + + // because the width/height are a multiply of a macroblocksize + // cols/rows always are even + colWork=cols>>1; + rowWork=rows>>1; + mod=cols+2*mod; + + while(rowWork--) { + n=colWork; + while(n--) { + + local_r_2_pix=r_2_pix+Cr_r_tab[*cr]; + local_g_2_pix=g_2_pix+Cr_g_tab[*cr++] + Cb_g_tab[*cb]; + local_b_2_pix=b_2_pix+Cb_b_tab[*cb++]; + + L = L_tab[*lum++]; + doRow(row1,L); + + L = L_tab[*lum++]; + doRow(row1,L); + + L = L_tab [*lum2++]; + doRow(row2,L); + + L = L_tab [*lum2++]; + doRow(row2,L); + + + } + row2 += mod; + lum += cols; + lum2 += cols; + row1 += mod; + + } + +} + +/* + *-------------------------------------------------------------- + * + * Twox2Color32 -- + * + * Converts image into 24/32 bit color. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +void Dither32Bit::ditherImageTwox2Color32(unsigned char* lum, + unsigned char* cr, + unsigned char* cb, + unsigned char* out, + int rows, + int cols, + int mod) { + int L, CR, CB; + unsigned PIXVAL *row1 = (unsigned PIXVAL *)out; + unsigned PIXVAL *row2 = row1 + cols * ONE_TWO + mod; + unsigned PIXVAL *row3 = row2 + cols * ONE_TWO + mod; + unsigned PIXVAL *row4 = row3 + cols * ONE_TWO + mod; + unsigned char *lum2; + int x, y; + int cr_r; + int cr_g; + int cb_g; + int cb_b; + int cols_2 = cols/2; + int loffset = ONE_TWO * 6 *cols_2 + 4*mod ; + + lum2 = lum + cols_2 + cols_2; + for (y=0; y<rows; y+=2) { + for (x=0; x<cols_2; x++) { + int R, G, B; + PIXVAL t; + + CR = *cr++; + CB = *cb++; + cr_r = Cr_r_tab[CR]; + cr_g = Cr_g_tab[CR]; + cb_g = Cb_g_tab[CB]; + cb_b = Cb_b_tab[CB]; + + L = L_tab[ (int) *lum++]; + + R = L + cr_r; + G = L + cr_g + cb_g; + B = L + cb_b; + + t = (r_2_pix[R] | g_2_pix[G] | b_2_pix[B]); + row1[0] = t; + row2[0] = t; +#ifndef SIXTYFOUR_BIT + row1[1] = t; + row2[1] = t; +#endif + row1 += ONE_TWO; + row2 += ONE_TWO; + + /* INTERPOLATE is now standard */ + // INTERPOLATE + if(x != cols_2 - 1) { + CR = (CR + *cr) >> 1; + CB = (CB + *cb) >> 1; + cr_r = Cr_r_tab[CR]; + cr_g = Cr_g_tab[CR]; + cb_g = Cb_g_tab[CB]; + cb_b = Cb_b_tab[CB]; + } + // end + /* end INTERPOLATE */ + + L = L_tab[ (int) *lum++]; + + R = L + cr_r; + G = L + cr_g + cb_g; + B = L + cb_b; + + t = (r_2_pix[R] | g_2_pix[G] | b_2_pix[B]); + row1[0] = t; + row2[0] = t; +#ifndef SIXTYFOUR_BIT + row1[1] = t; + row2[1] = t; +#endif + row1 += ONE_TWO; + row2 += ONE_TWO; + + /* + * Now, do second row. + */ + /* INTERPOLATE is now standard */ + // INTERPOLATE + if(y != rows - 2) { + CR = (unsigned int) (CR + *(cr + cols_2 - 1)) >> 1; + CB = (unsigned int) (CB + *(cb + cols_2 - 1)) >> 1; + cr_r = Cr_r_tab[CR]; + cr_g = Cr_g_tab[CR]; + cb_g = Cb_g_tab[CB]; + cb_b = Cb_b_tab[CB]; + } + // end + /* endif */ + L = L_tab[ (int) *lum2++]; + R = L + cr_r; + G = L + cr_g + cb_g; + B = L + cb_b; + + t = (r_2_pix[R] | g_2_pix[G] | b_2_pix[B]); + row3[0] = t; + row4[0] = t; +#ifndef SIXTYFOUR_BIT + row3[1] = t; + row4[1] = t; +#endif + row3 += ONE_TWO; + row4 += ONE_TWO; + + L = L_tab[(int) *lum2++]; + R = L + cr_r; + G = L + cr_g + cb_g; + B = L + cb_b; + + t = (r_2_pix[R] | g_2_pix[G] | b_2_pix[B]); + row3[0] = t; + row4[0] = t; +#ifndef SIXTYFOUR_BIT + row3[1] = t; + row4[1] = t; +#endif + row3 += ONE_TWO; + row4 += ONE_TWO; + } + lum += cols_2 + cols_2; + lum2 += cols_2 + cols_2; + + row1 += loffset; + row3 += loffset; + row2 += loffset; + row4 += loffset; + } +} diff --git a/mpeglib/lib/util/render/dither/dither32Bit.h b/mpeglib/lib/util/render/dither/dither32Bit.h new file mode 100644 index 00000000..440d021a --- /dev/null +++ b/mpeglib/lib/util/render/dither/dither32Bit.h @@ -0,0 +1,55 @@ +/* + dither 32 bit depth yuv images + 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 __DITHER32Bit_H +#define __DITHER32Bit_H + +#include "colorTableHighBit.h" + +class Dither32Bit { + + ColorTableHighBit* colorTableHighBit; + + TABTYPE *L_tab; + TABTYPE *Cr_r_tab; + TABTYPE *Cr_g_tab; + TABTYPE *Cb_g_tab; + TABTYPE *Cb_b_tab; + + PIXVAL *r_2_pix; + PIXVAL *g_2_pix; + PIXVAL *b_2_pix; + + public: + Dither32Bit(unsigned int redMask, + unsigned int greenMask,unsigned int blueMask); + ~Dither32Bit(); + + void ditherImageColor32(unsigned char* lum, + unsigned char* cr, + unsigned char* cb, + unsigned char* out, + int rows, + int cols, + int offset); + + void ditherImageTwox2Color32(unsigned char* lum, + unsigned char* cr, + unsigned char* cb, + unsigned char* out, + int rows, + int cols, + int mod); + +}; + +#endif diff --git a/mpeglib/lib/util/render/dither/dither32mmx.cpp b/mpeglib/lib/util/render/dither/dither32mmx.cpp new file mode 100644 index 00000000..b5fa4807 --- /dev/null +++ b/mpeglib/lib/util/render/dither/dither32mmx.cpp @@ -0,0 +1,272 @@ +/* + MMX ditherer for 32 bit displays + 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 "ditherMMX.h" + +#include <iostream> + +using namespace std; + + +#ifndef INTEL + void dither32_mmx(unsigned char* lum, + unsigned char* cr, + unsigned char* cb, + unsigned char* out, + int rows, + int cols, + int mod) { + printf("urgs! dither32_mmx \n"); + printf("never should happen!\n"); + exit(0); +} + +#else + + +static unsigned long MMX32_80w[] = {0x00800080, 0x00800080}; +static unsigned long MMX32_10w[] = {0x00100010, 0x00100010}; +static unsigned long MMX32_00FFw[] = {0x00ff00ff, 0x00ff00ff}; +static unsigned long MMX32_FF00w[] = {0xff00ff00, 0xff00ff00}; +static unsigned short MMX32_Ycoeff[] = {0x4a, 0x4a, 0x4a, 0x4a}; +static unsigned short MMX32_Vredcoeff[] = {0x59, 0x59, 0x59, 0x59}; +static unsigned short MMX32_Ubluecoeff[] = {0x72, 0x72, 0x72, 0x72}; +static unsigned short MMX32_Ugrncoeff[] = {0xffea,0xffea,0xffea,0xffea}; +static unsigned short MMX32_Vgrncoeff[] = {0xffd2,0xffd2,0xffd2,0xffd2}; + +void dummy_dithermmx32() { + cout << "MMX32_10w:"<<MMX32_10w<<endl; + cout << "MMX32_80w:"<<MMX32_80w<<endl; + cout << "MMX32_Ubluecoeff:"<<MMX32_Ubluecoeff<<endl; + cout << "MMX32_Vredcoeff:"<<MMX32_Vredcoeff<<endl; + cout << "MMX32_Ugrncoeff:"<<MMX32_Ugrncoeff<<endl; + cout << "MMX32_Vgrncoeff:"<<MMX32_Vgrncoeff<<endl; + cout << "MMX32_Ycoeff:"<<MMX32_Ycoeff<<endl; + cout << "MMX32_00FFw:"<<MMX32_00FFw<<endl; + cout << "MMX32_FF00w:"<<MMX32_FF00w<<endl; +} + + +/** + This MMX assembler is my first assembler/MMX program ever. + Thus it maybe buggy. + Send patches to: + mvogt@rhrk.uni-kl.de + + After it worked fine I have "obfuscated" the code a bit to have + more parallism in the MMX units. This means I moved + initilisation around and delayed other instruction. + Performance measurement did not show that this brought any advantage + but in theory it _should_ be faster this way. + + The overall performanve gain to the C based dither was 30%-40%. + The MMX routine calculates 256bit=8RGB values in each cycle + (4 for row1 & 4 for row2) + + The red/green/blue.. coefficents are taken from the mpeg_play + player. They look nice, but I dont know if you can have + better values, to avoid integer rounding errors. + + + IMPORTANT: + ========== + + It is a requirement that the cr/cb/lum are 8 byte aligned and + the out are 16byte aligned or you will/may get segfaults + +*/ + +void dither32_mmx(unsigned char* lum, + unsigned char* cr, + unsigned char* cb, + unsigned char* out, + int rows, + int cols, + int mod) { + + + + unsigned int *row1; + unsigned int *row2; + row1 = (unsigned int *)out; // 32 bit target + + unsigned char* end = lum +cols*rows; // Pointer to the end + int x=cols; + row2=row1+cols+mod; // start of second row + mod=4*cols+8*mod; // increment for row1 in byte + + // buffer for asm function + int buf[6]; + buf[0]=(int)(lum+cols); // lum2 pointer + buf[1]=(int)end; + buf[2]=x; + buf[3]=mod; + buf[4]=0; //tmp0; + buf[5]=cols; + + + __asm__ __volatile__ ( + ".align 32\n" + "1:\n" + + // create Cr (result in mm1) + "movd (%0), %%mm1\n" // 0 0 0 0 v3 v2 v1 v0 + "pxor %%mm7,%%mm7\n" // 00 00 00 00 00 00 00 00 + "movd (%2), %%mm2\n" // 0 0 0 0 l3 l2 l1 l0 + "punpcklbw %%mm7,%%mm1\n" // 0 v3 0 v2 00 v1 00 v0 + "punpckldq %%mm1,%%mm1\n" // 00 v1 00 v0 00 v1 00 v0 + "psubw MMX32_80w,%%mm1\n" // mm1-128:r1 r1 r0 r0 r1 r1 r0 r0 + + // create Cr_g (result in mm0) + "movq %%mm1,%%mm0\n" // r1 r1 r0 r0 r1 r1 r0 r0 + "pmullw MMX32_Vgrncoeff,%%mm0\n" // red*-46dec=0.7136*64 + "pmullw MMX32_Vredcoeff,%%mm1\n" // red*89dec=1.4013*64 + "psraw $6, %%mm0\n" // red=red/64 + "psraw $6, %%mm1\n" // red=red/64 + + + // create L1 L2 (result in mm2,mm4) + // L2=lum2 + "movl %2,16%5\n" // store register in tmp0 + "movl %5,%2\n" // lum2->register + "movd (%2),%%mm3\n" // 0 0 0 0 L3 L2 L1 L0 + "movl 16%5,%2\n" // tmp0->register + "punpckldq %%mm3,%%mm2\n" // L3 L2 L1 L0 l3 l2 l1 l0 + "movq %%mm2,%%mm4\n" // L3 L2 L1 L0 l3 l2 l1 l0 + "pand MMX32_FF00w, %%mm2\n" // L3 0 L1 0 l3 0 l1 0 + "pand MMX32_00FFw, %%mm4\n" // 0 L2 0 L0 0 l2 0 l0 + "psrlw $8,%%mm2\n" // 0 L3 0 L1 0 l3 0 l1 + + + + // create R (result in mm6) + "movq %%mm2,%%mm5\n" // 0 L3 0 L1 0 l3 0 l1 + "movq %%mm4,%%mm6\n" // 0 L2 0 L0 0 l2 0 l0 + "paddsw %%mm1, %%mm5\n" // lum1+red:x R3 x R1 x r3 x r1 + "paddsw %%mm1, %%mm6\n" // lum1+red:x R2 x R0 x r2 x r0 + "packuswb %%mm5,%%mm5\n" // R3 R1 r3 r1 R3 R1 r3 r1 + "packuswb %%mm6,%%mm6\n" // R2 R0 r2 r0 R2 R0 r2 r0 + "pxor %%mm7,%%mm7\n" // 00 00 00 00 00 00 00 00 + "punpcklbw %%mm5,%%mm6\n" // R3 R2 R1 R0 r3 r2 r1 r0 + + + // create Cb (result in mm1) + "movd (%1), %%mm1\n" // 0 0 0 0 u3 u2 u1 u0 + "punpcklbw %%mm7,%%mm1\n" // 0 u3 0 u2 00 u1 00 u0 + "punpckldq %%mm1,%%mm1\n" // 00 u1 00 u0 00 u1 00 u0 + "psubw MMX32_80w,%%mm1\n" // mm1-128:u1 u1 u0 u0 u1 u1 u0 u0 + // create Cb_g (result in mm5) + "movq %%mm1,%%mm5\n" // u1 u1 u0 u0 u1 u1 u0 u0 + "pmullw MMX32_Ugrncoeff,%%mm5\n" // blue*-109dec=1.7129*64 + "pmullw MMX32_Ubluecoeff,%%mm1\n" // blue*114dec=1.78125*64 + "psraw $6, %%mm5\n" // blue=red/64 + "psraw $6, %%mm1\n" // blue=blue/64 + + + // create G (result in mm7) + "movq %%mm2,%%mm3\n" // 0 L3 0 L1 0 l3 0 l1 + "movq %%mm4,%%mm7\n" // 0 L2 0 L0 0 l2 0 l1 + "paddsw %%mm5, %%mm3\n" // lum1+Cb_g:x G3t x G1t x g3t x g1t + "paddsw %%mm5, %%mm7\n" // lum1+Cb_g:x G2t x G0t x g2t x g0t + "paddsw %%mm0, %%mm3\n" // lum1+Cr_g:x G3 x G1 x g3 x g1 + "paddsw %%mm0, %%mm7\n" // lum1+blue:x G2 x G0 x g2 x g0 + "packuswb %%mm3,%%mm3\n" // G3 G1 g3 g1 G3 G1 g3 g1 + "packuswb %%mm7,%%mm7\n" // G2 G0 g2 g0 G2 G0 g2 g0 + "punpcklbw %%mm3,%%mm7\n" // G3 G2 G1 G0 g3 g2 g1 g0 + + + // create B (result in mm5) + "movq %%mm2,%%mm3\n" // 0 L3 0 L1 0 l3 0 l1 + "movq %%mm4,%%mm5\n" // 0 L2 0 L0 0 l2 0 l1 + "paddsw %%mm1, %%mm3\n" // lum1+blue:x B3 x B1 x b3 x b1 + "paddsw %%mm1, %%mm5\n" // lum1+blue:x B2 x B0 x b2 x b0 + "packuswb %%mm3,%%mm3\n" // B3 B1 b3 b1 B3 B1 b3 b1 + "packuswb %%mm5,%%mm5\n" // B2 B0 b2 b0 B2 B0 b2 b0 + "punpcklbw %%mm3,%%mm5\n" // B3 B2 B1 B0 b3 b2 b1 b0 + + + // fill destination row1 (needed are mm6=Rr,mm7=Gg,mm5=Bb) + + "pxor %%mm2,%%mm2\n" // 0 0 0 0 0 0 0 0 + "pxor %%mm4,%%mm4\n" // 0 0 0 0 0 0 0 0 + "movq %%mm6,%%mm1\n" // R3 R2 R1 R0 r3 r2 r1 r0 + "movq %%mm5,%%mm3\n" // B3 B2 B1 B0 b3 b2 b1 b0 + // process lower lum + "punpcklbw %%mm4,%%mm1\n" // 0 r3 0 r2 0 r1 0 r0 + "punpcklbw %%mm4,%%mm3\n" // 0 b3 0 b2 0 b1 0 b0 + "movq %%mm1,%%mm2\n" // 0 r3 0 r2 0 r1 0 r0 + "movq %%mm3,%%mm0\n" // 0 b3 0 b2 0 b1 0 b0 + "punpcklwd %%mm1,%%mm3\n" // 0 r1 0 b1 0 r0 0 b0 + "punpckhwd %%mm2,%%mm0\n" // 0 r3 0 b3 0 r2 0 b2 + + "pxor %%mm2,%%mm2\n" // 0 0 0 0 0 0 0 0 + "movq %%mm7,%%mm1\n" // G3 G2 G1 G0 g3 g2 g1 g0 + "punpcklbw %%mm1,%%mm2\n" // g3 0 g2 0 g1 0 g0 0 + "punpcklwd %%mm4,%%mm2\n" // 0 0 g1 0 0 0 g0 0 + "por %%mm3, %%mm2\n" // 0 r1 g1 b1 0 r0 g0 b0 + "movq %%mm2,(%3)\n" // wrote out ! row1 + + "pxor %%mm2,%%mm2\n" // 0 0 0 0 0 0 0 0 + "punpcklbw %%mm1,%%mm4\n" // g3 0 g2 0 g1 0 g0 0 + "punpckhwd %%mm2,%%mm4\n" // 0 0 g3 0 0 0 g2 0 + "por %%mm0, %%mm4\n" // 0 r3 g3 b3 0 r2 g2 b2 + "movq %%mm4,8(%3)\n" // wrote out ! row1 + + // fill destination row2 (needed are mm6=Rr,mm7=Gg,mm5=Bb) + // this can be done "destructive" + "pxor %%mm2,%%mm2\n" // 0 0 0 0 0 0 0 0 + "punpckhbw %%mm2,%%mm6\n" // 0 R3 0 R2 0 R1 0 R0 + "punpckhbw %%mm1,%%mm5\n" // G3 B3 G2 B2 G1 B1 G0 B0 + "movq %%mm5,%%mm1\n" // G3 B3 G2 B2 G1 B1 G0 B0 + "punpcklwd %%mm6,%%mm1\n" // 0 R1 G1 B1 0 R0 G0 B0 + "movq %%mm1,(%4)\n" // wrote out ! row2 + "punpckhwd %%mm6,%%mm5\n" // 0 R3 G3 B3 0 R2 G2 B2 + "movq %%mm5,8(%4)\n" // wrote out ! row2 + + "addl $4,%2\n" // lum+4 + "addl $4,%5\n" // lum2+4 + "leal 16(%3),%3\n" // row1+16 + "leal 16(%4),%4\n" // row2+16 + "addl $2, %0\n" // cr+2 + "addl $2, %1\n" // cb+2 + + "subl $4,8%5\n" // x+4 x is buf[2] + "cmpl $0,8%5\n" + + "jne 1b\n" + "addl 20%5, %2\n" // lum += cols + "movl %2,16%5\n" // store register in tmp0 + "movl 20%5,%2\n" // cols->register + + "addl %2, %5\n" // lum2 += cols + "addl 12%5, %3\n" // row1+= mod is buf[0] + "addl 12%5, %4\n" // row2+= mod is buf[0] + + "movl %2, 8%5\n" // x=cols + "movl 16%5,%2\n" // store tmp0 in register + + "cmpl 4%5, %2\n" // buf[1] is end + "jl 1b\n" + "emms\n" + : + : "r" (cr), "r"(cb),"r"(lum), + "r"(row1),"r"(row2),"m"(buf[0]) + ); + + + +} + + +#endif diff --git a/mpeglib/lib/util/render/dither/dither8Bit.cpp b/mpeglib/lib/util/render/dither/dither8Bit.cpp new file mode 100644 index 00000000..4f85d3fb --- /dev/null +++ b/mpeglib/lib/util/render/dither/dither8Bit.cpp @@ -0,0 +1,306 @@ +/* + dither 8 bit depth yuv images + 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 "dither8Bit.h" + + +Dither8Bit::Dither8Bit(unsigned char pixel[256]) { + + int i; + for(i=0;i<256;i++) { + this->pixel[i]=pixel[i]; + } + colorTable8Bit=new ColorTable8Bit(); + + lum_values = colorTable8Bit->getLumValues(); + cr_values = colorTable8Bit->getCrValues(); + cb_values = colorTable8Bit->getCbValues(); + + + + initOrderedDither(); + +} + + +Dither8Bit::~Dither8Bit() { + int i; + for (i=0; i<DITH_SIZE; i++) { + delete cb_darrays[i]; + delete l_darrays[i]; + delete cr_darrays[i]; + } +} + + + + + +/* + *-------------------------------------------------------------- + * + * InitOrderedDither-- + * + * Structures initialized for ordered dithering. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ +void Dither8Bit::initOrderedDither() { + int i, j, k, err_range, threshval; + unsigned char *lmark, *cmark; + + for (i=0; i<DITH_SIZE; i++) { + lmark = l_darrays[i] = new unsigned char[256]; + for (j=0; j<lum_values[0]; j++) { + *lmark++ = 0; + } + for (j=0; j<(LUM_RANGE-1); j++) { + err_range = lum_values[j+1] - lum_values[j]; + threshval = ((i * err_range) / DITH_SIZE)+lum_values[j]; + + for (k=lum_values[j]; k<lum_values[j+1]; k++) { + if (k > threshval) { + *lmark++ = ((j+1) * (CR_RANGE * CB_RANGE)); + } + else { + *lmark++ = (j * (CR_RANGE * CB_RANGE)); + } + } + } + for (j=lum_values[LUM_RANGE-1]; j<256; j++) { + *lmark++ = (LUM_RANGE-1)*(CR_RANGE * CB_RANGE); + } + } + for (i=0; i<DITH_SIZE; i++) { + cmark = cr_darrays[i] = new unsigned char[256]; + + for (j=0; j<cr_values[0]; j++) { + *cmark++ = 0; + } + + for (j=0; j<(CR_RANGE-1); j++) { + err_range = cr_values[j+1] - cr_values[j]; + threshval = ((i * err_range) / DITH_SIZE)+cr_values[j]; + + for (k=cr_values[j]; k<cr_values[j+1]; k++) { + if (k > threshval) { + *cmark++ = ((j+1) * CB_RANGE); + } + else { + *cmark++ = (j * CB_RANGE); + } + } + } + + for (j=cr_values[CR_RANGE-1]; j<256; j++) { + *cmark++ = (CR_RANGE-1)*(CB_RANGE); + } + } + + for (i=0; i<DITH_SIZE; i++) { + cmark = cb_darrays[i] = new unsigned char[256]; + + for (j=0; j<cb_values[0]; j++) { + *cmark++ = 0; + } + + for (j=0; j<(CB_RANGE-1); j++) { + err_range = cb_values[j+1] - cb_values[j]; + threshval = ((i * err_range) / DITH_SIZE)+cb_values[j]; + + for (k=cb_values[j]; k<cb_values[j+1]; k++) { + if (k > threshval) { + *cmark++ = j+1; + } + else { + *cmark++ = j; + } + } + } + + for (j=cb_values[CB_RANGE-1]; j<256; j++) { + *cmark++ = CB_RANGE-1; + } + } +} + + + +/* + *-------------------------------------------------------------- + * + * OrderedDitherImage -- + * + * Dithers an image using an ordered dither. + * Assumptions made: + * 1) The color space is allocated y:cr:cb = 8:4:4 + * 2) The spatial resolution of y:cr:cb is 4:1:1 + * The channels are dithered based on the standard + * ordered dither pattern for a 4x4 area. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +void Dither8Bit::ditherImageOrdered (unsigned char* lum, + unsigned char* cr, + unsigned char* cb, + unsigned char* out, + int h, + int w) { + unsigned char *l, *r, *b, *o1, *o2; + unsigned char *l2; + unsigned char L, R, B; + int i, j; + + l = lum; + l2 = lum+w; + r = cr; + b = cb; + o1 = out; + o2 = out+w; + + + for (i=0; i<h; i+=4) { + + for (j=0; j<w; j+=8) { + + R = r[0]; B = b[0]; + + L = l[0]; + o1[0] = pixel[(l_darrays[0][L] + cr_darrays[0][R] + cb_darrays[0][B])]; + L = l[1]; + o1[1] = pixel[(l_darrays[8][L] + cr_darrays[8][R] + cb_darrays[8][B])]; + L = l2[0]; + o2[0] = pixel[(l_darrays[12][L] + cr_darrays[12][R] + cb_darrays[12][B])]; + L = l2[1]; + o2[1] = pixel[(l_darrays[4][L] + cr_darrays[4][R] + cb_darrays[4][B])]; + + R = r[1]; B = b[1]; + + L = l[2]; + o1[2] = pixel[(l_darrays[2][L] + cr_darrays[2][R] + cb_darrays[2][B])]; + L = l[3]; + o1[3] = pixel[(l_darrays[10][L] + cr_darrays[10][R] + cb_darrays[10][B])]; + L = l2[2]; + o2[2] = pixel[(l_darrays[14][L] + cr_darrays[14][R] + cb_darrays[14][B])]; + L = l2[3]; + o2[3] = pixel[(l_darrays[6][L] + cr_darrays[6][R] + cb_darrays[6][B])]; + + R = r[2]; B = b[2]; + + L = l[4]; + o1[4] = pixel[(l_darrays[0][L] + cr_darrays[0][R] + cb_darrays[0][B])]; + L = l[5]; + o1[5] = pixel[(l_darrays[8][L] + cr_darrays[8][R] + cb_darrays[8][B])]; + L = l2[4]; + o2[4] = pixel[(l_darrays[12][L] + cr_darrays[12][R] + cb_darrays[12][B])]; + L = l2[5]; + o2[5] = pixel[(l_darrays[4][L] + cr_darrays[4][R] + cb_darrays[4][B])]; + + R = r[3]; B = b[3]; + + L = l[6]; + o1[6] = pixel[(l_darrays[2][L] + cr_darrays[2][R] + cb_darrays[2][B])]; + L = l[7]; + o1[7] = pixel[(l_darrays[10][L] + cr_darrays[10][R] + cb_darrays[10][B])]; + L = l2[6]; + o2[6] = pixel[(l_darrays[14][L] + cr_darrays[14][R] + cb_darrays[14][B])]; + L = l2[7]; + o2[7] = pixel[(l_darrays[6][L] + cr_darrays[6][R] + cb_darrays[6][B])]; + + l += 8; + l2 += 8; + r += 4; + b += 4; + o1 += 8; + o2 += 8; + } + + l += w; + l2 += w; + o1 += w; + o2 += w; + + for (j=0; j<w; j+=8) { + + R = r[0]; B = b[0]; + + L = l[0]; + o1[0] = pixel[(l_darrays[3][L] + cr_darrays[3][R] + cb_darrays[3][B])]; + L = l[1]; + o1[1] = pixel[(l_darrays[11][L] + cr_darrays[11][R] + cb_darrays[11][B])]; + L = l2[0]; + o2[0] = pixel[(l_darrays[15][L] + cr_darrays[15][R] + cb_darrays[15][B])]; + L = l2[1]; + o2[1] = pixel[(l_darrays[7][L] + cr_darrays[7][R] + cb_darrays[7][B])]; + + R = r[1]; B = b[1]; + + L = l[2]; + o1[2] = pixel[(l_darrays[1][L] + cr_darrays[1][R] + cb_darrays[1][B])]; + L = l[3]; + o1[3] = pixel[(l_darrays[9][L] + cr_darrays[9][R] + cb_darrays[9][B])]; + L = l2[2]; + o2[2] = pixel[(l_darrays[13][L] + cr_darrays[13][R] + cb_darrays[13][B])]; + L = l2[3]; + o2[3] = pixel[(l_darrays[5][L] + cr_darrays[5][R] + cb_darrays[5][B])]; + + R = r[2]; B = b[2]; + + L = l[4]; + o1[4] = pixel[(l_darrays[3][L] + cr_darrays[3][R] + cb_darrays[3][B])]; + L = l[5]; + o1[5] = pixel[(l_darrays[11][L] + cr_darrays[11][R] + cb_darrays[11][B])]; + L = l2[4]; + o2[4] = pixel[(l_darrays[15][L] + cr_darrays[15][R] + cb_darrays[15][B])]; + L = l2[5]; + o2[5] = pixel[(l_darrays[7][L] + cr_darrays[7][R] + cb_darrays[7][B])]; + + R = r[3]; B = b[3]; + + L = l[6]; + o1[6] = pixel[(l_darrays[1][L] + cr_darrays[1][R] + cb_darrays[1][B])]; + L = l[7]; + o1[7] = pixel[(l_darrays[9][L] + cr_darrays[9][R] + cb_darrays[9][B])]; + L = l2[6]; + o2[6] = pixel[(l_darrays[13][L] + cr_darrays[13][R] + cb_darrays[13][B])]; + L = l2[7]; + o2[7] = pixel[(l_darrays[5][L] + cr_darrays[5][R] + cb_darrays[5][B])]; + + l += 8; + l2 += 8; + r += 4; + b += 4; + o1 += 8; + o2 += 8; + } + + l += w; + l2 += w; + o1 += w; + o2 += w; + } +} + diff --git a/mpeglib/lib/util/render/dither/dither8Bit.h b/mpeglib/lib/util/render/dither/dither8Bit.h new file mode 100644 index 00000000..7bdd4d8f --- /dev/null +++ b/mpeglib/lib/util/render/dither/dither8Bit.h @@ -0,0 +1,63 @@ +/* + dither 8 bit depth yuv images + 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 __DITHER_8BIT_H +#define __DITHER_8BIT_H + + +#include "colorTable8Bit.h" + +#define DITH_SIZE 16 + + +class Dither8Bit { + + /* Structures used to implement hybrid ordered dither/floyd-steinberg + dither algorithm. + */ + + unsigned char *l_darrays[DITH_SIZE]; + unsigned char *cr_darrays[DITH_SIZE]; + unsigned char *cb_darrays[DITH_SIZE]; + + // private colormap + unsigned char pixel[256]; + + ColorTable8Bit* colorTable8Bit; + + // Arrays holding quantized value ranged for lum, cr, and cb. + // (used for 8 Bit) + + int* lum_values; + int* cr_values; + int* cb_values; + + + public: + Dither8Bit(unsigned char pixel[256]); + ~Dither8Bit(); + + void ditherImageOrdered (unsigned char* lum, + unsigned char* cr, + unsigned char* cb, + unsigned char* out, + int h, + int w); + + private: + void initOrderedDither(); +}; + +#endif + diff --git a/mpeglib/lib/util/render/dither/ditherDef.h b/mpeglib/lib/util/render/dither/ditherDef.h new file mode 100644 index 00000000..2e8d7d0e --- /dev/null +++ b/mpeglib/lib/util/render/dither/ditherDef.h @@ -0,0 +1,100 @@ +/* + global definitions for dithering + 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 __DITHERDEF_H +#define __DITHERDEF_H + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +extern "C" { +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +} + + +#ifdef __GNUC__ +#if (__GNUC__ < 2 || ( __GNUC__ == 2 && __GNUC_MINOR__ < 91 ) ) +#ifndef _AIX +#warning "inline code disabled! (buggy egcs version)" +#undef __NO_MATH_INLINES +#define __NO_MATH_INLINES 1 +#endif +#endif +#endif +#include <math.h> + + + +/* Gamma correction stuff */ +extern int gammaCorrectFlag; +extern double gammaCorrect; + +/* Chroma correction stuff */ +extern int chromaCorrectFlag; +extern double chromaCorrect; + + +#define CB_BASE 1 +#define CR_BASE (CB_BASE*CB_RANGE) +#define LUM_BASE (CR_BASE*CR_RANGE) + +#define TABTYPE short + +#ifdef SIXTYFOUR_BIT +#define PIXVAL long +#else +#define PIXVAL int +#endif + +#ifdef SIXTYFOUR_BIT +#define ONE_TWO 1 +#else +#define ONE_TWO 2 +#endif + + + +#define Min(x,y) (((x) < (y)) ? (x) : (y)) +#define Max(x,y) (((x) > (y)) ? (x) : (y)) + +#define CHROMA_CORRECTION128(x) ((x) >= 0 \ + ? Min(127, (int)(((x) * chromaCorrect))) \ + : Max(-128, (int)(((x) * chromaCorrect)))) +#define CHROMA_CORRECTION256D(x) ((x) >= 128 \ + ? 128.0 + Min(127.0, (((x)-128.0) * chromaCorrect)) \ + : 128.0 - Min(128.0, (((128.0-(x))* chromaCorrect)))) + + + +#define GAMMA_CORRECTION(x) ((int)(pow((x) / 255.0, 1.0/gammaCorrect)* 255.0)) + +#define CHROMA_CORRECTION128D(x) ((x) >= 0 \ + ? Min(127.0, ((x) * chromaCorrect)) \ + : Max(-128.0, ((x) * chromaCorrect))) + +#define CHROMA_CORRECTION256(x) ((x) >= 128 \ + ? 128 + Min(127, (int)(((x)-128.0) * chromaCorrect)) \ + : 128 - Min(128, (int)((128.0-(x)) * chromaCorrect))) + +// Range values for lum, cr, cb. +#define LUM_RANGE 8 +#define CR_RANGE 4 +#define CB_RANGE 4 + + +#endif diff --git a/mpeglib/lib/util/render/dither/ditherMMX.h b/mpeglib/lib/util/render/dither/ditherMMX.h new file mode 100644 index 00000000..2f08b689 --- /dev/null +++ b/mpeglib/lib/util/render/dither/ditherMMX.h @@ -0,0 +1,38 @@ +/* + mmx ditherer + 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 __DITHERMMX_H +#define __DITHERMMX_H + +#include "ditherDef.h" + + +// The mmx dither routine come from NIST +// NIST is an mpeg2/dvd player +// more: http://home.germany.net/100-5083/ +extern void ditherBlock(unsigned char *lum, + unsigned char *cr, + unsigned char *cb, + unsigned char *out, + int rows, int cols, int mod); + +extern void dither32_mmx(unsigned char* lum, + unsigned char* cr, + unsigned char* cb, + unsigned char* out, + int rows, + int cols, + int mod); + + +#endif diff --git a/mpeglib/lib/util/render/dither/ditherRGB.cpp b/mpeglib/lib/util/render/dither/ditherRGB.cpp new file mode 100644 index 00000000..1bcdb2ff --- /dev/null +++ b/mpeglib/lib/util/render/dither/ditherRGB.cpp @@ -0,0 +1,230 @@ +/* + copys RGB images to a destination + 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 "ditherRGB.h" + +#include <iostream> + +using namespace std; + +DitherRGB::DitherRGB() { +} + + +DitherRGB::~DitherRGB() { +} + + +int DitherRGB::getDepth(int pixel) { + int byteDepth=0; + + switch(pixel) { + case 8: + byteDepth=1; + break; + case 15: + case 16: + byteDepth=2; + break; + case 24: + case 32: + byteDepth=4; + break; + default: + cout << "unknown byteDepth:"<<pixel + << " in DitherRGB_flipped::flipRGBImage"<<endl; + } + return byteDepth; + +} + +void DitherRGB::ditherRGBImage(unsigned char* dest,unsigned char* src, + int depth,int width,int height,int offset) { + int byteDepth=getDepth(depth); + if (byteDepth == 0) { + return; + } + + + if (offset==0) { + int bytes=height*width*byteDepth; + memcpy(dest,src,bytes); + return; + } + + int i; + int lineSize=width*byteDepth; + + offset=offset*byteDepth+lineSize; + + for (i=0;i<height;i++) { + memcpy(dest,src,lineSize); + src+=lineSize; + dest+=offset; + } + + +} + +void DitherRGB::ditherRGBImage_x2(unsigned char* dest,unsigned char* src, + int depth,int width,int height,int offset) { + + int byteDepth=getDepth(depth); + if (byteDepth == 0) { + return; + } + + switch(byteDepth) { + case 1: + ditherRGB1Byte_x2(dest,src,1,width, height,offset); + break; + case 2: + ditherRGB2Byte_x2(dest,src,2,width, height,offset); + break; + case 4: + ditherRGB4Byte_x2(dest,src,4,width, height,offset); + break; + default: + cout <<"ditherRGBImage_x2 byteDepth:"<<byteDepth + <<" not supported"<<endl; + } +} + + +void DitherRGB::ditherRGB1Byte_x2(unsigned char* dest,unsigned char* src, + int depth,int width,int height,int offset) { + + // + // dest destr + // destd destrd + + int lineInc=2*width+offset; + unsigned char* destr=dest+1; + unsigned char* destd=dest+lineInc; + unsigned char* destrd=destd+1; + + int row; + int col; + // + // We copy byte by byte this is slow, but works for + // all byteDepth + // this memcpy can be optimized with MMX very i) good ii) easily + + for(row=0;row<height;row++) { + for(col=0;col<width;col++) { + *dest++=*src; + *destr++=*src; + *destd++=*src; + *destrd++=*src; + dest++; + destr++; + destd++; + destrd++; + + src++; + } + dest+=lineInc; + destr+=lineInc; + destd+=lineInc; + destrd+=lineInc; + } +} + + +void DitherRGB::ditherRGB2Byte_x2(unsigned char* destination, + unsigned char* source, + int depth,int width,int height,int offset) { + // + // dest destr + // destd destrd + + unsigned short int* src=(unsigned short int*) source; + unsigned short int* dest=(unsigned short int*) destination; + + int lineInc=2*width+offset; + unsigned short int* destr=dest+1; + unsigned short int* destd=dest+lineInc; + unsigned short int* destrd=destd+1; + + int row; + int col; + // + // We copy byte by byte this is slow, but works for + // all byteDepth + // this memcpy can be optimized with MMX very i) good ii) easily + + for(row=0;row<height;row++) { + for(col=0;col<width;col++) { + *dest++=*src; + *destr++=*src; + *destd++=*src; + *destrd++=*src; + dest++; + destr++; + destd++; + destrd++; + + src++; + } + dest+=lineInc; + destr+=lineInc; + destd+=lineInc; + destrd+=lineInc; + } +} + + +void DitherRGB::ditherRGB4Byte_x2(unsigned char* destination, + unsigned char* source, + int depth,int width,int height,int offset) { + + // + // dest destr + // destd destrd + + unsigned int* src=(unsigned int*) source; + unsigned int* dest=(unsigned int*) destination; + + int lineInc=2*width+offset; + unsigned int* destr=dest+1; + unsigned int* destd=dest+lineInc; + unsigned int* destrd=destd+1; + + int row; + int col; + // + // We copy byte by byte this is slow, but works for + // all byteDepth + // this memcpy can be optimized with MMX very i) good ii) easily + + for(row=0;row<height;row++) { + for(col=0;col<width;col++) { + *dest++=*src; + *destr++=*src; + *destd++=*src; + *destrd++=*src; + dest++; + destr++; + destd++; + destrd++; + + src++; + } + dest+=lineInc; + destr+=lineInc; + destd+=lineInc; + destrd+=lineInc; + } + +} + diff --git a/mpeglib/lib/util/render/dither/ditherRGB.h b/mpeglib/lib/util/render/dither/ditherRGB.h new file mode 100644 index 00000000..6f24cd8c --- /dev/null +++ b/mpeglib/lib/util/render/dither/ditherRGB.h @@ -0,0 +1,45 @@ +/* + copys RGB images to a destination + 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 __DITHERRGB_H +#define __DITHERRGB_H + +#include "colorTableHighBit.h" + +class DitherRGB { + + int flipSize; + unsigned char* flipSpace; + + public: + DitherRGB(); + ~DitherRGB(); + + // Note: this methods swaps the image + // itsself + void ditherRGBImage(unsigned char* dest,unsigned char* src, + int depth,int width,int height,int offset); + void ditherRGBImage_x2(unsigned char* dest,unsigned char* src, + int depth,int width,int height,int offset); + private: + int getDepth(int pixel); + // depth is here in byte! + void ditherRGB1Byte_x2(unsigned char* dest,unsigned char* src, + int depth,int width,int height,int offset); + void ditherRGB2Byte_x2(unsigned char* dest,unsigned char* src, + int depth,int width,int height,int offset); + void ditherRGB4Byte_x2(unsigned char* dest,unsigned char* src, + int depth,int width,int height,int offset); + +}; + +#endif diff --git a/mpeglib/lib/util/render/dither/ditherRGB_flipped.cpp b/mpeglib/lib/util/render/dither/ditherRGB_flipped.cpp new file mode 100644 index 00000000..ba177675 --- /dev/null +++ b/mpeglib/lib/util/render/dither/ditherRGB_flipped.cpp @@ -0,0 +1,82 @@ +/* + flips RGB images + 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 "ditherRGB_flipped.h" + +#include <iostream> + +using namespace std; + + +DitherRGB_flipped::DitherRGB_flipped() { + flipSpace=NULL; + flipSize=0; +} + +DitherRGB_flipped::~DitherRGB_flipped() { + if (flipSpace != NULL) { + delete flipSpace; + } +} + + + + +void DitherRGB_flipped::flipRGBImage(unsigned char* dest,unsigned char* src, + int depth,int width,int height,int ) { + + int byteDepth; + + switch(depth) { + case 8: + byteDepth=1; + break; + case 15: + case 16: + byteDepth=2; + break; + case 24: + case 32: + byteDepth=4; + break; + default: + cout << "unknown byteDepth:"<<depth + << " in DitherRGB_flipped::flipRGBImage"<<endl; + return; + } + + + int spaceNeeded=width*height*byteDepth; + + if (spaceNeeded > flipSize) { + if (flipSpace != NULL) { + delete flipSpace; + } + cout << "flipSpace:"<<spaceNeeded<<endl; + flipSpace=new unsigned char[spaceNeeded+64]; + flipSize=spaceNeeded; + } + + int i; + int lineSize=width*byteDepth; + unsigned char* end=dest+lineSize*(height-1); + + for (i=0;i<height;i++) { + memcpy(end,src,lineSize); + src+=lineSize; + end-=lineSize; + } + +} + + diff --git a/mpeglib/lib/util/render/dither/ditherRGB_flipped.h b/mpeglib/lib/util/render/dither/ditherRGB_flipped.h new file mode 100644 index 00000000..1d99f7f6 --- /dev/null +++ b/mpeglib/lib/util/render/dither/ditherRGB_flipped.h @@ -0,0 +1,34 @@ +/* + flips RGB images + 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 __DITHERRGB_FLIPPED_H +#define __DITHERRGB_FLIPPED_H + +#include "colorTableHighBit.h" + +class DitherRGB_flipped { + + int flipSize; + unsigned char* flipSpace; + + public: + DitherRGB_flipped(); + ~DitherRGB_flipped(); + + // Note: this methods swaps the image + // itsself + void flipRGBImage(unsigned char* dest,unsigned char* src, + int depth,int width,int height,int offset); + +}; + +#endif diff --git a/mpeglib/lib/util/render/dither/ditherWrapper.cpp b/mpeglib/lib/util/render/dither/ditherWrapper.cpp new file mode 100644 index 00000000..c6c37a79 --- /dev/null +++ b/mpeglib/lib/util/render/dither/ditherWrapper.cpp @@ -0,0 +1,246 @@ +/* + wrapper for X11 Window + 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 "ditherWrapper.h" + +#include <iostream> + +using namespace std; + + +/* + Flag for gamma correction + Makes images brighter/darker. + It's in the source but not activated (for now) +*/ +int gammaCorrectFlag = 0; +double gammaCorrect = 1.0; + +/* + Flag for chroma correction. + reduce the color intensity.. + It's in the source but not activated (for now) +*/ +int chromaCorrectFlag = 0; +double chromaCorrect = 1.0; + + + +DitherWrapper::DitherWrapper(int bpp,unsigned int redMask, + unsigned int greenMask,unsigned int blueMask, + unsigned char pixel[256]) { + + this->bpp=bpp; + this->redMask=redMask; + this->greenMask=greenMask; + this->blueMask=blueMask; + + + dither8Bit=new Dither8Bit(pixel); + dither16Bit=new Dither16Bit(redMask,greenMask,blueMask); + dither32Bit=new Dither32Bit(redMask,greenMask,blueMask); + ditherRGB_flipped=new DitherRGB_flipped(); + ditherRGB=new DitherRGB(); + + +#ifdef INTEL + lmmx=mm_support(); +#else + lmmx=false; +#endif + + +} + + +DitherWrapper::~DitherWrapper(){ + delete dither16Bit; + delete dither8Bit; + delete dither32Bit; + delete ditherRGB_flipped; + delete ditherRGB; +} + + + + + +void DitherWrapper::doDither(YUVPicture* pic,int depth,int imageMode, + unsigned char* dest,int offset) { + + + // + // according to the input imageType and the output area + // handle different dither methods + // + + int inputType=pic->getImageType(); + + if ( (inputType == PICTURE_YUVMODE_CR_CB) || + (inputType == PICTURE_YUVMODE_CB_CR) ) { + doDitherYUV(pic,depth,imageMode,dest,offset); + return; + } + + if ( (inputType == PICTURE_RGB) || + (inputType == PICTURE_RGB_FLIPPED) ){ + doDitherRGB(pic,depth,imageMode,dest,offset); + return; + } + + cout << "unknown inputType:"<<inputType + << " in DitherWrapper::doDither"<<endl; +} + + +void DitherWrapper::doDitherRGB(YUVPicture* pic,int depth,int imageMode, + unsigned char* dest,int offset) { + + int inputType=pic->getImageType(); + + switch(inputType) { + case PICTURE_RGB: + doDitherRGB_NORMAL(pic,depth,imageMode,dest,offset); + break; + case PICTURE_RGB_FLIPPED: + doDitherRGB_FLIPPED(pic,depth,imageMode,dest,offset); + break; + default: + cout << "unknown RGB type:"<<inputType<<" in DitherWrapper"<<endl; + exit(0); + } +} + + +void DitherWrapper::doDitherRGB_NORMAL(YUVPicture* pic, + int depth,int imageMode, + unsigned char* dest,int offset) { + + int w=pic->getWidth(); + int h=pic->getHeight(); + + unsigned char* src=pic->getImagePtr(); + + if (imageMode & _IMAGE_DOUBLE) { + ditherRGB->ditherRGBImage_x2(dest,src,depth,w,h,offset); + } else { + ditherRGB->ditherRGBImage(dest,src,depth,w,h,offset); + } +} + +void DitherWrapper::doDitherRGB_FLIPPED(YUVPicture* pic, + int depth,int imageMode, + unsigned char* dest,int offset) { + + int w=pic->getWidth(); + int h=pic->getHeight(); + + unsigned char* src=pic->getImagePtr(); + + ditherRGB_flipped->flipRGBImage(dest,src,depth,w,h,offset); +} + + + +void DitherWrapper::doDitherYUV(YUVPicture* pic,int depth,int imageMode, + unsigned char* dest,int offset) { + + if (imageMode & _IMAGE_DOUBLE) { + doDither_x2(pic,depth,dest,offset); + } else { + doDither_std(pic,depth,dest,offset); + } +} + + +void DitherWrapper::doDither_std(YUVPicture* pic,int depth, + unsigned char* dest,int offset){ + + int h=pic->getHeight(); + int w=pic->getWidth(); + unsigned char* lum=pic->getLuminancePtr(); + unsigned char* cr=pic->getCrPtr(); + unsigned char* cb=pic->getCbPtr(); + + + switch (depth) { + case 8: + dither8Bit->ditherImageOrdered(lum, cr, cb,dest , h, w); + break; + case 16: + if (lmmx) { + ditherBlock(lum,cr,cb,dest,h,w,offset); + } else { + dither16Bit->ditherImageColor16(lum,cr,cb,dest,h,w,offset); + } + + break; + case 24: + case 32: + if (lmmx) { + dither32_mmx(lum, cr, cb,dest ,h,w,offset); + } else { + dither32Bit->ditherImageColor32(lum, cr, cb,dest ,h,w,offset); + } + + + break; + default: + cout << "cannot dither depth:"<<depth<<endl; + } + +} + + +void DitherWrapper::doDither_x2(YUVPicture* pic,int depth, + unsigned char* dest,int offset){ + + int h=pic->getHeight(); + int w=pic->getWidth(); + unsigned char* lum=pic->getLuminancePtr(); + unsigned char* cr=pic->getCrPtr(); + unsigned char* cb=pic->getCbPtr(); + + + switch (depth) { + case 8: { + // we do dither with the 8Bit std YUV ditherer to RGB + // and then we do the double part with the + // RGB ditherer. Its obviously much slower but at + // least it works. To not allocate memory twice + // we are a bit tricky. We know that the image + // has space for doubls size. We but the not double size + // image at the bottom of the dest. Maybe that + // the last line gets overwritten + int memPos=3*h*w; + dither8Bit->ditherImageOrdered(lum, cr, cb,dest+memPos, h, w); + unsigned char* src=dest+memPos; + ditherRGB->ditherRGBImage_x2(dest,src,depth,w,h,0); + break; + } + case 16: + dither16Bit->ditherImageTwox2Color16(lum,cr,cb,dest,h,w,offset); + break; + case 24: + case 32: + if (lmmx) { + //dither32x2_mmx(lum, cr, cb,dest ,h,w,offset); + dither32Bit->ditherImageTwox2Color32(lum,cr,cb,dest,h,w,offset); + } else { + dither32Bit->ditherImageTwox2Color32(lum,cr,cb,dest,h,w,offset); + } + break; + default: + cout << "cannot dither depth:" << depth << endl; + } +} diff --git a/mpeglib/lib/util/render/dither/ditherWrapper.h b/mpeglib/lib/util/render/dither/ditherWrapper.h new file mode 100644 index 00000000..b01abff8 --- /dev/null +++ b/mpeglib/lib/util/render/dither/ditherWrapper.h @@ -0,0 +1,80 @@ +/* + wrapper for X11 Window + 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 __DITHERWRAPPER_H +#define __DITHERWRAPPER_H + + +#include "../../mmx/mmx.h" + +#include "../yuvPicture.h" +#include "../imageBase.h" +#include <stdlib.h> +#include "ditherMMX.h" +#include "dither8Bit.h" +#include "dither16Bit.h" +#include "dither32Bit.h" +#include "ditherRGB_flipped.h" +#include "ditherRGB.h" + + +/** + Wraps all calls to software ditherer and the different + resolutions,mmx enhancements, and doublesize ditherers. +*/ + + +class DitherWrapper { + + int lmmx; + + int bpp; + // colorMask + unsigned int redMask; + unsigned int greenMask; + unsigned int blueMask; + + Dither8Bit* dither8Bit; + Dither16Bit* dither16Bit; + Dither32Bit* dither32Bit; + DitherRGB_flipped* ditherRGB_flipped; + DitherRGB* ditherRGB; + + public: + DitherWrapper(int bpp,unsigned int redMask, + unsigned int greenMask,unsigned int blueMask, + unsigned char pixel[256]); + ~DitherWrapper(); + +/* int getDitherSize(); */ +/* void setDitherSize(int ditherMode); */ + + void doDither(YUVPicture* pic,int depth,int imageMode, + unsigned char* dest,int offset); + + + private: + void doDitherYUV(YUVPicture* pic,int depth,int imageMode, + unsigned char* dest,int offset); + void doDitherRGB(YUVPicture* pic,int depth,int imageMode, + unsigned char* dest,int offset); + void doDitherRGB_NORMAL(YUVPicture* pic,int depth,int imageMode, + unsigned char* dest,int offset); + void doDitherRGB_FLIPPED(YUVPicture* pic,int depth,int imageMode, + unsigned char* dest,int offset); + + void doDither_std(YUVPicture* pic,int depth,unsigned char* dest,int offset); + void doDither_x2(YUVPicture* pic,int depth,unsigned char* dest,int offset); +}; + +#endif diff --git a/mpeglib/lib/util/render/dither/ditherer_mmx16.cpp b/mpeglib/lib/util/render/dither/ditherer_mmx16.cpp new file mode 100644 index 00000000..757f0676 --- /dev/null +++ b/mpeglib/lib/util/render/dither/ditherer_mmx16.cpp @@ -0,0 +1,256 @@ + +#include "ditherMMX.h" + +#include <iostream> + +using namespace std; + +#ifndef INTEL +// nothing +void ditherBlock(unsigned char *lum, unsigned char *cr, unsigned char *cb, + unsigned char *out, + int cols, int rows, int screen_width) { + printf("call to ditherBlock. this should never happen\n"); + printf("check mmx detection routine.\n"); + exit(0); +} +#else + + +static long long MMX16_0 = 0L; +static unsigned long MMX16_10w[] = {0x00100010, 0x00100010}; +static unsigned long MMX16_80w[] = {0x00800080, 0x00800080}; +static unsigned long MMX16_00FFw[] = {0x00ff00ff, 0x00ff00ff}; +static unsigned short MMX16_Ublucoeff[] = {0x81, 0x81, 0x81, 0x81}; +static unsigned short MMX16_Vredcoeff[] = {0x66, 0x66, 0x66, 0x66}; +static unsigned short MMX16_Ugrncoeff[] = {0xffe8, 0xffe8, 0xffe8, 0xffe8}; +static unsigned short MMX16_Vgrncoeff[] = {0xffcd, 0xffcd, 0xffcd, 0xffcd}; +static unsigned short MMX16_Ycoeff[] = {0x4a, 0x4a, 0x4a, 0x4a}; +static unsigned short MMX16_redmask[] = {0xf800, 0xf800, 0xf800, 0xf800}; +static unsigned short MMX16_grnmask[] = {0x7e0, 0x7e0, 0x7e0, 0x7e0}; + +void dummy_dithermmx16() { + cout << "MMX16_0"<<MMX16_0<<endl; + cout << "MMX16_10w:"<<MMX16_10w<<endl; + cout << "MMX16_80w:"<<MMX16_80w<<endl; + cout << "MMX16_Ublucoeff:"<<MMX16_Ublucoeff<<endl; + cout << "MMX16_Vredcoeff:"<<MMX16_Vredcoeff<<endl; + cout << "MMX16_Ugrncoeff:"<<MMX16_Ugrncoeff<<endl; + cout << "MMX16_Vgrncoeff:"<<MMX16_Vgrncoeff<<endl; + cout << "MMX16_Ycoeff:"<<MMX16_Ycoeff<<endl; + cout << "MMX16_redmask:"<<MMX16_redmask<<endl; + cout << "MMX16_grnmask:"<<MMX16_grnmask<<endl; + cout << "MMX16_00FFw:"<<MMX16_00FFw<<endl; +} + + +void ditherBlock(unsigned char *lum, + unsigned char *cr, + unsigned char *cb, + unsigned char *out, + int rows, + int cols, + int mod) { + + unsigned short *row1; + unsigned short *row2; + row1 = (unsigned short* )out; // 16 bit target + + unsigned char* end = lum +cols*rows; // Pointer to the end + int x=cols; + row2=row1+mod+cols; // start of second row + mod=2*cols+4*mod; // increment for row1 in byte + + // buffer for asm function + int buf[6]; + buf[0]=(int)(lum+cols); // lum2 pointer + buf[1]=(int)end; + buf[2]=x; + buf[3]=mod; + buf[4]=0; //tmp0; + buf[5]=cols; + + + + __asm__ __volatile__( + ".align 32\n" + "1:\n" + "movd (%1), %%mm0\n" // 4 Cb 0 0 0 0 u3 u2 u1 u0 + "pxor %%mm7, %%mm7\n" + "movd (%0), %%mm1\n" // 4 Cr 0 0 0 0 v3 v2 v1 v0 + "punpcklbw %%mm7, %%mm0\n" // 4 W cb 0 u3 0 u2 0 u1 0 u0 + "punpcklbw %%mm7, %%mm1\n" // 4 W cr 0 v3 0 v2 0 v1 0 v0 + "psubw MMX16_80w, %%mm0\n" + "psubw MMX16_80w, %%mm1\n" + "movq %%mm0, %%mm2\n" // Cb 0 u3 0 u2 0 u1 0 u0 + "movq %%mm1, %%mm3\n" // Cr + "pmullw MMX16_Ugrncoeff, %%mm2\n" // Cb2green 0 R3 0 R2 0 R1 0 R0 + "movq (%2), %%mm6\n" // L1 l7 L6 L5 L4 L3 L2 L1 L0 + "pmullw MMX16_Ublucoeff, %%mm0\n" // Cb2blue + "pand MMX16_00FFw, %%mm6\n" // L1 00 L6 00 L4 00 L2 00 L0 + "pmullw MMX16_Vgrncoeff, %%mm3\n" // Cr2green + "movq (%2), %%mm7\n" // L2 + "pmullw MMX16_Vredcoeff, %%mm1\n" // Cr2red + // "psubw MMX16_10w, %%mm6\n" + "psrlw $8, %%mm7\n" // L2 00 L7 00 L5 00 L3 00 L1 + "pmullw MMX16_Ycoeff, %%mm6\n" // lum1 + // "psubw MMX16_10w, %%mm7\n" // L2 + "paddw %%mm3, %%mm2\n" // Cb2green + Cr2green == green + "pmullw MMX16_Ycoeff, %%mm7\n" // lum2 + + "movq %%mm6, %%mm4\n" // lum1 + "paddw %%mm0, %%mm6\n" // lum1 +blue 00 B6 00 B4 00 B2 00 B0 + "movq %%mm4, %%mm5\n" // lum1 + "paddw %%mm1, %%mm4\n" // lum1 +red 00 R6 00 R4 00 R2 00 R0 + "paddw %%mm2, %%mm5\n" // lum1 +green 00 G6 00 G4 00 G2 00 G0 + "psraw $6, %%mm4\n" // R1 0 .. 64 + "movq %%mm7, %%mm3\n" // lum2 00 L7 00 L5 00 L3 00 L1 + "psraw $6, %%mm5\n" // G1 - .. + + "paddw %%mm0, %%mm7\n" // Lum2 +blue 00 B7 00 B5 00 B3 00 B1 + "psraw $6, %%mm6\n" // B1 0 .. 64 + "packuswb %%mm4, %%mm4\n" // R1 R1 + "packuswb %%mm5, %%mm5\n" // G1 G1 + "packuswb %%mm6, %%mm6\n" // B1 B1 + "punpcklbw %%mm4, %%mm4\n" + "punpcklbw %%mm5, %%mm5\n" + + "pand MMX16_redmask, %%mm4\n" + "psllw $3, %%mm5\n" // GREEN 1 + "punpcklbw %%mm6, %%mm6\n" + "pand MMX16_grnmask, %%mm5\n" + "pand MMX16_redmask, %%mm6\n" + "por %%mm5, %%mm4\n" // + "psrlw $11, %%mm6\n" // BLUE 1 + "movq %%mm3, %%mm5\n" // lum2 + "paddw %%mm1, %%mm3\n" // lum2 +red 00 R7 00 R5 00 R3 00 R1 + "paddw %%mm2, %%mm5\n" // lum2 +green 00 G7 00 G5 00 G3 00 G1 + "psraw $6, %%mm3\n" // R2 + "por %%mm6, %%mm4\n" // MM4 + "psraw $6, %%mm5\n" // G2 + + "movl %2,16%5\n" // store register in tmp0 + "movl %5,%2\n" // lum2->register + "movq (%2),%%mm6\n" // 0 0 0 0 L3 L2 L1 L0 (load lum2) + + + //"movq (%2, %5), %%mm6\n" // L3 load lum2 + "psraw $6, %%mm7\n" + "packuswb %%mm3, %%mm3\n" + "packuswb %%mm5, %%mm5\n" + "packuswb %%mm7, %%mm7\n" + "pand MMX16_00FFw, %%mm6\n" // L3 + "punpcklbw %%mm3, %%mm3\n" + // "psubw MMX16_10w, %%mm6\n" // L3 + "punpcklbw %%mm5, %%mm5\n" + "pmullw MMX16_Ycoeff, %%mm6\n" // lum3 + "punpcklbw %%mm7, %%mm7\n" + "psllw $3, %%mm5\n" // GREEN 2 + "pand MMX16_redmask, %%mm7\n" + "pand MMX16_redmask, %%mm3\n" + "psrlw $11, %%mm7\n" // BLUE 2 + "pand MMX16_grnmask, %%mm5\n" + "por %%mm7, %%mm3\n" + + "movq (%2), %%mm7\n" // L4 load lum2 + "movl 16%5,%2\n" // tmp0->register + + "por %%mm5, %%mm3\n" // + "psrlw $8, %%mm7\n" // L4 + "movq %%mm4, %%mm5\n" + // "psubw MMX16_10w, %%mm7\n" // L4 + "punpcklwd %%mm3, %%mm4\n" + "pmullw MMX16_Ycoeff, %%mm7\n" // lum4 + "punpckhwd %%mm3, %%mm5\n" + + "movq %%mm4, (%3)\n" // write row1 + "movq %%mm5, 8(%3)\n" // write row1 + + "movq %%mm6, %%mm4\n" // Lum3 + "paddw %%mm0, %%mm6\n" // Lum3 +blue + + "movq %%mm4, %%mm5\n" // Lum3 + "paddw %%mm1, %%mm4\n" // Lum3 +red + "paddw %%mm2, %%mm5\n" // Lum3 +green + "psraw $6, %%mm4\n" + "movq %%mm7, %%mm3\n" // Lum4 + "psraw $6, %%mm5\n" + "paddw %%mm0, %%mm7\n" // Lum4 +blue + "psraw $6, %%mm6\n" // Lum3 +blue + "movq %%mm3, %%mm0\n" // Lum4 + "packuswb %%mm4, %%mm4\n" + "paddw %%mm1, %%mm3\n" // Lum4 +red + "packuswb %%mm5, %%mm5\n" + "paddw %%mm2, %%mm0\n" // Lum4 +green + "packuswb %%mm6, %%mm6\n" + "punpcklbw %%mm4, %%mm4\n" + "punpcklbw %%mm5, %%mm5\n" + "punpcklbw %%mm6, %%mm6\n" + "psllw $3, %%mm5\n" // GREEN 3 + "pand MMX16_redmask, %%mm4\n" + "psraw $6, %%mm3\n" // psr 6 + "psraw $6, %%mm0\n" + "pand MMX16_redmask, %%mm6\n" // BLUE + "pand MMX16_grnmask, %%mm5\n" + "psrlw $11, %%mm6\n" // BLUE 3 + "por %%mm5, %%mm4\n" + "psraw $6, %%mm7\n" + "por %%mm6, %%mm4\n" + "packuswb %%mm3, %%mm3\n" + "packuswb %%mm0, %%mm0\n" + "packuswb %%mm7, %%mm7\n" + "punpcklbw %%mm3, %%mm3\n" + "punpcklbw %%mm0, %%mm0\n" + "punpcklbw %%mm7, %%mm7\n" + "pand MMX16_redmask, %%mm3\n" + "pand MMX16_redmask, %%mm7\n" // BLUE + "psllw $3, %%mm0\n" // GREEN 4 + "psrlw $11, %%mm7\n" + "pand MMX16_grnmask, %%mm0\n" + "por %%mm7, %%mm3\n" + "por %%mm0, %%mm3\n" + + "movq %%mm4, %%mm5\n" + + "punpcklwd %%mm3, %%mm4\n" + "punpckhwd %%mm3, %%mm5\n" + + "movq %%mm4, (%4)\n" + "movq %%mm5, 8(%4)\n" + + "subl $8, 8%5\n" // x-=8 + "addl $8, %5\n" // lum2+8 + "addl $8, %2\n" + "addl $4, %0\n" + "addl $4, %1\n" + "cmpl $0, 8%5\n" + "leal 16(%3), %3\n" + "leal 16(%4), %4\n" // row2+16 + + + "jne 1b\n" + "addl 20%5, %2\n" // lum += cols + + "movl %2,16%5\n" // store register in tmp0 + "movl 20%5,%2\n" // cols->register + + "addl %2, %5\n" // lum2 += cols + "addl 12%5, %3\n" // row1+= mod + "addl 12%5, %4\n" // row2+= mod + "movl %2, 8%5\n" // x=cols + "movl 16%5,%2\n" // store tmp0 in register + + "cmpl 4%5, %2\n" + "jl 1b\n" + + : + :"r" (cr), "r"(cb),"r"(lum), + "r"(row1),"r"(row2),"m"(buf[0]) + + ); + __asm__ ( + "emms\n" + ); + + } + +#endif diff --git a/mpeglib/lib/util/render/dither2YUV/Makefile.am b/mpeglib/lib/util/render/dither2YUV/Makefile.am new file mode 100644 index 00000000..374658a3 --- /dev/null +++ b/mpeglib/lib/util/render/dither2YUV/Makefile.am @@ -0,0 +1,22 @@ +# libdivxplugin - Makefile.am + +EXTRA_DIST = README + +INCLUDES = -I.. $(all_includes) + + +noinst_LTLIBRARIES = libdivxutil_dither.la + +noinst_HEADERS = dither2YUV.h rgb2yuvdefs.h rgb2yuv16.h \ + rgb2yuv32.h + +libdivxutil_dither_la_SOURCES = dither2YUV.cpp rgb2yuv16.cpp \ + rgb2yuv32.cpp + + + + + + + + diff --git a/mpeglib/lib/util/render/dither2YUV/README b/mpeglib/lib/util/render/dither2YUV/README new file mode 100644 index 00000000..66246c13 --- /dev/null +++ b/mpeglib/lib/util/render/dither2YUV/README @@ -0,0 +1,13 @@ + + +* we have a Dither2Yuv base class. Currently this is not derived + from a basic ditherWrapper class because we don not have this + in mpeglib yet. + TODO: change in mpeglib DitherWrapper->Dither2RGB and + make DitherWrapper pure virtual and derive Dither2YUV + Dither2RGB from this class. + +* Note we do not support 8 Bit here, thus the constructor looks + dofferent. + + diff --git a/mpeglib/lib/util/render/dither2YUV/dither2YUV.cpp b/mpeglib/lib/util/render/dither2YUV/dither2YUV.cpp new file mode 100644 index 00000000..db4a3288 --- /dev/null +++ b/mpeglib/lib/util/render/dither2YUV/dither2YUV.cpp @@ -0,0 +1,124 @@ +/* + this class dithery RGB picture to yuv12 + 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 "dither2YUV.h" + +#include <iostream> + +using namespace std; + + +Dither2YUV::Dither2YUV() { + + + lmmx=mm_support(); + +} + + +Dither2YUV::~Dither2YUV(){ +} + + + + + + +void Dither2YUV::doDither(YUVPicture* pic,int depth,int ditherSize, + unsigned char* dest,int offset) { + + int inputType=pic->getImageType(); + + switch(inputType) { + case PICTURE_RGB: + doDitherRGB_NORMAL(pic,depth,ditherSize,dest,offset); + break; + default: + std::cout << "unknown RGB type:"<<inputType<<" in Dither2YUV"<<std::endl; + exit(0); + } +} + + +void Dither2YUV::doDitherRGB_NORMAL(YUVPicture* rgbPic, + int depth,int ditherSize, + unsigned char* dest,int offset) { + + switch (ditherSize) { + case _SIZE_NORMAL: + doDither2YUV_std(rgbPic,depth,dest,offset); + break; + case _SIZE_DOUBLE: + std::cout << "double not supported for RGB"<<std::endl; + break; + default: + std::cout << "unknown size:"<<ditherSize<<" in Dither2YUV"<<std::endl; + exit(0); + } +} + + +void Dither2YUV::doDither2YUV_std(YUVPicture* rgbPic,int depth, + unsigned char* dest,int offset){ + + int h=rgbPic->getHeight(); + int w=rgbPic->getWidth(); + int lumLength=w * h; + int colorLength=(w * h) / 4; + + unsigned char* lum=dest; + unsigned char* cr=lum+lumLength; + unsigned char* cb=cr+colorLength; + unsigned char* rgbSource=rgbPic->getImagePtr(); + + + switch (depth) { + case 8: + std::cout << "8 bit dither to yuv not supported"<<std::endl; + exit(0); + break; + case 16: + if (lmmx) { +#ifdef INTEL + rgb2yuv16bit_mmx(rgbSource,lum,cr,cb,h,w); +#endif + } else { + rgb2yuv16bit(rgbSource,lum,cr,cb,h,w); + } + + break; + case 24: + if (lmmx) { +#ifdef INTEL + rgb2yuv24bit_mmx(rgbSource,lum,cr,cb,h,w); +#endif + } else { + rgb2yuv24bit(rgbSource,lum,cr,cb,h,w); + } + break; + case 32: + if (lmmx) { +#ifdef INTEL + rgb2yuv32bit_mmx(rgbSource,lum,cr,cb,h,w); +#endif + } else { + rgb2yuv32bit(rgbSource,lum,cr,cb,h,w); + } + break; + default: + std::cout << "cannot dither depth:"<<depth<<std::endl; + } + +} + + diff --git a/mpeglib/lib/util/render/dither2YUV/dither2YUV.h b/mpeglib/lib/util/render/dither2YUV/dither2YUV.h new file mode 100644 index 00000000..5ef26b2b --- /dev/null +++ b/mpeglib/lib/util/render/dither2YUV/dither2YUV.h @@ -0,0 +1,64 @@ +/* + this class dithery RGB picture to yuv12 + 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 __DITHER2YUV_H +#define __DITHER2YUV_H + + +#include "../../mmx/mmx.h" +#include "../yuvPicture.h" + + +#include <stdlib.h> +#include "rgb2yuv16.h" +#include "rgb2yuv32.h" + +#define _SIZE_NONE 0 +#define _SIZE_NORMAL 1 +#define _SIZE_DOUBLE 2 + + +/** + Wraps all calls to software ditherer and the different + resolutions,mmx enhancements, and doublesize ditherers. +*/ + + +class Dither2YUV { + + int lmmx; + + int bpp; + + + public: + Dither2YUV(); + ~Dither2YUV(); + + int getDitherSize(); + void setDitherSize(int ditherSize); + + void doDither(YUVPicture* pic,int depth,int ditherSize, + unsigned char* dest,int offset); + + + private: + void doDitherRGB_NORMAL(YUVPicture* pic,int depth,int ditherSize, + unsigned char* dest,int offset); + + void doDither2YUV_std(YUVPicture* pic,int depth, + unsigned char* dest,int offset); + +}; + +#endif diff --git a/mpeglib/lib/util/render/dither2YUV/rgb2yuv16.cpp b/mpeglib/lib/util/render/dither2YUV/rgb2yuv16.cpp new file mode 100644 index 00000000..e0d7fc86 --- /dev/null +++ b/mpeglib/lib/util/render/dither2YUV/rgb2yuv16.cpp @@ -0,0 +1,916 @@ +/*************************************************************************** + rgb2yuv16.c - description + ------------------- + begin : Tue Nov 2 2000 + copyright : (C) 2000 by Christian Gerlach + email : cgerlach@rhrk.uni-kl.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "rgb2yuv16.h" +#include <iostream> + +static unsigned short KEEPR[4] = { 63488, 63488, 63488, 63488 }; +unsigned short KEEPG[4] = { 2016, 2016, 2016, 2016 }; +unsigned short KEEPB[4] = { 31, 31, 31, 31 }; + +short Y_RED[4] = { 307, 307, 307, 307 }; +short Y_GREEN[4] = { 302, 302, 302, 302 }; +short Y_BLUE[4] = { 117, 117, 117, 117 }; + +short U_RED[4] = { -150, -150, -150, -150 }; +short U_GREEN[4] = { -147, -147, -147, -147 }; +short U_BLUE[4] = { 444, 444, 444, 444 }; + +short V_RED[4] = { 632, 632, 632, 632 }; +short V_GREEN[4] = { -265, -265, -265, -265 }; +short V_BLUE[4] = { -102, -102, -102, -102 }; + + +// how to avoid these nasty compiler warinings? +// heres one (maybe bad) method +void dummyRGB2YUV16Bit() { + + printf("%p\n",KEEPR); + printf("%p\n",KEEPG); + printf("%p\n",KEEPB); + printf("%p\n",Y_RED); + printf("%p\n",Y_GREEN); + printf("%p\n",Y_BLUE); + printf("%p\n",U_RED); + printf("%p\n",U_GREEN); + printf("%p\n",U_BLUE); + printf("%p\n",V_RED); + printf("%p\n",V_GREEN); + printf("%p\n",V_BLUE); +} + + +#ifndef INTEL +void rgb2yuv16bit_mmx(unsigned char* ,unsigned char* ,unsigned char* , + unsigned char* ,int , int ) { + std::cout << "RGB->YUV not compiled with INTEL" << std::endl; + exit(0); +} + +void rgb2yuv16bit_mmx_fast(unsigned char* ,unsigned char* ,unsigned char* , + unsigned char* ,int , int ) { + std::cout << "RGB->YUV not compiled with INTEL" << std::endl; + exit(0); +} +#endif + + +void rgb2yuv16(unsigned char* rgbSource, unsigned char* dest) +{ + int rgb = *((unsigned short*) rgbSource++ ); + int r = RED(rgb); + int g = GREEN(rgb); + int b = BLUE(rgb); + + dest[0] = Y_RGB(r, g, b); + dest[1] = U_RGB(r, g, b); + dest[2] = V_RGB(r, g, b); +} + +void rgb2yuv16bit(unsigned char* rgbSource, + unsigned char* lum, + unsigned char* cr, + unsigned char* cb,int height, int width) { + + int height2 = height / 2; + int width2 = width / 2; + int r, g, b, row, col, rgb; + + for (row=0 ; row<height2 ; row++) { + for (col=0 ; col<width2 ; col++) { + rgb = *((unsigned short*) rgbSource++ ); + r = RED(rgb); + g = GREEN(rgb); + b = BLUE(rgb); + + *lum++ = Y_RGB(r, g, b); + *cr++ = U_RGB(r, g, b); + *cb++ = V_RGB(r, g, b); + + rgb = *((unsigned short*) rgbSource++ ); + r = RED(rgb); + g = GREEN(rgb); + b = BLUE(rgb); + + *lum++ = Y_RGB(r, g, b); + } + for (col=0 ; col<width ; col++) { + rgb = *((unsigned short*) rgbSource++ ); + r = RED(rgb); + g = GREEN(rgb); + b = BLUE(rgb); + + *lum++ = Y_RGB(r, g, b); + } + } +} + + +#ifdef INTEL + +void rgb2yuv16bit_mmx(unsigned char* rgbSource, + unsigned char* lum, + unsigned char* cr, + unsigned char* cb,int height, int width) { + int height2 = height / 2; + int width2 = width / 2; + int bytesPerLine = width * 2; + + for (int row=0 ; row<height2 ; row++) { + rgb2yuv16bit_mmx422_row(rgbSource, lum, cr, cb, width); + rgbSource += bytesPerLine; + lum += width; + cr += width2; + cb += width2; + + rgb2y16bit_mmx_row(rgbSource, lum, width); + rgbSource += bytesPerLine; + lum += width; + } +} + +void rgb2yuv16bit_mmx_fast(unsigned char* rgbSource, + unsigned char* lum, + unsigned char* cr, + unsigned char* cb,int height, int width) { + + int height2 = height / 2; + int width2 = width / 2; + int bytesPerLine = width * 2; + + for (int row=0 ; row<height2 ; row++) { + rgb2yuv16bit_mmx422_row_fast(rgbSource, lum, cr, cb, width); + rgbSource += bytesPerLine; + lum += width; + cr += width2; + cb += width2; + + rgb2y16bit_mmx_row_fast(rgbSource, lum, width); + rgbSource += bytesPerLine; + lum += width; + } +} + +void rgb2yuv16bit_mmx422_row(unsigned char* rgb, + unsigned char* lum, unsigned char* cr, + unsigned char* cb, int pixel) { + unsigned int buf[17]; + + // 36%5 = TEMP0 + // 44%5 = TEMPY + // 52%5 = TEMPU + // 60%5 = TEMPV + + __asm__ __volatile__ ( + "1:\n" + + // unpack hicolor ( pixel 1 - 4) + "movq (%0), %%mm0\n" + + "movq %%mm0, %%mm1\n" + "pand KEEPR, %%mm1\n" + "psrlq $8, %%mm1\n" // B3B2B1B0 -> mm1 + "movq %%mm0, %%mm2\n" + "pand KEEPG, %%mm2\n" + "psrlq $3, %%mm2\n" // G3G2G1G0 -> mm2 + "movq %%mm0, %%mm3\n" + "pand KEEPB, %%mm3\n" + "psllq $3, %%mm3\n" // G3G2G1G0 -> mm3 + + "movq %%mm2, %%mm0\n" + "punpcklbw %%mm1, %%mm2\n" + "punpckhbw %%mm1, %%mm0\n" + + "pxor %%mm5, %%mm5\n" + "movq %%mm3, %%mm4\n" + "punpcklbw %%mm5, %%mm3\n" + "punpckhbw %%mm5, %%mm4\n" + + "psllq $8, %%mm2\n" + "por %%mm2, %%mm3\n" // 0B1G1R10B0G0G0 -> mm3 + "psllq $8, %%mm0\n" + "por %%mm0, %%mm4\n" // 0B3G3R30B2G2G2 -> mm4 + + "movq %%mm3, %5\n" + "movq %%mm4, 8%5\n" + + // next 4 pixels ------------------------------ + + "movq 8(%0), %%mm0\n" + + "movq %%mm0, %%mm1\n" + "pand KEEPR, %%mm1\n" + "psrlq $8, %%mm1\n" // B3B2B1B0 -> mm1 + "movq %%mm0, %%mm2\n" + "pand KEEPG, %%mm2\n" + "psrlq $3, %%mm2\n" // G3G2G1G0 -> mm2 + "movq %%mm0, %%mm3\n" + "pand KEEPB, %%mm3\n" + "psllq $3, %%mm3\n" // G3G2G1G0 -> mm3 + + "movq %%mm2, %%mm0\n" + "punpcklbw %%mm1, %%mm2\n" + "punpckhbw %%mm1, %%mm0\n" + + "pxor %%mm5, %%mm5\n" + "movq %%mm3, %%mm4\n" + "punpcklbw %%mm5, %%mm3\n" + "punpckhbw %%mm5, %%mm4\n" + + "psllq $8, %%mm2\n" + "por %%mm2, %%mm3\n" // 0B1G1R10B0G0G0 -> mm3 + "psllq $8, %%mm0\n" + "por %%mm0, %%mm4\n" // 0B3G3R30B2G2G2 -> mm4 + + "movq %%mm3, 16%5\n" + "movq %%mm4, 24%5\n" + + "add $16, %0\n" + + // standard algorithm -------------------------------------------------- + + // pack rgb + // was: "movq (%0), %%mm1\n" // load G2R2B1G1R1B0G0R0 + // ------------------------------ + // (uses: mm0, mm1) + "movd 8%5, %%mm0\n" + "psllq $24, %%mm0\n" + "movd 4%5, %%mm1\n" + "por %%mm1, %%mm0\n" + "psllq $24, %%mm0\n" + "movd %5, %%mm1\n" + "por %%mm0, %%mm1\n" + // ------------------------------ + + "pxor %%mm6, %%mm6\n" // 0 -> mm6 + "movq %%mm1, %%mm0\n" // G2R2B1G1R1B0G0R0 -> mm0 + "psrlq $16, %%mm1\n" // 00G2R2B1G1R1B0 -> mm1 + "punpcklbw ZEROSX, %%mm0\n" // R1B0G0R0 -> mm0 + "movq %%mm1, %%mm7\n" // 00G2R2B1G1R1B0 -> mm7 + "punpcklbw ZEROSX, %%mm1\n" // B1G1R1B0 -> mm1 + "movq %%mm0, %%mm2\n" // R1B0G0R0 -> mm2 + "pmaddwd YR0GRX, %%mm0\n" // yrR1,ygG0+yrR0 -> mm0 + + "movq %%mm1, %%mm3\n" // B1G1R1B0 -> mm3 + "pmaddwd YBG0BX, %%mm1\n" // ybB1+ygG1,ybB0 -> mm1 + "movq %%mm2, %%mm4\n" // R1B0G0R0 -> mm4 + "pmaddwd UR0GRX, %%mm2\n" // urR1,ugG0+urR0 -> mm2 + "movq %%mm3, %%mm5\n" // B1G1R1B0 -> mm5 + "pmaddwd UBG0BX, %%mm3\n" // ubB1+ugG1,ubB0 -> mm3 + "punpckhbw %%mm6, %%mm7\n" // 00G2R2 -> mm7 + "pmaddwd VR0GRX, %%mm4\n" // vrR1,vgG0+vrR0 -> mm4 + "paddd %%mm1, %%mm0\n" // Y1Y0 -> mm0 + + "pmaddwd VBG0BX, %%mm5\n" // vbB1+vgG1,vbB0 -> mm5 + + // pack rgb + // was: "movq 8(%0),%%mm1\n" // R5B4G4R4B3G3R3B2 -> mm1 + // ------------------------------ + // (uses: mm1, mm6) + "movd 20%5, %%mm1\n" + "psllq $24, %%mm1\n" + "movd 16%5, %%mm6\n" + "por %%mm6, %%mm1\n" + "psllq $24, %%mm1\n" + "movd 12%5, %%mm6\n" + "por %%mm6, %%mm1\n" + "psllq $8, %%mm1\n" + "movd 8%5, %%mm6\n" + "psrlq $16, %%mm6\n" + "por %%mm6, %%mm1\n" + // ------------------------------ + + "paddd %%mm3, %%mm2\n" // U1U0 -> mm2 + + "movq %%mm1, %%mm6\n" // R5B4G4R4B3G3R3B2 -> mm6 + "punpcklbw ZEROSX, %%mm1\n" // B3G3R3B2 -> mm1 + "paddd %%mm5, %%mm4\n" // V1V0 -> mm4 + + //---------------------------------------------------------------------- + + "movq %%mm1, %%mm5\n" // B3G3R3B2 -> mm5 + "psllq $32, %%mm1\n" // R3B200 -> mm1 + + "paddd %%mm7, %%mm1\n" // R3B200+00G2R2=R3B2G2R2->mm1 + + "punpckhbw ZEROSX, %%mm6\n" // R5B4G4R3 -> mm6 + "movq %%mm1, %%mm3\n" // R3B2G2R2 -> mm3 + + "pmaddwd YR0GRX, %%mm1\n" // yrR3,ygG2+yrR2 -> mm1 + "movq %%mm5, %%mm7\n" // B3G3R3B2 -> mm7 + + "pmaddwd YBG0BX, %%mm5\n" // ybB3+ygG3,ybB2 -> mm5 + "psrad $15, %%mm0\n" // 32-bit scaled Y1Y0 -> mm0 + + "movq %%mm6, 36%5\n" // R5B4G4R4 -> TEMP0 + "movq %%mm3, %%mm6\n" // R3B2G2R2 -> mm6 + "pmaddwd UR0GRX, %%mm6\n" // urR3,ugG2+urR2 -> mm6 + "psrad $15, %%mm2\n" // 32-bit scaled U1U0 -> mm2 + + "paddd %%mm5, %%mm1\n" // Y3Y2 -> mm1 + "movq %%mm7, %%mm5\n" // B3G3R3B2 -> mm5 + "pmaddwd UBG0BX, %%mm7\n" // ubB3+ugG3,ubB2 + "psrad $15, %%mm1\n" // 32-bit scaled Y3Y2 -> mm1 + + "pmaddwd VR0GRX, %%mm3\n" // vrR3,vgG2+vgR2 + "packssdw %%mm1, %%mm0\n" // Y3Y2Y1Y0 -> mm0 + + "pmaddwd VBG0BX, %%mm5\n" // vbB3+vgG3,vbB2 -> mm5 + "psrad $15, %%mm4\n" // 32-bit scaled V1V0 -> mm4 + + //---------------------------------------------------------------------- + + "paddd %%mm7, %%mm6\n" // U3U2 -> mm6 + + // pack rgb + // was: "movq 16(%0), %%mm1\n" // B7G7R7B6G6R6B5G5 -> mm1 + // ------------------------------ + // (uses: mm1, mm7) + "movd 28%5, %%mm1\n" + "psllq $24, %%mm1\n" + "movd 24%5, %%mm7\n" + "por %%mm7, %%mm1\n" + "psllq $16, %%mm1\n" + "movd 20%5, %%mm7\n" + "psrlq $8, %%mm7\n" + "por %%mm7, %%mm1\n" + // ------------------------------ + + "movq %%mm1, %%mm7\n" // B7G7R7B6G6R6B5G5 -> mm1 + "psrad $15, %%mm6\n" // 32-bit scaled U3U2 -> mm6 + + "paddd %%mm5, %%mm3\n" // V3V2 -> mm3 + "psllq $16, %%mm7\n" // R7B6G6R6B5G500 -> mm7 + + "movq %%mm7, %%mm5\n" // R7B6G6R6B5G500 -> mm5 + "psrad $15, %%mm3\n" // 32-bit scaled V3V2 -> mm3 + + "movq %%mm0, 44%5\n" // 32-bit scaled Y3Y2Y1Y0 -> TEMPY + + "packssdw %%mm6, %%mm2\n" // 32-bit scaled U3U2U1U0 -> mm2 + + "movq 36%5, %%mm0\n" // R5B4G4R4 -> mm0 + + "punpcklbw ZEROSX, %%mm7\n" // B5G500 -> mm7 + "movq %%mm0, %%mm6\n" // R5B4G4R4 -> mm6 + + "movq %%mm2, 52%5\n" // 32-bit scaled U3U2U1U0 -> TEMPU + "psrlq $32, %%mm0\n" // 00R5B4 -> mm0 + + "paddw %%mm0, %%mm7\n" // B5G5R5B4 -> mm7 + "movq %%mm6, %%mm2\n" // B5B4G4R4 -> mm2 + + "pmaddwd YR0GRX, %%mm2\n" // yrR5,ygG4+yrR4 -> mm2 + "movq %%mm7, %%mm0\n" // B5G5R5B4 -> mm0 + + "pmaddwd YBG0BX, %%mm7\n" // ybB5+ygG5,ybB4 -> mm7 + "packssdw %%mm3, %%mm4\n" // 32-bit scaled V3V2V1V0 -> mm4 + + //---------------------------------------------------------------------- + + "movq %%mm4, 60%5\n" // (V3V2V1V0)/256 -> mm4 + + "movq %%mm6, %%mm4\n" // B5B4G4R4 -> mm4 + + "pmaddwd UR0GRX, %%mm6\n" // urR5,ugG4+urR4 + "movq %%mm0, %%mm3\n" // B5G5R5B4 -> mm0 + + "pmaddwd UBG0BX, %%mm0\n" // ubB5+ugG5,ubB4 + "paddd %%mm7, %%mm2\n" // Y5Y4 -> mm2 + + //---------------------------------------------------------------------- + + "pmaddwd VR0GRX, %%mm4\n" // vrR5,vgG4+vrR4 -> mm4 + "pxor %%mm7, %%mm7\n" // 0 -> mm7 + + "pmaddwd VBG0BX, %%mm3\n" // vbB5+vgG5,vbB4 -> mm3 + "punpckhbw %%mm7, %%mm1\n" // B7G7R7B6 -> mm1 + + "paddd %%mm6, %%mm0\n" // U5U4 -> mm0 + "movq %%mm1, %%mm6\n" // B7G7R7B6 -> mm6 + + "pmaddwd YBG0BX, %%mm6\n" // ybB7+ygG7,ybB6 -> mm6 + "punpckhbw %%mm7, %%mm5\n" // R7B6G6R6 -> mm5 + + "movq %%mm5, %%mm7\n" // R7B6G6R6 -> mm7 + "paddd %%mm4, %%mm3\n" // V5V4 -> mm3 + + "pmaddwd YR0GRX, %%mm5\n" // yrR7,ygG6+yrR6 -> mm5 + "movq %%mm1, %%mm4\n" // B7G7R7B6 -> mm4 + + "pmaddwd UBG0BX, %%mm4\n" // ubB7+ugG7,ubB6 -> mm4 + "psrad $15, %%mm0\n" // 32-bit scaled U5U4 -> %%mm0 + + //---------------------------------------------------------------------- + + "paddd OFFSETWX, %%mm0\n" // add offset to U5U4 -> mm0 + "psrad $15, %%mm2\n" // 32-bit scaled Y5Y4 -> mm2 + + "paddd %%mm5, %%mm6\n" // Y7Y6 -> mm6 + "movq %%mm7, %%mm5\n" // R7B6G6R6 -> mm5 + + "pmaddwd UR0GRX, %%mm7\n" // urR7,ugG6+ugR6 -> mm7 + "psrad $15, %%mm3\n" // 32-bit scaled V5V4 -> mm3 + + "pmaddwd VBG0BX, %%mm1\n" // vbB7+vgG7,vbB6 -> mm1 + "psrad $15, %%mm6\n" // 32-bit scaled Y7Y6 -> mm6 + + "paddd OFFSETDX, %%mm4\n" // add offset to U7U6 + "packssdw %%mm6, %%mm2\n" // Y7Y6Y5Y4 -> mm2 + + "pmaddwd VR0GRX, %%mm5\n" // vrR7,vgG6+vrR6 -> mm5 + "paddd %%mm4, %%mm7\n" // U7U6 -> mm7 + + "psrad $15, %%mm7\n" // 32-bit scaled U7U6 -> mm7 + + //---------------------------------------------------------------------- + + "movq 44%5, %%mm6\n" // 32-bit scaled Y3Y2Y1Y0 -> mm6 + "packssdw %%mm7, %%mm0\n" // 32-bit scaled U7U6U5U4 -> mm0 + + "movq 52%5, %%mm4\n" // 32-bit scaled U3U2U1U0 -> mm4 + "packuswb %%mm2, %%mm6\n" // all 8 Y values -> mm6 + + "movq OFFSETBX, %%mm7\n" // 128,128,128,128 -> mm7 + "paddd %%mm5, %%mm1\n" // V7V6 -> mm1 + + "paddw %%mm7, %%mm4\n" // add offset to U3U2U1U0/256 + "psrad $15, %%mm1\n" // 32-bit scaled V7V6 -> mm1 + + //---------------------------------------------------------------------- + + "movq %%mm6, (%1)\n" // store Y + + "packuswb %%mm0, %%mm4\n" // all 8 U values -> mm4 + "movq 60%5, %%mm5\n" // 32-bit scaled V3V2V1V0 -> mm5 + + "packssdw %%mm1, %%mm3\n" // V7V6V5V4 -> mm3 + "paddw %%mm7, %%mm5\n" // add offset to V3V2V1V0 + "paddw %%mm7, %%mm3\n" // add offset to V7V6V5V4 + + "packuswb %%mm3, %%mm5\n" // ALL 8 V values -> mm5 + + "movq CLEARX, %%mm2\n" + "pand %%mm2, %%mm4\n" + "pand %%mm2, %%mm5\n" + + "packuswb %%mm5, %%mm4\n" + + "movd %%mm4, (%2)\n" + "psrlq $32, %%mm4\n" + "movd %%mm4, (%3)\n" + + "add $8, %1\n" + "add $4, %2\n" + "add $4, %3\n" + + "sub $8, %4\n" + "jnz 1b\n" + + "emms\n" + + : + : "r" (rgb), "r" (lum), "r" (cr), "r" (cb), + "m" (pixel), "m" (buf[0]) + + ); +} + +void rgb2yuv16bit_mmx422_row_fast(unsigned char* rgb, + unsigned char* lum, unsigned char* cr, + unsigned char* cb, int pixel) +{ + __asm__ __volatile__ ( + "1:\n" + + // unpack hicolor ( pixel 0 - 3) + "movq (%0), %%mm0\n" + + "movq %%mm0, %%mm1\n" + "pand KEEPR, %%mm1\n" + "psrlq $11, %%mm1\n" // B3B2B1B0 -> mm1 + + "movq %%mm0, %%mm2\n" + "pand KEEPG, %%mm2\n" + "psrlq $5, %%mm2\n" // G3G2G1G0 -> mm2 + + "movq %%mm0, %%mm3\n" + "pand KEEPB, %%mm3\n" // R3R2R1R0 -> mm3 + + // unpack hicolor ( pixel 4 - 7) + "movq 8(%0), %%mm0\n" + + "movq %%mm0, %%mm4\n" + "pand KEEPR, %%mm4\n" + "psrlq $11, %%mm4\n" // B7B6B5B4 -> mm4 + + "movq %%mm0, %%mm5\n" + "pand KEEPG, %%mm5\n" + "psrlq $5, %%mm5\n" // G7G6G5G4 -> mm5 + + "movq %%mm0, %%mm6\n" + "pand KEEPB, %%mm6\n" // R7R6R5R4 -> mm6 + + // calculate Y + "movq %%mm6, %%mm7\n" + "pmullw Y_RED, %%mm7\n" + + "movq %%mm5, %%mm0\n" + "pmullw Y_GREEN, %%mm0\n" + "paddw %%mm0, %%mm7\n" + + "movq %%mm4, %%mm0\n" + "pmullw Y_BLUE, %%mm0\n" + "paddw %%mm0, %%mm7\n" + + "psrlw $7, %%mm7\n" // Y3Y2Y1Y0 -> mm7 + + "pxor %%mm0, %%mm0\n" + "packuswb %%mm0, %%mm7\n" + "movd %%mm7, 4(%1)\n" // Y3Y2Y1Y0 -> lum + + // -------- + + "movq %%mm3, %%mm7\n" + "pmullw Y_RED, %%mm7\n" + + "movq %%mm2, %%mm0\n" + "pmullw Y_GREEN, %%mm0\n" + "paddw %%mm0, %%mm7\n" + + "movq %%mm1, %%mm0\n" + "pmullw Y_BLUE, %%mm0\n" + "paddw %%mm0, %%mm7\n" + + "psrlw $7, %%mm7\n" // Y7Y6Y5Y4 -> mm7 + + "pxor %%mm0, %%mm0\n" + "packuswb %%mm0, %%mm7\n" + "movd %%mm7, (%1)\n" // Y7Y6Y5Y4 -> lum + "add $8, %1\n" + + // pack RGB + "packuswb %%mm4, %%mm1\n" + "pand CLEARX, %%mm1\n" // B6B4B2B0 -> mm1 + "packuswb %%mm5, %%mm2\n" + "pand CLEARX, %%mm2\n" // GRG4G2G0 -> mm2 + "packuswb %%mm6, %%mm3\n" + "pand CLEARX, %%mm3\n" // R6R4R2R0 -> mm3 + + // calculate U + "movq %%mm3, %%mm7\n" + "pmullw U_RED, %%mm7\n" + + "movq %%mm2, %%mm0\n" + "pmullw U_GREEN, %%mm0\n" + "paddw %%mm0, %%mm7\n" + + "movq %%mm1, %%mm0\n" + "pmullw U_BLUE, %%mm0\n" + "paddw %%mm0, %%mm7\n" + + "psrlw $7, %%mm7\n" // U3U2U1U0 -> mm7 + "paddw OFFSETBX,%%mm7\n" + "pand CLEARX, %%mm7\n" + + "pxor %%mm0, %%mm0\n" + "packuswb %%mm0, %%mm7\n" + "movd %%mm7, (%2)\n" // U3U2U1U0 -> lum + "add $4, %2\n" + + // calculate V + "movq %%mm3, %%mm7\n" + "pmullw V_RED, %%mm7\n" + + "movq %%mm2, %%mm0\n" + "pmullw V_GREEN, %%mm0\n" + "paddw %%mm0, %%mm7\n" + + "movq %%mm1, %%mm0\n" + "pmullw V_BLUE, %%mm0\n" + "paddw %%mm0, %%mm7\n" + + "psrlw $7, %%mm7\n" // V3V2V1V0 -> mm7 + "paddw OFFSETBX,%%mm7\n" + "pand CLEARX, %%mm7\n" + + "pxor %%mm0, %%mm0\n" + "packuswb %%mm0, %%mm7\n" + "movd %%mm7, (%3)\n" // V3V2V1V0 -> lum + "add $4, %3\n" + + "add $16, %0\n" + + "sub $8, %4\n" + "jnz 1b\n" + + "emms\n" + + : + : "r" (rgb), "r" (lum), "r" (cr), "r" (cb), "m" (pixel) + + ); +} + +void rgb2y16bit_mmx_row(unsigned char* rgbSource, + unsigned char* lum, int pixel) +{ + unsigned int buf[16]; + + // 36%3 = TEMP0 + // 44%3 = TEMPY + + __asm__ __volatile__ ( + "1:\n" + + // unpack hicolor ( pixel 1 - 4) + "movq (%0), %%mm0\n" + + "movq %%mm0, %%mm1\n" + "pand KEEPR, %%mm1\n" + "psrlq $8, %%mm1\n" // B3B2B1B0 -> mm1 + "movq %%mm0, %%mm2\n" + "pand KEEPG, %%mm2\n" + "psrlq $3, %%mm2\n" // G3G2G1G0 -> mm2 + "movq %%mm0, %%mm3\n" + "pand KEEPB, %%mm3\n" + "psllq $3, %%mm3\n" // G3G2G1G0 -> mm3 + + "movq %%mm2, %%mm0\n" + "punpcklbw %%mm1, %%mm2\n" + "punpckhbw %%mm1, %%mm0\n" + + "pxor %%mm5, %%mm5\n" + "movq %%mm3, %%mm4\n" + "punpcklbw %%mm5, %%mm3\n" + "punpckhbw %%mm5, %%mm4\n" + + "psllq $8, %%mm2\n" + "por %%mm2, %%mm3\n" // 0B1G1R10B0G0G0 -> mm3 + "psllq $8, %%mm0\n" + "por %%mm0, %%mm4\n" // 0B3G3R30B2G2G2 -> mm4 + + "movq %%mm3, %3\n" + "movq %%mm4, 8%3\n" + + // next 4 pixels ------------------------------ + + "movq 8(%0), %%mm0\n" + + "movq %%mm0, %%mm1\n" + "pand KEEPR, %%mm1\n" + "psrlq $8, %%mm1\n" // B3B2B1B0 -> mm1 + "movq %%mm0, %%mm2\n" + "pand KEEPG, %%mm2\n" + "psrlq $3, %%mm2\n" // G3G2G1G0 -> mm2 + "movq %%mm0, %%mm3\n" + "pand KEEPB, %%mm3\n" + "psllq $3, %%mm3\n" // G3G2G1G0 -> mm3 + + "movq %%mm2, %%mm0\n" + "punpcklbw %%mm1, %%mm2\n" + "punpckhbw %%mm1, %%mm0\n" + + "pxor %%mm5, %%mm5\n" + "movq %%mm3, %%mm4\n" + "punpcklbw %%mm5, %%mm3\n" + "punpckhbw %%mm5, %%mm4\n" + + "psllq $8, %%mm2\n" + "por %%mm2, %%mm3\n" // 0B1G1R10B0G0G0 -> mm3 + "psllq $8, %%mm0\n" + "por %%mm0, %%mm4\n" // 0B3G3R30B2G2G2 -> mm4 + + "movq %%mm3, 16%3\n" + "movq %%mm4, 24%3\n" + + "add $16, %0\n" + + // standard algorithm -------------------------------------------------- + + // pack rgb + // was: "movq (%0), %%mm1\n" // load G2R2B1G1R1B0G0R0 + // ------------------------------ + // (uses: mm0, mm1) + "movd 8%3, %%mm0\n" + "psllq $24, %%mm0\n" + "movd 4%3, %%mm1\n" + "por %%mm1, %%mm0\n" + "psllq $24, %%mm0\n" + "movd %3, %%mm1\n" + "por %%mm0, %%mm1\n" + // ------------------------------ + + "pxor %%mm6, %%mm6\n" // 0 -> mm6 + "movq %%mm1, %%mm0\n" // G2R2B1G1R1B0G0R0 -> mm0 + "psrlq $16, %%mm1\n" // 00G2R2B1G1R1B0 -> mm1 + "punpcklbw ZEROSX, %%mm0\n" // R1B0G0R0 -> mm0 + "movq %%mm1, %%mm7\n" // 00G2R2B1G1R1B0 -> mm7 + "punpcklbw ZEROSX, %%mm1\n" // B1G1R1B0 -> mm1 + "movq %%mm0, %%mm2\n" // R1B0G0R0 -> mm2 + "pmaddwd YR0GRX, %%mm0\n" // yrR1,ygG0+yrR0 -> mm0 + "movq %%mm1, %%mm3\n" // B1G1R1B0 -> mm3 + "pmaddwd YBG0BX, %%mm1\n" // ybB1+ygG1,ybB0 -> mm1 + "movq %%mm2, %%mm4\n" // R1B0G0R0 -> mm4 + "movq %%mm3, %%mm5\n" // B1G1R1B0 -> mm5 + "punpckhbw %%mm6, %%mm7\n" // 00G2R2 -> mm7 + "paddd %%mm1, %%mm0\n" // Y1Y0 -> mm0 + + // pack rgb + // was: "movq 8(%0),%%mm1\n" // R5B4G4R4B3G3R3B2 -> mm1 + // ------------------------------ + // (uses: mm1, mm6) + "movd 20%3, %%mm1\n" + "psllq $24, %%mm1\n" + "movd 16%3, %%mm6\n" + "por %%mm6, %%mm1\n" + "psllq $24, %%mm1\n" + "movd 12%3, %%mm6\n" + "por %%mm6, %%mm1\n" + "psllq $8, %%mm1\n" + "movd 8%3, %%mm6\n" + "psrlq $16, %%mm6\n" + "por %%mm6, %%mm1\n" + // ------------------------------ + + "movq %%mm1, %%mm6\n" // R5B4G4R4B3G3R3B2 -> mm6 + "punpcklbw ZEROSX, %%mm1\n" // B3G3R3B2 -> mm1 + + //---------------------------------------------------------------------- + + "movq %%mm1, %%mm5\n" // B3G3R3B2 -> mm5 + "psllq $32, %%mm1\n" // R3B200 -> mm1 + + "paddd %%mm7, %%mm1\n" // R3B200+00G2R2=R3B2G2R2->mm1 + + "punpckhbw ZEROSX, %%mm6\n" // R5B4G4R3 -> mm6 + "movq %%mm1, %%mm3\n" // R3B2G2R2 -> mm3 + + "pmaddwd YR0GRX, %%mm1\n" // yrR3,ygG2+yrR2 -> mm1 + "movq %%mm5, %%mm7\n" // B3G3R3B2 -> mm7 + + "pmaddwd YBG0BX, %%mm5\n" // ybB3+ygG3,ybB2 -> mm5 + "psrad $15, %%mm0\n" // 32-bit scaled Y1Y0 -> mm0 + + "movq %%mm6, 36%3\n" // R5B4G4R4 -> TEMP0 + "movq %%mm3, %%mm6\n" // R3B2G2R2 -> mm6 + + "paddd %%mm5, %%mm1\n" // Y3Y2 -> mm1 + "movq %%mm7, %%mm5\n" // B3G3R3B2 -> mm5 + "psrad $15, %%mm1\n" // 32-bit scaled Y3Y2 -> mm1 + + "packssdw %%mm1, %%mm0\n" // Y3Y2Y1Y0 -> mm0 + + //---------------------------------------------------------------------- + + // pack rgb + // was: "movq 16(%0), %%mm1\n" // B7G7R7B6G6R6B5G5 -> mm1 + // ------------------------------ + // (uses: mm1, mm7) + "movd 28%3, %%mm1\n" + "psllq $24, %%mm1\n" + "movd 24%3, %%mm7\n" + "por %%mm7, %%mm1\n" + "psllq $16, %%mm1\n" + "movd 20%3, %%mm7\n" + "psrlq $8, %%mm7\n" + "por %%mm7, %%mm1\n" + // ------------------------------ + + "movq %%mm1, %%mm7\n" // B7G7R7B6G6R6B5G5 -> mm1 + + "psllq $16, %%mm7\n" // R7B6G6R6B5G500 -> mm7 + + "movq %%mm7, %%mm5\n" // R7B6G6R6B5G500 -> mm5 + + "movq %%mm0, 44%3\n" // 32-bit scaled Y3Y2Y1Y0 -> TEMPY + + "movq 36%3, %%mm0\n" // R5B4G4R4 -> mm0 + + "punpcklbw ZEROSX, %%mm7\n" // B5G500 -> mm7 + "movq %%mm0, %%mm6\n" // R5B4G4R4 -> mm6 + + "psrlq $32, %%mm0\n" // 00R5B4 -> mm0 + + "paddw %%mm0, %%mm7\n" // B5G5R5B4 -> mm7 + "movq %%mm6, %%mm2\n" // B5B4G4R4 -> mm2 + + "pmaddwd YR0GRX, %%mm2\n" // yrR5,ygG4+yrR4 -> mm2 + + "pmaddwd YBG0BX, %%mm7\n" // ybB5+ygG5,ybB4 -> mm7 + + //---------------------------------------------------------------------- + "paddd %%mm7, %%mm2\n" // Y5Y4 -> mm2 + + //---------------------------------------------------------------------- + + "pxor %%mm7, %%mm7\n" // 0 -> mm7 + + "punpckhbw %%mm7, %%mm1\n" // B7G7R7B6 -> mm1 + + "movq %%mm1, %%mm6\n" // B7G7R7B6 -> mm6 + + "pmaddwd YBG0BX, %%mm6\n" // ybB7+ygG7,ybB6 -> mm6 + "punpckhbw %%mm7, %%mm5\n" // R7B6G6R6 -> mm5 + + "pmaddwd YR0GRX, %%mm5\n" // yrR7,ygG6+yrR6 -> mm5 + + //---------------------------------------------------------------------- + + "psrad $15, %%mm2\n" // 32-bit scaled Y5Y4 -> mm2 + + "paddd %%mm5, %%mm6\n" // Y7Y6 -> mm6 + "psrad $15, %%mm6\n" // 32-bit scaled Y7Y6 -> mm6 + + "packssdw %%mm6, %%mm2\n" // Y7Y6Y5Y4 -> mm2 + + //---------------------------------------------------------------------- + + "movq 44%3, %%mm6\n" // 32-bit scaled Y3Y2Y1Y0 -> mm6 + "packuswb %%mm2, %%mm6\n" // all 8 Y values -> mm6 + + //---------------------------------------------------------------------- + + "movq %%mm6, (%1)\n" // store Y + + "add $8, %1\n" + + "sub $8, %2\n" + "jnz 1b\n" + "emms\n" + + : + : "r" (rgbSource), "r" (lum), "m" (pixel), "m" (buf[0]) + + ); +} + +void rgb2y16bit_mmx_row_fast(unsigned char* rgb, unsigned char* lum, int pixel) +{ + __asm__ __volatile__ ( + "1:\n" + + // unpack hicolor ( pixel 1 - 4) + "movq (%0), %%mm0\n" + + "movq %%mm0, %%mm1\n" + "pand KEEPR, %%mm1\n" + "psrlq $11, %%mm1\n" // B3B2B1B0 -> mm1 + + "movq %%mm0, %%mm2\n" + "pand KEEPG, %%mm2\n" + "psrlq $5, %%mm2\n" // G3G2G1G0 -> mm2 + "movq %%mm0, %%mm3\n" + "pand KEEPB, %%mm3\n" // R3R2R1R0 -> mm3 + + // calculate Y + "movq %%mm3, %%mm4\n" + "pmullw Y_RED, %%mm4\n" + + "movq %%mm2, %%mm5\n" + "pmullw Y_GREEN, %%mm5\n" + "paddw %%mm5, %%mm4\n" + + "movq %%mm1, %%mm6\n" + "pmullw Y_BLUE, %%mm6\n" + "paddw %%mm6, %%mm4\n" + + "psrlw $7, %%mm4\n" // Y3Y2Y1Y0 -> mm4 + + "pxor %%mm5, %%mm5\n" + "packuswb %%mm5, %%mm4\n" + + "movd %%mm4, (%1)\n" + "add $4, %1\n" + + "add $8, %0\n" + + "sub $4, %2\n" + "jnz 1b\n" + + "emms\n" + + : + : "r" (rgb), "r" (lum), "m" (pixel) + ); +} + + +#endif +// INTEL + + diff --git a/mpeglib/lib/util/render/dither2YUV/rgb2yuv16.h b/mpeglib/lib/util/render/dither2YUV/rgb2yuv16.h new file mode 100644 index 00000000..7e4d6508 --- /dev/null +++ b/mpeglib/lib/util/render/dither2YUV/rgb2yuv16.h @@ -0,0 +1,74 @@ +/*************************************************************************** + rgb2yuv16.h - description + ------------------- + begin : Tue Nov 2 2000 + copyright : (C) 2000 by Christian Gerlach + email : cgerlach@rhrk.uni-kl.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef __RGB2YUV16_H +#define __RGB2YUV16_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "../yuvPicture.h" +#include "rgb2yuvdefs.h" + +// slow C implementation +void rgb2yuv16bit(unsigned char* rgbSource, + unsigned char* destLum, + unsigned char* destCr, + unsigned char* destCb,int height, int width); + + + +// +// We compile with MMX if we are on INTEL arch +// (this does not mean that we really support MMX, +// this is a seperate/runtime check) +// + +#ifdef INTEL + +void rgb2yuv16bit_mmx(unsigned char* rgbSource, + unsigned char* lum, + unsigned char* cr, + unsigned char* cb,int height, int width); + +void rgb2yuv16bit_mmx_fast(unsigned char* rgbSource, + unsigned char* lum, + unsigned char* cr, + unsigned char* cb,int height, int width); + +void rgb2yuv16bit_mmx422_row(unsigned char* rgb, + unsigned char* lum, unsigned char* cr, + unsigned char* cb, int pixel); + +void rgb2y16bit_mmx_row(unsigned char* rgbSource, + unsigned char* lum, int pixel); + +void rgb2yuv16bit_mmx422_row_fast(unsigned char* rgb, + unsigned char* lum, unsigned char* cr, + unsigned char* cb, int pixel); + +void rgb2y16bit_mmx_row_fast(unsigned char* rgb, + unsigned char* lum, int pixel); + + +#endif +// INTEL + + + +#endif diff --git a/mpeglib/lib/util/render/dither2YUV/rgb2yuv32.cpp b/mpeglib/lib/util/render/dither2YUV/rgb2yuv32.cpp new file mode 100644 index 00000000..3e246e25 --- /dev/null +++ b/mpeglib/lib/util/render/dither2YUV/rgb2yuv32.cpp @@ -0,0 +1,1143 @@ +/*************************************************************************** + rgb2yuv32.cpp - description + ------------------- + begin : Tue Nov 2 2000 + copyright : (C) 2000 by Christian Gerlach + email : cgerlach@rhrk.uni-kl.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "rgb2yuv32.h" +#include <iostream> + +void rgb2yuv32(unsigned char* rgb, unsigned char* dest) +{ + dest[0] = Y_RGB(rgb[0], rgb[1], rgb[2]); + dest[1] = U_RGB(rgb[0], rgb[1], rgb[2]); + dest[2] = V_RGB(rgb[0], rgb[1], rgb[2]); +} + +void rgb2yuv24bit(unsigned char* rgbSource, + unsigned char* lum, + unsigned char* cr, + unsigned char* cb,int height, int width) { + int width2 = width / 2; + int height2 = height / 2; + int r, g, b, row, col; + + for (row=0 ; row<height2 ; row++) { + for (col=0 ; col<width2 ; col++) { + r = *rgbSource++; + g = *rgbSource++; + b = *rgbSource++; + + *lum++ = Y_RGB(r, g, b); + *cr++ = U_RGB(r, g, b); + *cb++ = V_RGB(r, g, b); + + r = *rgbSource++; + g = *rgbSource++; + b = *rgbSource++; + + *lum++ = Y_RGB(r, g, b); + } + for (col=0 ; col<width ; col++) { + r = *rgbSource++; + g = *rgbSource++; + b = *rgbSource++; + + *lum++ = Y_RGB(r, g, b); + } + } +} + +void rgb2yuv32bit(unsigned char* rgbSource, + unsigned char* lum, + unsigned char* cr, + unsigned char* cb,int height, int width) { + + int width2 = width / 2; + int height2 = height / 2; + int r, g, b, row, col; + + for (row=0 ; row<height2 ; row++) { + for (col=0 ; col<width2 ; col++) { + r = *rgbSource++; + g = *rgbSource++; + b = *rgbSource++; + rgbSource ++; + + *lum++ = Y_RGB(r, g, b); + *cr++ = U_RGB(r, g, b); + *cb++ = V_RGB(r, g, b); + + r = *rgbSource++; + g = *rgbSource++; + b = *rgbSource++; + rgbSource++; + + *lum++ = Y_RGB(r, g, b); + } + for (col=0 ; col<width ; col++) { + r = *rgbSource++; + g = *rgbSource++; + b = *rgbSource++; + rgbSource ++; + + *lum++ = Y_RGB(r, g, b); + } + } +} + +#ifndef INTEL +void rgb2yuv24bit_mmx(unsigned char* rgbSource, + unsigned char* lum, + unsigned char* cr, + unsigned char* cb,int height, int width) { + std::cout << "RGB->YUV render not compiled for INTEL"<<std::endl; + exit(0); +} + +void rgb2yuv32bit_mmx(unsigned char* rgbSource, + unsigned char* lum, + unsigned char* cr, + unsigned char* cb,int height, int width) { + std::cout << "RGB->YUV render not compiled for INTEL"<<std::endl; + exit(0); +} + +#endif + +#ifdef INTEL + +void rgb2yuv24bit_mmx(unsigned char* rgbSource, + unsigned char* lum, + unsigned char* cr, + unsigned char* cb,int height, int width) { + int width2 = width / 2; + int height2 = height / 2; + int row; + int bytesPerLine = width * 3; + + for (row=0 ; row<height2 ; row++) { + rgb2yuv24bit_mmx422_row(rgbSource, lum, cr, cb, width); + rgbSource += bytesPerLine; + lum += width; + cr += width2; + cb += width2; + + rgb2y24bit_mmx_row(rgbSource, lum, width); + rgbSource += bytesPerLine; + lum += width; + } +} + +void rgb2yuv32bit_mmx(unsigned char* rgbSource, + unsigned char* lum, + unsigned char* cr, + unsigned char* cb,int height, int width) { + + + int width2 = width / 2; + int height2 = height / 2; + int bytesPerLine = width * 4; + + for (int row=0 ; row<height2 ; row++) { + rgb2yuv32bit_mmx422_row(rgbSource, lum,cr, cb, width); + rgbSource += bytesPerLine; + lum += width; + cr += width2; + cb += width2; + + rgb2y32bit_mmx_row(rgbSource, lum, width); + rgbSource += bytesPerLine; + lum += width; + } +} + +void rgb2yuv24bit_mmx444_row(unsigned char* rgb, unsigned char* lum, unsigned char* cr, + unsigned char* cb, int pixel) +{ + unsigned int buf[8]; + + // %5 = TEMP0 + // 8%5 = TEMPY + // 16%5 = TEMPU + // 24%5 = TEMPV + + __asm__ __volatile__ ( + "1:\n" + + "movq (%0), %%mm1\n" // load G2R2B1G1R1B0G0R0 + "pxor %%mm6, %%mm6\n" // 0 -> mm6 + "movq %%mm1, %%mm0\n" // G2R2B1G1R1B0G0R0 -> mm0 + "psrlq $16, %%mm1\n" // 00G2R2B1G1R1B0 -> mm1 + "punpcklbw ZEROSX, %%mm0\n" // R1B0G0R0 -> mm0 + "movq %%mm1, %%mm7\n" // 00G2R2B1G1R1B0 -> mm7 + "punpcklbw ZEROSX, %%mm1\n" // B1G1R1B0 -> mm1 + "movq %%mm0, %%mm2\n" // R1B0G0R0 -> mm2 + "pmaddwd YR0GRX, %%mm0\n" // yrR1,ygG0+yrR0 -> mm0 + "movq %%mm1, %%mm3\n" // B1G1R1B0 -> mm3 + "pmaddwd YBG0BX, %%mm1\n" // ybB1+ygG1,ybB0 -> mm1 + "movq %%mm2, %%mm4\n" // R1B0G0R0 -> mm4 + "pmaddwd UR0GRX, %%mm2\n" // urR1,ugG0+urR0 -> mm2 + "movq %%mm3, %%mm5\n" // B1G1R1B0 -> mm5 + "pmaddwd UBG0BX, %%mm3\n" // ubB1+ugG1,ubB0 -> mm3 + "punpckhbw %%mm6, %%mm7\n" // 00G2R2 -> mm7 + "pmaddwd VR0GRX, %%mm4\n" // vrR1,vgG0+vrR0 -> mm4 + "paddd %%mm1, %%mm0\n" // Y1Y0 -> mm0 + + "pmaddwd VBG0BX, %%mm5\n" // vbB1+vgG1,vbB0 -> mm5 + + "movq 8(%0),%%mm1\n" // load G2R2B1G1R1B0G0R0 + "paddd %%mm3, %%mm2\n" // U1U0 -> mm2 + + "movq %%mm1, %%mm6\n" // R5B4G4R4B3G3R3B2 -> mm6 + "punpcklbw ZEROSX, %%mm1\n" // B3G3R3B2 -> mm1 + "paddd %%mm5, %%mm4\n" // V1V0 -> mm4 + + //---------------------------------------------------------------------- + + "movq %%mm1, %%mm5\n" // B3G3R3B2 -> mm5 + "psllq $32, %%mm1\n" // R3B200 -> mm1 + + "paddd %%mm7, %%mm1\n" // R3B200+00G2R2=R3B2G2R2->mm1 + + "punpckhbw ZEROSX, %%mm6\n" // R5B4G4R3 -> mm6 + "movq %%mm1, %%mm3\n" // R3B2G2R2 -> mm3 + + "pmaddwd YR0GRX, %%mm1\n" // yrR3,ygG2+yrR2 -> mm1 + "movq %%mm5, %%mm7\n" // B3G3R3B2 -> mm7 + + "pmaddwd YBG0BX, %%mm5\n" // ybB3+ygG3,ybB2 -> mm5 + "psrad $15, %%mm0\n" // 32-bit scaled Y1Y0 -> mm0 + + "movq %%mm6, %5\n" // R5B4G4R4 -> TEMP0 + "movq %%mm3, %%mm6\n" // R3B2G2R2 -> mm6 + "pmaddwd UR0GRX, %%mm6\n" // urR3,ugG2+urR2 -> mm6 + "psrad $15, %%mm2\n" // 32-bit scaled U1U0 -> mm2 + + "paddd %%mm5, %%mm1\n" // Y3Y2 -> mm1 + "movq %%mm7, %%mm5\n" // B3G3R3B2 -> mm5 + "pmaddwd UBG0BX, %%mm7\n" // ubB3+ugG3,ubB2 + "psrad $15, %%mm1\n" // 32-bit scaled Y3Y2 -> mm1 + + "pmaddwd VR0GRX, %%mm3\n" // vrR3,vgG2+vgR2 + "packssdw %%mm1, %%mm0\n" // Y3Y2Y1Y0 -> mm0 + + "pmaddwd VBG0BX, %%mm5\n" // vbB3+vgG3,vbB2 -> mm5 + "psrad $15, %%mm4\n" // 32-bit scaled V1V0 -> mm4 + + //---------------------------------------------------------------------- + + "movq 16(%0), %%mm1\n" // B7G7R7B6G6R6B5G5 -> mm7 + "paddd %%mm7, %%mm6\n" // U3U2 -> mm6 + + "movq %%mm1, %%mm7\n" // B7G7R7B6G6R6B5G5 -> mm1 + "psrad $15, %%mm6\n" // 32-bit scaled U3U2 -> mm6 + + "paddd %%mm5, %%mm3\n" // V3V2 -> mm3 + "psllq $16, %%mm7\n" // R7B6G6R6B5G500 -> mm7 + + "movq %%mm7, %%mm5\n" // R7B6G6R6B5G500 -> mm5 + "psrad $15, %%mm3\n" // 32-bit scaled V3V2 -> mm3 + + "movq %%mm0, 8%5\n" // 32-bit scaled Y3Y2Y1Y0 -> TEMPY + "packssdw %%mm6, %%mm2\n" // 32-bit scaled U3U2U1U0 -> mm2 + + "movq %5, %%mm0\n" // R5B4G4R4 -> mm0 + + "punpcklbw ZEROSX, %%mm7\n" // B5G500 -> mm7 + "movq %%mm0, %%mm6\n" // R5B4G4R4 -> mm6 + + "movq %%mm2, 16%5\n" // 32-bit scaled U3U2U1U0 -> TEMPU + "psrlq $32, %%mm0\n" // 00R5B4 -> mm0 + + "paddw %%mm0, %%mm7\n" // B5G5R5B4 -> mm7 + "movq %%mm6, %%mm2\n" // B5B4G4R4 -> mm2 + + "pmaddwd YR0GRX, %%mm2\n" // yrR5,ygG4+yrR4 -> mm2 + "movq %%mm7, %%mm0\n" // B5G5R5B4 -> mm0 + + "pmaddwd YBG0BX, %%mm7\n" // ybB5+ygG5,ybB4 -> mm7 + "packssdw %%mm3, %%mm4\n" // 32-bit scaled V3V2V1V0 -> mm4 + + //---------------------------------------------------------------------- + + "movq %%mm4, 24%5\n" // (V3V2V1V0)/256 -> mm4 + + "movq %%mm6, %%mm4\n" // B5B4G4R4 -> mm4 + + "pmaddwd UR0GRX, %%mm6\n" // urR5,ugG4+urR4 + "movq %%mm0, %%mm3\n" // B5G5R5B4 -> mm0 + + "pmaddwd UBG0BX, %%mm0\n" // ubB5+ugG5,ubB4 + "paddd %%mm7, %%mm2\n" // Y5Y4 -> mm2 + + //---------------------------------------------------------------------- + + "pmaddwd VR0GRX, %%mm4\n" // vrR5,vgG4+vrR4 -> mm4 + "pxor %%mm7, %%mm7\n" // 0 -> mm7 + + "pmaddwd VBG0BX, %%mm3\n" // vbB5+vgG5,vbB4 -> mm3 + "punpckhbw %%mm7, %%mm1\n" // B7G7R7B6 -> mm1 + + "paddd %%mm6, %%mm0\n" // U5U4 -> mm0 + "movq %%mm1, %%mm6\n" // B7G7R7B6 -> mm6 + + "pmaddwd YBG0BX, %%mm6\n" // ybB7+ygG7,ybB6 -> mm6 + "punpckhbw %%mm7, %%mm5\n" // R7B6G6R6 -> mm5 + + "movq %%mm5, %%mm7\n" // R7B6G6R6 -> mm7 + "paddd %%mm4, %%mm3\n" // V5V4 -> mm3 + + "pmaddwd YR0GRX, %%mm5\n" // yrR7,ygG6+yrR6 -> mm5 + "movq %%mm1, %%mm4\n" // B7G7R7B6 -> mm4 + + "pmaddwd UBG0BX, %%mm4\n" // ubB7+ugG7,ubB6 -> mm4 + "psrad $15, %%mm0\n" // 32-bit scaled U5U4 -> %%mm0 + + //---------------------------------------------------------------------- + + "paddd OFFSETWX, %%mm0\n" // add offset to U5U4 -> mm0 + "psrad $15, %%mm2\n" // 32-bit scaled Y5Y4 -> mm2 + + "paddd %%mm5, %%mm6\n" // Y7Y6 -> mm6 + "movq %%mm7, %%mm5\n" // R7B6G6R6 -> mm5 + + "pmaddwd UR0GRX, %%mm7\n" // urR7,ugG6+ugR6 -> mm7 + "psrad $15, %%mm3\n" // 32-bit scaled V5V4 -> mm3 + + "pmaddwd VBG0BX, %%mm1\n" // vbB7+vgG7,vbB6 -> mm1 + "psrad $15, %%mm6\n" // 32-bit scaled Y7Y6 -> mm6 + + "paddd OFFSETDX, %%mm4\n" // add offset to U7U6 + "packssdw %%mm6, %%mm2\n" // Y7Y6Y5Y4 -> mm2 + + "pmaddwd VR0GRX, %%mm5\n" // vrR7,vgG6+vrR6 -> mm5 + "paddd %%mm4, %%mm7\n" // U7U6 -> mm7 + + "psrad $15, %%mm7\n" // 32-bit scaled U7U6 -> mm7 + + //---------------------------------------------------------------------- + + "movq 8%5, %%mm6\n" // 32-bit scaled Y3Y2Y1Y0 -> mm6 + "packssdw %%mm7, %%mm0\n" // 32-bit scaled U7U6U5U4 -> mm0 + + "movq 16%5, %%mm4\n" // 32-bit scaled U3U2U1U0 -> mm4 + "packuswb %%mm2, %%mm6\n" // all 8 Y values -> mm6 + + "movq OFFSETBX, %%mm7\n" // 128,128,128,128 -> mm7 + "paddd %%mm5, %%mm1\n" // V7V6 -> mm1 + + "paddw %%mm7, %%mm4\n" // add offset to U3U2U1U0/256 + "psrad $15, %%mm1\n" // 32-bit scaled V7V6 -> mm1 + + //---------------------------------------------------------------------- + + "movq %%mm6, (%1)\n" // store Y + "packuswb %%mm0, %%mm4\n" // all 8 U values -> mm4 + + "movq 24%5, %%mm5\n" // 32-bit scaled V3V2V1V0 -> mm5 + "packssdw %%mm1, %%mm3\n" // V7V6V5V4 -> mm3 + "paddw %%mm7, %%mm5\n" // add offset to V3V2V1V0 + "paddw %%mm7, %%mm3\n" // add offset to V7V6V5V4 + + "movq %%mm4, (%2)\n" // store U + "packuswb %%mm3, %%mm5\n" // ALL 8 V values -> mm5 + + "movq %%mm5, (%3)\n" // store V + + "sub $8, %4\n" + "jnz 1b\n" + "emms\n" + + : + : "r" (rgb), "r" (lum), "r" (cr), "r" (cb), "m" (pixel), "m" (buf[0]) + ); +} + +void rgb2yuv24bit_mmx422_row(unsigned char* rgb, unsigned char* lum, unsigned char* cr, + unsigned char* cb, int pixel) +{ + unsigned int buf[8]; + + // %5 = TEMP0 + // 8%5 = TEMPY + // 16%5 = TEMPU + // 24%5 = TEMPV + + __asm__ __volatile__ ( + "1:\n" + + "movq (%0), %%mm1\n" // load G2R2B1G1R1B0G0R0 + "pxor %%mm6, %%mm6\n" // 0 -> mm6 + "movq %%mm1, %%mm0\n" // G2R2B1G1R1B0G0R0 -> mm0 + "psrlq $16, %%mm1\n" // 00G2R2B1G1R1B0 -> mm1 + "punpcklbw ZEROSX, %%mm0\n" // R1B0G0R0 -> mm0 + "movq %%mm1, %%mm7\n" // 00G2R2B1G1R1B0 -> mm7 + "punpcklbw ZEROSX, %%mm1\n" // B1G1R1B0 -> mm1 + "movq %%mm0, %%mm2\n" // R1B0G0R0 -> mm2 + "pmaddwd YR0GRX, %%mm0\n" // yrR1,ygG0+yrR0 -> mm0 + + "movq %%mm1, %%mm3\n" // B1G1R1B0 -> mm3 + "pmaddwd YBG0BX, %%mm1\n" // ybB1+ygG1,ybB0 -> mm1 + "movq %%mm2, %%mm4\n" // R1B0G0R0 -> mm4 + "pmaddwd UR0GRX, %%mm2\n" // urR1,ugG0+urR0 -> mm2 + "movq %%mm3, %%mm5\n" // B1G1R1B0 -> mm5 + "pmaddwd UBG0BX, %%mm3\n" // ubB1+ugG1,ubB0 -> mm3 + "punpckhbw %%mm6, %%mm7\n" // 00G2R2 -> mm7 + "pmaddwd VR0GRX, %%mm4\n" // vrR1,vgG0+vrR0 -> mm4 + "paddd %%mm1, %%mm0\n" // Y1Y0 -> mm0 + + "pmaddwd VBG0BX, %%mm5\n" // vbB1+vgG1,vbB0 -> mm5 + + "movq 8(%0),%%mm1\n" // load G2R2B1G1R1B0G0R0 + "paddd %%mm3, %%mm2\n" // U1U0 -> mm2 + + "movq %%mm1, %%mm6\n" // R5B4G4R4B3G3R3B2 -> mm6 + "punpcklbw ZEROSX, %%mm1\n" // B3G3R3B2 -> mm1 + "paddd %%mm5, %%mm4\n" // V1V0 -> mm4 + + //---------------------------------------------------------------------- + + "movq %%mm1, %%mm5\n" // B3G3R3B2 -> mm5 + "psllq $32, %%mm1\n" // R3B200 -> mm1 + + "paddd %%mm7, %%mm1\n" // R3B200+00G2R2=R3B2G2R2->mm1 + + "punpckhbw ZEROSX, %%mm6\n" // R5B4G4R3 -> mm6 + "movq %%mm1, %%mm3\n" // R3B2G2R2 -> mm3 + + "pmaddwd YR0GRX, %%mm1\n" // yrR3,ygG2+yrR2 -> mm1 + "movq %%mm5, %%mm7\n" // B3G3R3B2 -> mm7 + + "pmaddwd YBG0BX, %%mm5\n" // ybB3+ygG3,ybB2 -> mm5 + "psrad $15, %%mm0\n" // 32-bit scaled Y1Y0 -> mm0 + + "movq %%mm6, %5\n" // R5B4G4R4 -> TEMP0 + "movq %%mm3, %%mm6\n" // R3B2G2R2 -> mm6 + "pmaddwd UR0GRX, %%mm6\n" // urR3,ugG2+urR2 -> mm6 + "psrad $15, %%mm2\n" // 32-bit scaled U1U0 -> mm2 + + "paddd %%mm5, %%mm1\n" // Y3Y2 -> mm1 + "movq %%mm7, %%mm5\n" // B3G3R3B2 -> mm5 + "pmaddwd UBG0BX, %%mm7\n" // ubB3+ugG3,ubB2 + "psrad $15, %%mm1\n" // 32-bit scaled Y3Y2 -> mm1 + + "pmaddwd VR0GRX, %%mm3\n" // vrR3,vgG2+vgR2 + "packssdw %%mm1, %%mm0\n" // Y3Y2Y1Y0 -> mm0 + + "pmaddwd VBG0BX, %%mm5\n" // vbB3+vgG3,vbB2 -> mm5 + "psrad $15, %%mm4\n" // 32-bit scaled V1V0 -> mm4 + + //---------------------------------------------------------------------- + + "movq 16(%0), %%mm1\n" // B7G7R7B6G6R6B5G5 -> mm7 + "paddd %%mm7, %%mm6\n" // U3U2 -> mm6 + + "movq %%mm1, %%mm7\n" // B7G7R7B6G6R6B5G5 -> mm1 + "psrad $15, %%mm6\n" // 32-bit scaled U3U2 -> mm6 + + "paddd %%mm5, %%mm3\n" // V3V2 -> mm3 + "psllq $16, %%mm7\n" // R7B6G6R6B5G500 -> mm7 + + "movq %%mm7, %%mm5\n" // R7B6G6R6B5G500 -> mm5 + "psrad $15, %%mm3\n" // 32-bit scaled V3V2 -> mm3 + + "movq %%mm0, 8%5\n" // 32-bit scaled Y3Y2Y1Y0 -> TEMPY + "packssdw %%mm6, %%mm2\n" // 32-bit scaled U3U2U1U0 -> mm2 + + "movq %5, %%mm0\n" // R5B4G4R4 -> mm0 + + "punpcklbw ZEROSX, %%mm7\n" // B5G500 -> mm7 + "movq %%mm0, %%mm6\n" // R5B4G4R4 -> mm6 + + "movq %%mm2, 16%5\n" // 32-bit scaled U3U2U1U0 -> TEMPU + "psrlq $32, %%mm0\n" // 00R5B4 -> mm0 + + "paddw %%mm0, %%mm7\n" // B5G5R5B4 -> mm7 + "movq %%mm6, %%mm2\n" // B5B4G4R4 -> mm2 + + "pmaddwd YR0GRX, %%mm2\n" // yrR5,ygG4+yrR4 -> mm2 + "movq %%mm7, %%mm0\n" // B5G5R5B4 -> mm0 + + "pmaddwd YBG0BX, %%mm7\n" // ybB5+ygG5,ybB4 -> mm7 + "packssdw %%mm3, %%mm4\n" // 32-bit scaled V3V2V1V0 -> mm4 + + //---------------------------------------------------------------------- + + "movq %%mm4, 24%5\n" // (V3V2V1V0)/256 -> mm4 + + "movq %%mm6, %%mm4\n" // B5B4G4R4 -> mm4 + + "pmaddwd UR0GRX, %%mm6\n" // urR5,ugG4+urR4 + "movq %%mm0, %%mm3\n" // B5G5R5B4 -> mm0 + + "pmaddwd UBG0BX, %%mm0\n" // ubB5+ugG5,ubB4 + "paddd %%mm7, %%mm2\n" // Y5Y4 -> mm2 + + //---------------------------------------------------------------------- + + "pmaddwd VR0GRX, %%mm4\n" // vrR5,vgG4+vrR4 -> mm4 + "pxor %%mm7, %%mm7\n" // 0 -> mm7 + + "pmaddwd VBG0BX, %%mm3\n" // vbB5+vgG5,vbB4 -> mm3 + "punpckhbw %%mm7, %%mm1\n" // B7G7R7B6 -> mm1 + + "paddd %%mm6, %%mm0\n" // U5U4 -> mm0 + "movq %%mm1, %%mm6\n" // B7G7R7B6 -> mm6 + + "pmaddwd YBG0BX, %%mm6\n" // ybB7+ygG7,ybB6 -> mm6 + "punpckhbw %%mm7, %%mm5\n" // R7B6G6R6 -> mm5 + + "movq %%mm5, %%mm7\n" // R7B6G6R6 -> mm7 + "paddd %%mm4, %%mm3\n" // V5V4 -> mm3 + + "pmaddwd YR0GRX, %%mm5\n" // yrR7,ygG6+yrR6 -> mm5 + "movq %%mm1, %%mm4\n" // B7G7R7B6 -> mm4 + + "pmaddwd UBG0BX, %%mm4\n" // ubB7+ugG7,ubB6 -> mm4 + "psrad $15, %%mm0\n" // 32-bit scaled U5U4 -> %%mm0 + + //---------------------------------------------------------------------- + + "paddd OFFSETWX, %%mm0\n" // add offset to U5U4 -> mm0 + "psrad $15, %%mm2\n" // 32-bit scaled Y5Y4 -> mm2 + + "paddd %%mm5, %%mm6\n" // Y7Y6 -> mm6 + "movq %%mm7, %%mm5\n" // R7B6G6R6 -> mm5 + + "pmaddwd UR0GRX, %%mm7\n" // urR7,ugG6+ugR6 -> mm7 + "psrad $15, %%mm3\n" // 32-bit scaled V5V4 -> mm3 + + "pmaddwd VBG0BX, %%mm1\n" // vbB7+vgG7,vbB6 -> mm1 + "psrad $15, %%mm6\n" // 32-bit scaled Y7Y6 -> mm6 + + "paddd OFFSETDX, %%mm4\n" // add offset to U7U6 + "packssdw %%mm6, %%mm2\n" // Y7Y6Y5Y4 -> mm2 + + "pmaddwd VR0GRX, %%mm5\n" // vrR7,vgG6+vrR6 -> mm5 + "paddd %%mm4, %%mm7\n" // U7U6 -> mm7 + + "psrad $15, %%mm7\n" // 32-bit scaled U7U6 -> mm7 + + //---------------------------------------------------------------------- + + "movq 8%5, %%mm6\n" // 32-bit scaled Y3Y2Y1Y0 -> mm6 + "packssdw %%mm7, %%mm0\n" // 32-bit scaled U7U6U5U4 -> mm0 + + "movq 16%5, %%mm4\n" // 32-bit scaled U3U2U1U0 -> mm4 + "packuswb %%mm2, %%mm6\n" // all 8 Y values -> mm6 + + "movq OFFSETBX, %%mm7\n" // 128,128,128,128 -> mm7 + "paddd %%mm5, %%mm1\n" // V7V6 -> mm1 + + "paddw %%mm7, %%mm4\n" // add offset to U3U2U1U0/256 + "psrad $15, %%mm1\n" // 32-bit scaled V7V6 -> mm1 + + //---------------------------------------------------------------------- + + "movq %%mm6, (%1)\n" // store Y + "packuswb %%mm0, %%mm4\n" // all 8 U values -> mm4 + + "movq 24%5, %%mm5\n" // 32-bit scaled V3V2V1V0 -> mm5 + "packssdw %%mm1, %%mm3\n" // V7V6V5V4 -> mm3 + "paddw %%mm7, %%mm5\n" // add offset to V3V2V1V0 + "paddw %%mm7, %%mm3\n" // add offset to V7V6V5V4 + + "packuswb %%mm3, %%mm5\n" // ALL 8 V values -> mm5 + + // pack U and V + "movq CLEARX, %%mm2\n" + "pand %%mm2, %%mm4\n" + "pand %%mm2, %%mm5\n" + + "packuswb %%mm5, %%mm4\n" + + "movd %%mm4, (%2)\n" + "psrlq $32, %%mm4\n" + "movd %%mm4, (%3)\n" + + "add $24, %0\n" + "add $8, %1\n" + "add $4, %2\n" + "add $4, %3\n" + + "sub $8, %4\n" + "jnz 1b\n" + "emms\n" + + : + : "r" (rgb), "r" (lum), "r" (cr), "r" (cb), "m" (pixel), "m" (buf[0]) + ); +} + +void rgb2yuv32bit_mmx422_row(unsigned char* rgb, unsigned char* lum, unsigned char* cr, + unsigned char* cb, int pixel) +{ + unsigned int buf[8]; + + // %5 = TEMP0 + // 8%5 = TEMPY + // 16%5 = TEMPU + // 24%5 = TEMPV + + __asm__ __volatile__ ( + "1:\n" + + // pack rgb + // was: "movq (%0), %%mm1\n" // load G2R2B1G1R1B0G0R0 + // ------------------------------ + // (uses: mm0, mm1) + "movd 8(%0), %%mm0\n" + "psllq $24, %%mm0\n" + "movd 4(%0), %%mm1\n" + "por %%mm1, %%mm0\n" + "psllq $24, %%mm0\n" + "movd (%0), %%mm1\n" + "por %%mm0, %%mm1\n" + // ------------------------------ + + "pxor %%mm6, %%mm6\n" // 0 -> mm6 + "movq %%mm1, %%mm0\n" // G2R2B1G1R1B0G0R0 -> mm0 + "psrlq $16, %%mm1\n" // 00G2R2B1G1R1B0 -> mm1 + "punpcklbw ZEROSX, %%mm0\n" // R1B0G0R0 -> mm0 + "movq %%mm1, %%mm7\n" // 00G2R2B1G1R1B0 -> mm7 + "punpcklbw ZEROSX, %%mm1\n" // B1G1R1B0 -> mm1 + "movq %%mm0, %%mm2\n" // R1B0G0R0 -> mm2 + "pmaddwd YR0GRX, %%mm0\n" // yrR1,ygG0+yrR0 -> mm0 + + "movq %%mm1, %%mm3\n" // B1G1R1B0 -> mm3 + "pmaddwd YBG0BX, %%mm1\n" // ybB1+ygG1,ybB0 -> mm1 + "movq %%mm2, %%mm4\n" // R1B0G0R0 -> mm4 + "pmaddwd UR0GRX, %%mm2\n" // urR1,ugG0+urR0 -> mm2 + "movq %%mm3, %%mm5\n" // B1G1R1B0 -> mm5 + "pmaddwd UBG0BX, %%mm3\n" // ubB1+ugG1,ubB0 -> mm3 + "punpckhbw %%mm6, %%mm7\n" // 00G2R2 -> mm7 + "pmaddwd VR0GRX, %%mm4\n" // vrR1,vgG0+vrR0 -> mm4 + "paddd %%mm1, %%mm0\n" // Y1Y0 -> mm0 + + "pmaddwd VBG0BX, %%mm5\n" // vbB1+vgG1,vbB0 -> mm5 + + // pack rgb + // was: "movq 8(%0),%%mm1\n" // R5B4G4R4B3G3R3B2 -> mm1 + // ------------------------------ + // (uses: mm1, mm6) + "movd 20(%0), %%mm1\n" + "psllq $24, %%mm1\n" + "movd 16(%0), %%mm6\n" + "por %%mm6, %%mm1\n" + "psllq $24, %%mm1\n" + "movd 12(%0), %%mm6\n" + "por %%mm6, %%mm1\n" + "psllq $8, %%mm1\n" + "movd 8(%0), %%mm6\n" + "psrlq $16, %%mm6\n" + "por %%mm6, %%mm1\n" + // ------------------------------ + + "paddd %%mm3, %%mm2\n" // U1U0 -> mm2 + + "movq %%mm1, %%mm6\n" // R5B4G4R4B3G3R3B2 -> mm6 + "punpcklbw ZEROSX, %%mm1\n" // B3G3R3B2 -> mm1 + "paddd %%mm5, %%mm4\n" // V1V0 -> mm4 + + //---------------------------------------------------------------------- + + "movq %%mm1, %%mm5\n" // B3G3R3B2 -> mm5 + "psllq $32, %%mm1\n" // R3B200 -> mm1 + + "paddd %%mm7, %%mm1\n" // R3B200+00G2R2=R3B2G2R2->mm1 + + "punpckhbw ZEROSX, %%mm6\n" // R5B4G4R3 -> mm6 + "movq %%mm1, %%mm3\n" // R3B2G2R2 -> mm3 + + "pmaddwd YR0GRX, %%mm1\n" // yrR3,ygG2+yrR2 -> mm1 + "movq %%mm5, %%mm7\n" // B3G3R3B2 -> mm7 + + "pmaddwd YBG0BX, %%mm5\n" // ybB3+ygG3,ybB2 -> mm5 + "psrad $15, %%mm0\n" // 32-bit scaled Y1Y0 -> mm0 + + "movq %%mm6, %5\n" // R5B4G4R4 -> TEMP0 + "movq %%mm3, %%mm6\n" // R3B2G2R2 -> mm6 + "pmaddwd UR0GRX, %%mm6\n" // urR3,ugG2+urR2 -> mm6 + "psrad $15, %%mm2\n" // 32-bit scaled U1U0 -> mm2 + + "paddd %%mm5, %%mm1\n" // Y3Y2 -> mm1 + "movq %%mm7, %%mm5\n" // B3G3R3B2 -> mm5 + "pmaddwd UBG0BX, %%mm7\n" // ubB3+ugG3,ubB2 + "psrad $15, %%mm1\n" // 32-bit scaled Y3Y2 -> mm1 + + "pmaddwd VR0GRX, %%mm3\n" // vrR3,vgG2+vgR2 + "packssdw %%mm1, %%mm0\n" // Y3Y2Y1Y0 -> mm0 + + "pmaddwd VBG0BX, %%mm5\n" // vbB3+vgG3,vbB2 -> mm5 + "psrad $15, %%mm4\n" // 32-bit scaled V1V0 -> mm4 + + //---------------------------------------------------------------------- + + "paddd %%mm7, %%mm6\n" // U3U2 -> mm6 + + // pack rgb + // was: "movq 16(%0), %%mm1\n" // B7G7R7B6G6R6B5G5 -> mm1 + // ------------------------------ + // (uses: mm1, mm7) + "movd 28(%0), %%mm1\n" + "psllq $24, %%mm1\n" + "movd 24(%0), %%mm7\n" + "por %%mm7, %%mm1\n" + "psllq $16, %%mm1\n" + "movd 20(%0), %%mm7\n" + "psrlq $8, %%mm7\n" + "por %%mm7, %%mm1\n" + // ------------------------------ + + "movq %%mm1, %%mm7\n" // B7G7R7B6G6R6B5G5 -> mm1 + "psrad $15, %%mm6\n" // 32-bit scaled U3U2 -> mm6 + + "paddd %%mm5, %%mm3\n" // V3V2 -> mm3 + "psllq $16, %%mm7\n" // R7B6G6R6B5G500 -> mm7 + + "movq %%mm7, %%mm5\n" // R7B6G6R6B5G500 -> mm5 + "psrad $15, %%mm3\n" // 32-bit scaled V3V2 -> mm3 + + "movq %%mm0, 8%5\n" // 32-bit scaled Y3Y2Y1Y0 -> TEMPY + + "packssdw %%mm6, %%mm2\n" // 32-bit scaled U3U2U1U0 -> mm2 + + "movq %5, %%mm0\n" // R5B4G4R4 -> mm0 + + "punpcklbw ZEROSX, %%mm7\n" // B5G500 -> mm7 + "movq %%mm0, %%mm6\n" // R5B4G4R4 -> mm6 + + "movq %%mm2, 16%5\n" // 32-bit scaled U3U2U1U0 -> TEMPU + "psrlq $32, %%mm0\n" // 00R5B4 -> mm0 + + "paddw %%mm0, %%mm7\n" // B5G5R5B4 -> mm7 + "movq %%mm6, %%mm2\n" // B5B4G4R4 -> mm2 + + "pmaddwd YR0GRX, %%mm2\n" // yrR5,ygG4+yrR4 -> mm2 + "movq %%mm7, %%mm0\n" // B5G5R5B4 -> mm0 + + "pmaddwd YBG0BX, %%mm7\n" // ybB5+ygG5,ybB4 -> mm7 + "packssdw %%mm3, %%mm4\n" // 32-bit scaled V3V2V1V0 -> mm4 + + //---------------------------------------------------------------------- + + "movq %%mm4, 24%5\n" // (V3V2V1V0)/256 -> mm4 + + "movq %%mm6, %%mm4\n" // B5B4G4R4 -> mm4 + + "pmaddwd UR0GRX, %%mm6\n" // urR5,ugG4+urR4 + "movq %%mm0, %%mm3\n" // B5G5R5B4 -> mm0 + + "pmaddwd UBG0BX, %%mm0\n" // ubB5+ugG5,ubB4 + "paddd %%mm7, %%mm2\n" // Y5Y4 -> mm2 + + //---------------------------------------------------------------------- + + "pmaddwd VR0GRX, %%mm4\n" // vrR5,vgG4+vrR4 -> mm4 + "pxor %%mm7, %%mm7\n" // 0 -> mm7 + + "pmaddwd VBG0BX, %%mm3\n" // vbB5+vgG5,vbB4 -> mm3 + "punpckhbw %%mm7, %%mm1\n" // B7G7R7B6 -> mm1 + + "paddd %%mm6, %%mm0\n" // U5U4 -> mm0 + "movq %%mm1, %%mm6\n" // B7G7R7B6 -> mm6 + + "pmaddwd YBG0BX, %%mm6\n" // ybB7+ygG7,ybB6 -> mm6 + "punpckhbw %%mm7, %%mm5\n" // R7B6G6R6 -> mm5 + + "movq %%mm5, %%mm7\n" // R7B6G6R6 -> mm7 + "paddd %%mm4, %%mm3\n" // V5V4 -> mm3 + + "pmaddwd YR0GRX, %%mm5\n" // yrR7,ygG6+yrR6 -> mm5 + "movq %%mm1, %%mm4\n" // B7G7R7B6 -> mm4 + + "pmaddwd UBG0BX, %%mm4\n" // ubB7+ugG7,ubB6 -> mm4 + "psrad $15, %%mm0\n" // 32-bit scaled U5U4 -> %%mm0 + + //---------------------------------------------------------------------- + + "paddd OFFSETWX, %%mm0\n" // add offset to U5U4 -> mm0 + "psrad $15, %%mm2\n" // 32-bit scaled Y5Y4 -> mm2 + + "paddd %%mm5, %%mm6\n" // Y7Y6 -> mm6 + "movq %%mm7, %%mm5\n" // R7B6G6R6 -> mm5 + + "pmaddwd UR0GRX, %%mm7\n" // urR7,ugG6+ugR6 -> mm7 + "psrad $15, %%mm3\n" // 32-bit scaled V5V4 -> mm3 + + "pmaddwd VBG0BX, %%mm1\n" // vbB7+vgG7,vbB6 -> mm1 + "psrad $15, %%mm6\n" // 32-bit scaled Y7Y6 -> mm6 + + "paddd OFFSETDX, %%mm4\n" // add offset to U7U6 + "packssdw %%mm6, %%mm2\n" // Y7Y6Y5Y4 -> mm2 + + "pmaddwd VR0GRX, %%mm5\n" // vrR7,vgG6+vrR6 -> mm5 + "paddd %%mm4, %%mm7\n" // U7U6 -> mm7 + + "psrad $15, %%mm7\n" // 32-bit scaled U7U6 -> mm7 + + //---------------------------------------------------------------------- + + "movq 8%5, %%mm6\n" // 32-bit scaled Y3Y2Y1Y0 -> mm6 + "packssdw %%mm7, %%mm0\n" // 32-bit scaled U7U6U5U4 -> mm0 + + "movq 16%5, %%mm4\n" // 32-bit scaled U3U2U1U0 -> mm4 + "packuswb %%mm2, %%mm6\n" // all 8 Y values -> mm6 + + "movq OFFSETBX, %%mm7\n" // 128,128,128,128 -> mm7 + "paddd %%mm5, %%mm1\n" // V7V6 -> mm1 + + "paddw %%mm7, %%mm4\n" // add offset to U3U2U1U0/256 + "psrad $15, %%mm1\n" // 32-bit scaled V7V6 -> mm1 + + //---------------------------------------------------------------------- + + "movq %%mm6, (%1)\n" // store Y + + "packuswb %%mm0, %%mm4\n" // all 8 U values -> mm4 + "movq 24%5, %%mm5\n" // 32-bit scaled V3V2V1V0 -> mm5 + + "packssdw %%mm1, %%mm3\n" // V7V6V5V4 -> mm3 + "paddw %%mm7, %%mm5\n" // add offset to V3V2V1V0 + "paddw %%mm7, %%mm3\n" // add offset to V7V6V5V4 + + "packuswb %%mm3, %%mm5\n" // ALL 8 V values -> mm5 + + "movq CLEARX, %%mm2\n" + "pand %%mm2, %%mm4\n" + "pand %%mm2, %%mm5\n" + + "packuswb %%mm5, %%mm4\n" + + "movd %%mm4, (%2)\n" + "psrlq $32, %%mm4\n" + "movd %%mm4, (%3)\n" + + "add $32, %0\n" + "add $8, %1\n" + "add $4, %2\n" + "add $4, %3\n" + + "sub $8, %4\n" + "jnz 1b\n" + + "emms\n" + + : + : "r" (rgb), "r" (lum), "r" (cr), "r" (cb), "m" (pixel), "m" (buf[0]) + + ); +} + +void rgb2y24bit_mmx_row(unsigned char* rgbSource, unsigned char* lum, int pixel) +{ + unsigned int buf[4]; + + // %3 = TEMP0 + // 8%3 = TEMPY + + __asm__ __volatile__ ( + "1:\n" + + "movq (%0), %%mm1\n" // load G2R2B1G1R1B0G0R0 + "pxor %%mm6, %%mm6\n" // 0 -> mm6 + "movq %%mm1, %%mm0\n" // G2R2B1G1R1B0G0R0 -> mm0 + "psrlq $16, %%mm1\n" // 00G2R2B1G1R1B0 -> mm1 + "punpcklbw ZEROSX, %%mm0\n" // R1B0G0R0 -> mm0 + "movq %%mm1, %%mm7\n" // 00G2R2B1G1R1B0 -> mm7 + "punpcklbw ZEROSX, %%mm1\n" // B1G1R1B0 -> mm1 + "movq %%mm0, %%mm2\n" // R1B0G0R0 -> mm2 + "pmaddwd YR0GRX, %%mm0\n" // yrR1,ygG0+yrR0 -> mm0 + "movq %%mm1, %%mm3\n" // B1G1R1B0 -> mm3 + "pmaddwd YBG0BX, %%mm1\n" // ybB1+ygG1,ybB0 -> mm1 + "movq %%mm2, %%mm4\n" // R1B0G0R0 -> mm4 + "movq %%mm3, %%mm5\n" // B1G1R1B0 -> mm5 + "punpckhbw %%mm6, %%mm7\n" // 00G2R2 -> mm7 + "paddd %%mm1, %%mm0\n" // Y1Y0 -> mm0 + + "movq 8(%0),%%mm1\n" // load G2R2B1G1R1B0G0R0 + + "movq %%mm1, %%mm6\n" // R5B4G4R4B3G3R3B2 -> mm6 + "punpcklbw ZEROSX, %%mm1\n" // B3G3R3B2 -> mm1 + + //---------------------------------------------------------------------- + + "movq %%mm1, %%mm5\n" // B3G3R3B2 -> mm5 + "psllq $32, %%mm1\n" // R3B200 -> mm1 + + "paddd %%mm7, %%mm1\n" // R3B200+00G2R2=R3B2G2R2->mm1 + + "punpckhbw ZEROSX, %%mm6\n" // R5B4G4R3 -> mm6 + "movq %%mm1, %%mm3\n" // R3B2G2R2 -> mm3 + + "pmaddwd YR0GRX, %%mm1\n" // yrR3,ygG2+yrR2 -> mm1 + "movq %%mm5, %%mm7\n" // B3G3R3B2 -> mm7 + + "pmaddwd YBG0BX, %%mm5\n" // ybB3+ygG3,ybB2 -> mm5 + "psrad $15, %%mm0\n" // 32-bit scaled Y1Y0 -> mm0 + + "movq %%mm6, %3\n" // R5B4G4R4 -> TEMP0 + "movq %%mm3, %%mm6\n" // R3B2G2R2 -> mm6 + + "paddd %%mm5, %%mm1\n" // Y3Y2 -> mm1 + "movq %%mm7, %%mm5\n" // B3G3R3B2 -> mm5 + "psrad $15, %%mm1\n" // 32-bit scaled Y3Y2 -> mm1 + + "packssdw %%mm1, %%mm0\n" // Y3Y2Y1Y0 -> mm0 + + //---------------------------------------------------------------------- + + "movq 16(%0), %%mm1\n" // B7G7R7B6G6R6B5G5 -> mm7 + + "movq %%mm1, %%mm7\n" // B7G7R7B6G6R6B5G5 -> mm1 + + "psllq $16, %%mm7\n" // R7B6G6R6B5G500 -> mm7 + + "movq %%mm7, %%mm5\n" // R7B6G6R6B5G500 -> mm5 + + "movq %%mm0, 8%3\n" // 32-bit scaled Y3Y2Y1Y0 -> TEMPY + + "movq %3, %%mm0\n" // R5B4G4R4 -> mm0 + + "punpcklbw ZEROSX, %%mm7\n" // B5G500 -> mm7 + "movq %%mm0, %%mm6\n" // R5B4G4R4 -> mm6 + + "psrlq $32, %%mm0\n" // 00R5B4 -> mm0 + + "paddw %%mm0, %%mm7\n" // B5G5R5B4 -> mm7 + "movq %%mm6, %%mm2\n" // B5B4G4R4 -> mm2 + + "pmaddwd YR0GRX, %%mm2\n" // yrR5,ygG4+yrR4 -> mm2 + + "pmaddwd YBG0BX, %%mm7\n" // ybB5+ygG5,ybB4 -> mm7 + + //---------------------------------------------------------------------- + "paddd %%mm7, %%mm2\n" // Y5Y4 -> mm2 + + //---------------------------------------------------------------------- + + "pxor %%mm7, %%mm7\n" // 0 -> mm7 + + "punpckhbw %%mm7, %%mm1\n" // B7G7R7B6 -> mm1 + + "movq %%mm1, %%mm6\n" // B7G7R7B6 -> mm6 + + "pmaddwd YBG0BX, %%mm6\n" // ybB7+ygG7,ybB6 -> mm6 + "punpckhbw %%mm7, %%mm5\n" // R7B6G6R6 -> mm5 + + "pmaddwd YR0GRX, %%mm5\n" // yrR7,ygG6+yrR6 -> mm5 + + //---------------------------------------------------------------------- + + "psrad $15, %%mm2\n" // 32-bit scaled Y5Y4 -> mm2 + + "paddd %%mm5, %%mm6\n" // Y7Y6 -> mm6 + "psrad $15, %%mm6\n" // 32-bit scaled Y7Y6 -> mm6 + + "packssdw %%mm6, %%mm2\n" // Y7Y6Y5Y4 -> mm2 + + //---------------------------------------------------------------------- + + "movq 8%3, %%mm6\n" // 32-bit scaled Y3Y2Y1Y0 -> mm6 + "packuswb %%mm2, %%mm6\n" // all 8 Y values -> mm6 + + //---------------------------------------------------------------------- + + "movq %%mm6, (%1)\n" // store Y + + "add $24, %0\n" + "add $8, %1\n" + + "sub $8, %2\n" + "jnz 1b\n" + "emms\n" + + : + : "r" (rgbSource), "r" (lum), "m" (pixel), "m" (buf[0]) + + ); +} + +void rgb2y32bit_mmx_row(unsigned char* rgbSource, unsigned char* lum, int pixel) +{ + unsigned int buf[4]; + + // %3 = TEMP0 + // 8%3 = TEMPY + + __asm__ __volatile__ ( + "1:\n" + + // pack rgb + // was: "movq (%0), %%mm1\n" // load G2R2B1G1R1B0G0R0 + // ------------------------------ + // (uses: mm0, mm1) + "movd 8(%0), %%mm0\n" + "psllq $24, %%mm0\n" + "movd 4(%0), %%mm1\n" + "por %%mm1, %%mm0\n" + "psllq $24, %%mm0\n" + "movd (%0), %%mm1\n" + "por %%mm0, %%mm1\n" + // ------------------------------ + + "pxor %%mm6, %%mm6\n" // 0 -> mm6 + "movq %%mm1, %%mm0\n" // G2R2B1G1R1B0G0R0 -> mm0 + "psrlq $16, %%mm1\n" // 00G2R2B1G1R1B0 -> mm1 + "punpcklbw ZEROSX, %%mm0\n" // R1B0G0R0 -> mm0 + "movq %%mm1, %%mm7\n" // 00G2R2B1G1R1B0 -> mm7 + "punpcklbw ZEROSX, %%mm1\n" // B1G1R1B0 -> mm1 + "movq %%mm0, %%mm2\n" // R1B0G0R0 -> mm2 + "pmaddwd YR0GRX, %%mm0\n" // yrR1,ygG0+yrR0 -> mm0 + "movq %%mm1, %%mm3\n" // B1G1R1B0 -> mm3 + "pmaddwd YBG0BX, %%mm1\n" // ybB1+ygG1,ybB0 -> mm1 + "movq %%mm2, %%mm4\n" // R1B0G0R0 -> mm4 + "movq %%mm3, %%mm5\n" // B1G1R1B0 -> mm5 + "punpckhbw %%mm6, %%mm7\n" // 00G2R2 -> mm7 + "paddd %%mm1, %%mm0\n" // Y1Y0 -> mm0 + + // pack rgb + // was: "movq 8(%0),%%mm1\n" // R5B4G4R4B3G3R3B2 -> mm1 + // ------------------------------ + // (uses: mm1, mm6) + "movd 20(%0), %%mm1\n" + "psllq $24, %%mm1\n" + "movd 16(%0), %%mm6\n" + "por %%mm6, %%mm1\n" + "psllq $24, %%mm1\n" + "movd 12(%0), %%mm6\n" + "por %%mm6, %%mm1\n" + "psllq $8, %%mm1\n" + "movd 8(%0), %%mm6\n" + "psrlq $16, %%mm6\n" + "por %%mm6, %%mm1\n" + // ------------------------------ + + "movq %%mm1, %%mm6\n" // R5B4G4R4B3G3R3B2 -> mm6 + "punpcklbw ZEROSX, %%mm1\n" // B3G3R3B2 -> mm1 + + //---------------------------------------------------------------------- + + "movq %%mm1, %%mm5\n" // B3G3R3B2 -> mm5 + "psllq $32, %%mm1\n" // R3B200 -> mm1 + + "paddd %%mm7, %%mm1\n" // R3B200+00G2R2=R3B2G2R2->mm1 + + "punpckhbw ZEROSX, %%mm6\n" // R5B4G4R3 -> mm6 + "movq %%mm1, %%mm3\n" // R3B2G2R2 -> mm3 + + "pmaddwd YR0GRX, %%mm1\n" // yrR3,ygG2+yrR2 -> mm1 + "movq %%mm5, %%mm7\n" // B3G3R3B2 -> mm7 + + "pmaddwd YBG0BX, %%mm5\n" // ybB3+ygG3,ybB2 -> mm5 + "psrad $15, %%mm0\n" // 32-bit scaled Y1Y0 -> mm0 + + "movq %%mm6, %3\n" // R5B4G4R4 -> TEMP0 + "movq %%mm3, %%mm6\n" // R3B2G2R2 -> mm6 + + "paddd %%mm5, %%mm1\n" // Y3Y2 -> mm1 + "movq %%mm7, %%mm5\n" // B3G3R3B2 -> mm5 + "psrad $15, %%mm1\n" // 32-bit scaled Y3Y2 -> mm1 + + "packssdw %%mm1, %%mm0\n" // Y3Y2Y1Y0 -> mm0 + + //---------------------------------------------------------------------- + + // pack rgb + // was: "movq 16(%0), %%mm1\n" // B7G7R7B6G6R6B5G5 -> mm1 + // ------------------------------ + // (uses: mm1, mm7) + "movd 28(%0), %%mm1\n" + "psllq $24, %%mm1\n" + "movd 24(%0), %%mm7\n" + "por %%mm7, %%mm1\n" + "psllq $16, %%mm1\n" + "movd 20(%0), %%mm7\n" + "psrlq $8, %%mm7\n" + "por %%mm7, %%mm1\n" + // ------------------------------ + + "movq %%mm1, %%mm7\n" // B7G7R7B6G6R6B5G5 -> mm1 + + "psllq $16, %%mm7\n" // R7B6G6R6B5G500 -> mm7 + + "movq %%mm7, %%mm5\n" // R7B6G6R6B5G500 -> mm5 + + "movq %%mm0, 8%3\n" // 32-bit scaled Y3Y2Y1Y0 -> TEMPY + + "movq %3, %%mm0\n" // R5B4G4R4 -> mm0 + + "punpcklbw ZEROSX, %%mm7\n" // B5G500 -> mm7 + "movq %%mm0, %%mm6\n" // R5B4G4R4 -> mm6 + + "psrlq $32, %%mm0\n" // 00R5B4 -> mm0 + + "paddw %%mm0, %%mm7\n" // B5G5R5B4 -> mm7 + "movq %%mm6, %%mm2\n" // B5B4G4R4 -> mm2 + + "pmaddwd YR0GRX, %%mm2\n" // yrR5,ygG4+yrR4 -> mm2 + + "pmaddwd YBG0BX, %%mm7\n" // ybB5+ygG5,ybB4 -> mm7 + + //---------------------------------------------------------------------- + "paddd %%mm7, %%mm2\n" // Y5Y4 -> mm2 + + //---------------------------------------------------------------------- + + "pxor %%mm7, %%mm7\n" // 0 -> mm7 + + "punpckhbw %%mm7, %%mm1\n" // B7G7R7B6 -> mm1 + + "movq %%mm1, %%mm6\n" // B7G7R7B6 -> mm6 + + "pmaddwd YBG0BX, %%mm6\n" // ybB7+ygG7,ybB6 -> mm6 + "punpckhbw %%mm7, %%mm5\n" // R7B6G6R6 -> mm5 + + "pmaddwd YR0GRX, %%mm5\n" // yrR7,ygG6+yrR6 -> mm5 + + //---------------------------------------------------------------------- + + "psrad $15, %%mm2\n" // 32-bit scaled Y5Y4 -> mm2 + + "paddd %%mm5, %%mm6\n" // Y7Y6 -> mm6 + "psrad $15, %%mm6\n" // 32-bit scaled Y7Y6 -> mm6 + + "packssdw %%mm6, %%mm2\n" // Y7Y6Y5Y4 -> mm2 + + //---------------------------------------------------------------------- + + "movq 8%3, %%mm6\n" // 32-bit scaled Y3Y2Y1Y0 -> mm6 + "packuswb %%mm2, %%mm6\n" // all 8 Y values -> mm6 + + //---------------------------------------------------------------------- + + "movq %%mm6, (%1)\n" // store Y + + "add $32, %0\n" + "add $8, %1\n" + + "sub $8, %2\n" + "jnz 1b\n" + "emms\n" + + : + : "r" (rgbSource), "r" (lum), "r" (pixel), "m" (buf[0]) + + ); +} + +#endif +// INTEL + diff --git a/mpeglib/lib/util/render/dither2YUV/rgb2yuv32.h b/mpeglib/lib/util/render/dither2YUV/rgb2yuv32.h new file mode 100644 index 00000000..75fea27f --- /dev/null +++ b/mpeglib/lib/util/render/dither2YUV/rgb2yuv32.h @@ -0,0 +1,93 @@ +/*************************************************************************** + rgb2yuv32.h - description + ------------------- + begin : Tue Nov 2 2000 + copyright : (C) 2000 by Christian Gerlach + email : cgerlach@rhrk.uni-kl.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef _RGB2YUV32_H_ +#define _RGB2YUV32_H_ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "../yuvPicture.h" +#include "rgb2yuvdefs.h" + +void rgb2yuv32(unsigned char* rgb, unsigned char* dest); + +// slow C rountines +void rgb2yuv24bit(unsigned char* rgbSource, + unsigned char* lum, + unsigned char* cr, + unsigned char* cb,int height, int width); + +void rgb2yuv32bit(unsigned char* rgbSource, + unsigned char* lum, + unsigned char* cr, + unsigned char* cb,int height, int width); + + + + +#ifndef INTEL +void rgb2yuv24bit_mmx(unsigned char* rgbSource, + unsigned char* lum, + unsigned char* cr, + unsigned char* cb,int height, int width); + +void rgb2yuv32bit_mmx(unsigned char* rgbSource, + unsigned char* lum, + unsigned char* cr, + unsigned char* cb,int height, int width); +#endif + + +#ifdef INTEL + +void rgb2yuv24bit_mmx(unsigned char* rgbSource, + unsigned char* lum, + unsigned char* cr, + unsigned char* cb,int height, int width); + +void rgb2yuv32bit_mmx(unsigned char* rgbSource, + unsigned char* lum, + unsigned char* cr, + unsigned char* cb,int height, int width); + + +void rgb2yuv24bit_mmx444_row(unsigned char* rgb, + unsigned char* lum, unsigned char* cr, + unsigned char* cb, int pixel); + + +void rgb2yuv24bit_mmx422_row(unsigned char* rgb, + unsigned char* lum, unsigned char* cr, + unsigned char* cb, int pixel); + +void rgb2yuv32bit_mmx422_row(unsigned char* rgb, + unsigned char* lum, unsigned char* cr, + unsigned char* cb, int pixel); + +void rgb2y24bit_mmx_row(unsigned char* rgbSource, + unsigned char* lum, int pixel); + +void rgb2y32bit_mmx_row(unsigned char* rgbSource, + unsigned char* lum, int pixel); + +#endif +//INTEL + + +#endif diff --git a/mpeglib/lib/util/render/dither2YUV/rgb2yuvdefs.h b/mpeglib/lib/util/render/dither2YUV/rgb2yuvdefs.h new file mode 100644 index 00000000..5c7ae574 --- /dev/null +++ b/mpeglib/lib/util/render/dither2YUV/rgb2yuvdefs.h @@ -0,0 +1,74 @@ +/*************************************************************************** + rgb2yuvdefs.h - description + ------------------- + begin : Tue Nov 2 2000 + copyright : (C) 2000 by Christian Gerlach + email : cgerlach@rhrk.uni-kl.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef __RGB2YUVDEFS_H +#define __RGB2YUVDEFS_H + +/* gcc 3.3.1 and later optimise the "not used" (only in asm code) + symbols away. So we need to mark them as used. */ +#if defined(__GNUC_PREREQ__) && !defined(__GNUC_PREREQ) +#define __GNUC_PREREQ __GNUC_PREREQ__ +#endif +#ifdef __GNUC_PREREQ +#if __GNUC_PREREQ (3,1) +# define __attribute_used__ __attribute__ ((__used__)) +#else +# define __attribute_used__ +#endif +#else +# define __attribute_used__ +#endif + +// hicolor mode (16 bit) with r(5) g(6) b(5) bits (reverse order b, g, r) +#define RED(rgb) (unsigned char) ((rgb) << 3) +#define GREEN(rgb) (((rgb) & 0x7e0) >> 3) +#define BLUE(rgb) (((rgb) & 0xf800) >> 8) + +#define YUV_SHIFT 15 +#define YUV_HALF (1<<(YUV_SHIFT-1)) +#define YUV_ONE (1<<YUV_SHIFT) +#define Y_R ((int)( 0.299 * YUV_ONE )) +#define Y_G ((int)( 0.587 * YUV_ONE )) +#define Y_B ((int)( 0.114 * YUV_ONE )) +#define U_R ((int)(-0.146 * YUV_ONE )) +#define U_G ((int)(-0.288 * YUV_ONE )) +#define U_B ((int)( 0.434 * YUV_ONE )) +#define V_R ((int)( 0.617 * YUV_ONE )) +#define V_G ((int)(-0.517 * YUV_ONE )) +#define V_B ((int)(-0.100 * YUV_ONE )) + +#define Y_RGB(R,G,B) (( Y_R * (R) + Y_G * (G) + Y_B * (B)) >> YUV_SHIFT) +#define U_RGB(R,G,B) ((( U_R * (R) + U_G * (G) + U_B * (B)) >> YUV_SHIFT) + 128) +#define V_RGB(R,G,B) ((( V_R * (R) + V_G * (G) + V_B * (B)) >> YUV_SHIFT) + 128) + +static unsigned char __attribute_used__ CLEARX[8] = { 255, 0, 255, 0, 255, 0, 255, 0 }; +static short __attribute_used__ ZEROSX[4] = { 0, 0, 0, 0 }; + +static short __attribute_used__ OFFSETDX[4] = { 0, 64, 0, 64 }; +static short __attribute_used__ OFFSETWX[4] = { 128, 0, 128, 0 }; +static short __attribute_used__ OFFSETBX[4] = { 128, 128, 128, 128 }; + +static short __attribute_used__ YR0GRX[4] = { Y_R, Y_G, 0, Y_R }; +static short __attribute_used__ YBG0BX[4] = { Y_B, 0, Y_G, Y_B }; + +static short __attribute_used__ UR0GRX[4] = { U_R, U_G, 0, U_R }; +static short __attribute_used__ UBG0BX[4] = { U_B, 0, U_G, U_B }; + +static short __attribute_used__ VR0GRX[4] = { V_R, V_G, 0, V_R }; +static short __attribute_used__ VBG0BX[4] = { V_B, 0, V_G, V_B }; + +#endif diff --git a/mpeglib/lib/util/render/imageBase.cpp b/mpeglib/lib/util/render/imageBase.cpp new file mode 100644 index 00000000..040486ea --- /dev/null +++ b/mpeglib/lib/util/render/imageBase.cpp @@ -0,0 +1,76 @@ +/* + base clase for X11 images (stores important parameters and dither pic) + 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 "imageBase.h" + +#include <iostream> + +using namespace std; + +ImageBase::ImageBase() { + identifier = NULL; +} + + +ImageBase::~ImageBase() { + if (identifier != NULL) + delete [] identifier; +} + +void ImageBase::init(XWindow* xWindow, YUVPicture*) +{ + cout << "direct virtual call: ImageBase::init "<<endl; +} + +int ImageBase::support() { + cout << "direct virtual call: ImageBase::support "<<endl; + return false; +} + +int ImageBase::openImage(int) { + cout << "direct virtual call: ImageBase::openImage "<<endl; + return false; +} + + +int ImageBase::closeImage(){ + cout << "direct virtual call: ImageBase::closeImage "<<endl; + return false; +} + +void ImageBase::ditherImage(YUVPicture*) { + cout << "direct virtual call: ImageBase::ditherImage "<<endl; +} + + +void ImageBase::putImage() { + cout << "direct virtual call: ImageBase::putImage "<<endl; +} + +void ImageBase::putImage(int ,int ) { + cout << "direct virtual call: ImageBase::putImage(w,h) "<<endl; +} + +void ImageBase::setIdentifier(const char *id) +{ + if (identifier != NULL) + delete [] identifier; + + identifier = new char [strlen(id) + 1]; + strcpy(identifier, id); +} + +char *ImageBase::getIdentifier() +{ + return identifier; +} diff --git a/mpeglib/lib/util/render/imageBase.h b/mpeglib/lib/util/render/imageBase.h new file mode 100644 index 00000000..e1f7ae8c --- /dev/null +++ b/mpeglib/lib/util/render/imageBase.h @@ -0,0 +1,140 @@ +/* + base clase for X11 images (stores important parameters and dither pic) + 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 __IMAGEBASE_H +#define __IMAGEBASE_H + + +#include <stdio.h> + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + + +#include "yuvPicture.h" +#include "dither/ditherWrapper.h" + + + +#define _IMAGE_NONE 0 +#define _IMAGE_DESK 1 +#define _IMAGE_FULL 2 +#define _IMAGE_DOUBLE 4 +#define _IMAGE_RESIZE 8 +#define _IMAGE_DISABLED 16 + + +#define HAS_DESK(image) ((((image)->supportedModes) & _IMAGE_DESK) > 0) +#define HAS_FULL(image) ((((image)->supportedModes) & _IMAGE_FULL) > 0) +#define HAS_DOUBLE(image) ((((image)->supportedModes) & _IMAGE_DOUBLE) > 0) +#define HAS_RESIZE(image) ((((image)->supportedModes) & _IMAGE_RESIZE) > 0) +#define IS_DISABLED(image) ((((image)->supportedModes) & _IMAGE_DISABLED) > 0) + +#define IS_DESK(mode) (((mode) & _IMAGE_DESK) > 0) +#define IS_FULL(mode) (((mode) & _IMAGE_FULL) > 0) +#define IS_DOUBLE(mode) (((mode) & _IMAGE_DOUBLE) > 0) +#define IS_RESIZEABLE(mode) (((mode) & _IMAGE_RESIZE) > 0) + + +/** + This class creates from a given X11 Window a special image to + display. + An image has some characteristics, like startadress, width height, + if each row has a terminating modifier etc... + + The image is resposible for the conversion from the yuv + format to the destination. + + It is initialized with the constructed x11Window. + During a mode-switch (which is handled by x11window) the following + sequence is called: + + support() ->true/false if this image type is supported + (switching to it is allowed) + + openImage() called once when we switch to this + image type + + ditherImage(..) for the conversion from yuv->rgb + obviously called for every image + putImage(..) time for display it + + closeImage() called once, when we leave this image type + + + This sequence is necessary, because the user likey to switch + form desktop display to dga fullscreen. + + The following image classes seems to be useful: + + imageDeskX11 : standard ximage, maybe with shared mem support + full software rendering + imageDeskXV : image with hardware yuv->rgb rendering + + imageDGAFull : dga 2.0 full software rendering (needs root) + imageXVFull : fullscreen hardware yuv->rgb rendering + + The hierarchy is as follows: + + (desk mode) + imageStdX11 : fallback, should work everywhere + imageStdXV : if supported imageStdX11 is disabled + + (fullscreen mode) + imageDGAFull : + imageXVFull : + + The supported switches between the modes are + + + desktop <-> fullscreen mode. + + +*/ + + +class XWindow; + +class ImageBase { + private: + char *identifier; + + public: + unsigned int supportedModes; + + public: + ImageBase(); + virtual ~ImageBase(); + + virtual void init(XWindow* xWindow, YUVPicture* pic = NULL); + + virtual int support(); + + virtual int openImage(int imageMode); + virtual int closeImage(); + + virtual void ditherImage(YUVPicture* pic); + virtual void putImage(); + virtual void putImage(int w,int h); + + virtual int active() { return true; } + + void setIdentifier(const char *id); + char *getIdentifier(); + +}; + +#endif + diff --git a/mpeglib/lib/util/render/pictureArray.cpp b/mpeglib/lib/util/render/pictureArray.cpp new file mode 100644 index 00000000..71381ea0 --- /dev/null +++ b/mpeglib/lib/util/render/pictureArray.cpp @@ -0,0 +1,101 @@ +/* + nice try of an X11 output 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 "pictureArray.h" + + + +PictureArray::PictureArray(int width, int height) { + int i; + pictureCallback=NULL; + imageType=PICTURE_NO_TYPE; + + for (i=0;i<_PICTURE_ARRAY_SIZE;i++) { + pictureArray[i]=new YUVPicture(width,height); + imageType=pictureArray[i]->getImageType(); + } + + /* Find a pict image structure in ring buffer not currently locked. */ + /* Set current pict image structure to the one just found in ring. */ + + current=pictureArray[0]; + past=pictureArray[1]; + future=pictureArray[2]; + + picPerSec=0.0; + this->width=width; + this->height=height; + +} + + +PictureArray::~PictureArray() { + int i; + for (i=0;i<_PICTURE_ARRAY_SIZE;i++) { + if (pictureArray[i] != NULL) { + delete pictureArray[i]; + pictureArray[i]=NULL; + } + + } +} + + + + + +void PictureArray::setPicturePerSecond(double val) { + picPerSec=val; +} + + +double PictureArray::getPicturePerSecond() { + return picPerSec; +} + + + + +void PictureArray::forward() { + /* Update past and future references if needed. */ + + YUVPicture* tmp=past; + + past = future; + future = current; + current = tmp; + + +} + + + + +YUVPicture* PictureArray::getYUVPictureCallback() { + return pictureCallback; +} + + +void PictureArray::setYUVPictureCallback(YUVPicture* pic) { + this->pictureCallback=pic; +} + + +void PictureArray::setImageType(int imageType) { + int i; + this->imageType=imageType; + for (i=0;i<_PICTURE_ARRAY_SIZE;i++) { + pictureArray[i]->setImageType(imageType); + } +} + diff --git a/mpeglib/lib/util/render/pictureArray.h b/mpeglib/lib/util/render/pictureArray.h new file mode 100644 index 00000000..6a7e731c --- /dev/null +++ b/mpeglib/lib/util/render/pictureArray.h @@ -0,0 +1,76 @@ +/* + nice try of an X11 output 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 __VIDEOOUTPUTX11_H +#define __VIDEOOUTPUTX11_H + + +#include "yuvPicture.h" +#include <stdlib.h> + +#define _PICTURE_ARRAY_SIZE 5 + +class PictureArray { + + class YUVPicture* pictureArray[_PICTURE_ARRAY_SIZE]; + + class YUVPicture* past; /* Past predictive frame. */ + class YUVPicture* future; /* Future predictive frame. */ + class YUVPicture* current; /* Current frame. */ + + double picPerSec; + int width; + int height; + + int imageType; + + public: + PictureArray(int width, int height); + ~PictureArray(); + + inline YUVPicture* getPast() {return past;} + inline YUVPicture* getFuture() {return future;} + inline YUVPicture* getCurrent() {return current;} + + + inline void setPast(YUVPicture* pic) {past=pic;} + inline void setFuture(YUVPicture* pic) {future=pic;} + inline void setCurrent(YUVPicture* pic) {current=pic;} + inline int getWidth() { return width; } + inline int getWidth_Half() { return width/2; } + + // attention with these! + // these are shares pointer + // only call after mpegVidRsrc and then set them back to NULL + YUVPicture* getYUVPictureCallback(); + void setYUVPictureCallback(YUVPicture* pic); + + + void forward(); + + void setPicturePerSecond(double val); + double getPicturePerSecond(); + + // use these to swap the yuv Mode + inline int getImageType() { return imageType; } + void setImageType(int mode); + + + private: + YUVPicture* pictureCallback; + + +}; +#endif + diff --git a/mpeglib/lib/util/render/renderMachine.cpp b/mpeglib/lib/util/render/renderMachine.cpp new file mode 100644 index 00000000..c6327930 --- /dev/null +++ b/mpeglib/lib/util/render/renderMachine.cpp @@ -0,0 +1,205 @@ + /* + puts the yuv images onto a surface + 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 "renderMachine.h" + +#include <iostream> + +using namespace std; + + +RenderMachine::RenderMachine() { + +#ifndef SDL_WRAPPER + surface=new X11Surface(); +#endif +#ifdef SDL_WRAPPER + surface=new SDLSurface(); +#endif + + + pictureArray=NULL; + + startTime=new TimeStamp(); + endTime=new TimeStamp(); + + initialMode = _IMAGE_DESK; +} + + +RenderMachine::~RenderMachine() { + + + closeWindow(); + delete surface; + + delete startTime; + delete endTime; + +} + + + + + + +void RenderMachine::waitRestTime() { + endTime->gettimeofday(); + startTime->minus(endTime,endTime); + endTime->waitForIt(); + +} + +int RenderMachine::x11WindowId() +{ + return surface->x11WindowId(); +} + + +int RenderMachine::openWindow(int width, + int height,const char *title) { +if (surface->open(width,height,title)) { + pictureArray=new PictureArray(width, height); + + return switchToMode(initialMode); + } + return false; +} + + +void RenderMachine::closeWindow() { + + if (surface->isOpen()==false) { + return; + } + if (pictureArray != NULL) { + delete pictureArray; + pictureArray=NULL; + } + surface->close(); +} + +/** + important method. This is our only way to switch from + fullscreen back to the desktop screen. + This method is called if the video end (normal or by user request) + We dont have a callback, thus after the image stops, we would + never get events. +*/ +void RenderMachine::flushWindow() { + + // we always switch back to desk mode. + if (IS_FULL(surface->getImageMode())) { + switchToMode(surface->getImageMode() ^ _IMAGE_DESK ^ _IMAGE_FULL); + } + + +} + + + + +void RenderMachine::putImage(YUVPicture* pic, + TimeStamp* waitTime, + TimeStamp* ) { + if (pic == NULL) { + cout << "pic is null"<<endl; + return; + } + startTime->gettimeofday(); + startTime->addOffset(waitTime); + + // need dither? + surface->dither(pic); + + int nextMode; + if (surface->checkEvent(&nextMode) == true) { + switchToMode(nextMode); + } + surface->putImage(pic); + waitRestTime(); +} + + +int RenderMachine::switchToMode(int mode) { + if (surface->getImageMode() != mode) { + surface->closeImage(); + if (mode != _IMAGE_NONE) { + surface->openImage(mode); + } + + else { + cout << "no imageMode, no open, that's life"<<endl; + return false; + } + } + return true; +} + + + +PictureArray* RenderMachine::lockPictureArray() { + return pictureArray; +} + + +void RenderMachine::unlockPictureArray(PictureArray* pictureArray) { + + // chance to switch mode + + + // put picture out + if (surface->getImageMode() != _IMAGE_NONE) { + YUVPicture* pic=pictureArray->getYUVPictureCallback(); + if (pic != NULL) { + TimeStamp* waitTime=pic->getWaitTime(); + TimeStamp* earlyTime=pic->getEarlyTime(); + putImage(pic,waitTime,earlyTime); + } + } else { + cout << "no mode selected"<<endl; + } +} + + +void RenderMachine::config(const char* key, + const char* value,void* user_data) { + if (strcmp(key,"getDepth")==0) { + int* val=(int*)user_data; + *val=surface->getDepth(); + } + if (surface != NULL) { + int mode = surface->getImageMode(); + if (strcmp(key,"toggleFullscreen")==0) { + if (surface->findImage(mode ^ _IMAGE_FULL) != NULL) { + if (surface->isOpen()) + switchToMode(mode ^ _IMAGE_FULL); + else + initialMode = _IMAGE_FULL; + } + } + if (strcmp(key,"toggleDouble")==0) { + if (surface->findImage(mode ^ _IMAGE_DOUBLE) != NULL) { + if (surface->isOpen()) + switchToMode(mode ^ _IMAGE_DOUBLE); + else + initialMode = _IMAGE_DOUBLE; + } + } + } + + surface->config(key,value,user_data); +} + + + diff --git a/mpeglib/lib/util/render/renderMachine.h b/mpeglib/lib/util/render/renderMachine.h new file mode 100644 index 00000000..728a6740 --- /dev/null +++ b/mpeglib/lib/util/render/renderMachine.h @@ -0,0 +1,90 @@ +/* + puts the yuv images onto a surface + 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 __RENDERMACHINE_H +#define __RENDERMACHINE_H + + + + +/** + RenderMachine. We still have the problem, because of performance, + that we cannot have a yuv picture format in the decoder + and one in the output to x11. they must be shared. + XV support then directly works on them and SDL images + can be exported to the decoder as well. + + Another point is : mode switch. User want desktop->fullscreen switch. + Due to the threaded nature, we must have a single synchronization + point, when we know that the decoder currently does _not_ decode + so that we can switch the imaged and free the memory. + + Some points are currently unclear, for example how to handle + applications, which want to redirect the image into their own + buffers, but hey, there are that many classes and layers + I really think it should be doable somehow + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef SDL_WRAPPER +#include "x11/x11Surface.h" +#endif + +#ifdef SDL_WRAPPER +#include "sdl/sdlSurface.h" +#endif + +#include "pictureArray.h" +#include "../abstract/abs_thread.h" + +class RenderMachine { + + + Surface* surface; + PictureArray* pictureArray; + + + TimeStamp* startTime; + TimeStamp* endTime; + + int initialMode; + + public: + RenderMachine(); + ~RenderMachine(); + + int openWindow(int width, int height,const char *title); + int x11WindowId(); + void closeWindow(); + void flushWindow(); + + + PictureArray* lockPictureArray(); + void unlockPictureArray(PictureArray* pictureArray); + + void config(const char* key, const char* value,void* user_data); + + private: + void waitRestTime(); + void putImage(YUVPicture* pic,TimeStamp* waitTime,TimeStamp* earlyTime); + + int switchToMode(int mode); + +}; +#endif diff --git a/mpeglib/lib/util/render/sdl/Makefile.am b/mpeglib/lib/util/render/sdl/Makefile.am new file mode 100644 index 00000000..1a4b85eb --- /dev/null +++ b/mpeglib/lib/util/render/sdl/Makefile.am @@ -0,0 +1,43 @@ +# player - Makefile.am + +INCLUDES = $(all_includes) + + +noinst_LTLIBRARIES = libutilsdl.la + +noinst_HEADERS = imageDeskSDL.h sdlSurface.h + +libutilsdl_la_SOURCES = imageDeskSDL.cpp sdlSurface.cpp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mpeglib/lib/util/render/sdl/imageDeskSDL.cpp b/mpeglib/lib/util/render/sdl/imageDeskSDL.cpp new file mode 100644 index 00000000..b1ff9a7c --- /dev/null +++ b/mpeglib/lib/util/render/sdl/imageDeskSDL.cpp @@ -0,0 +1,110 @@ +/* + SDL surface output + 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 "imageDeskSDL.h" + +#ifdef SDL_WRAPPER + + +ImageDeskSDL::ImageDeskSDL() { + + this->surface=NULL; + this->rect=NULL; + imageMode=_IMAGE_NONE; + lSupport=true; + image=NULL; +} + + +ImageDeskSDL::~ImageDeskSDL() { + closeImage(); + cout << "SDL destry needed"<<endl; +} + + + +int ImageDeskSDL::support() { + return lSupport; +} + + +void ImageDeskSDL::init(XWindow* xWindow, YUVPicture* pic) { + cout << "ImageDeskSDL::init"<<endl; + this->surface=(SDL_Surface*)xWindow; + this->rect=(SDL_Rect*)pic; +} + +int ImageDeskSDL::openImage(int imageMode) { + int w=rect->w; + int h=rect->h; + this->imageMode=imageMode; + /* Create a YV12 image (Y + V + U) */ + cout << "CreateYUVOverlay -s"<<imageMode<<" w:"<<w<<" h:"<<h<<endl; + image = SDL_CreateYUVOverlay(w,h, + SDL_YV12_OVERLAY, + surface); + if (image == NULL) { + cout << "error creating image"<<endl; + exit(0); + } + cout << "CreateYUVOverlay -e"<<endl; + return true; +} + + +int ImageDeskSDL::closeImage() { + if (image != NULL) { + cout << "FreeYUVOverlay -s"<<endl; + SDL_FreeYUVOverlay(image); + // otherwise test of NULL will fail + image = NULL; + cout << "FreeYUVOverlay -e"<<endl; + } + return true; +} + + + +void ImageDeskSDL::ditherImage(YUVPicture* pic) { + + int w=pic->getWidth(); + int h=pic->getHeight(); + int size=w*h+(w*h)/2; + SDL_LockYUVOverlay(image); + memcpy(*((char**)image->pixels),pic->getLuminancePtr(),size); + SDL_UnlockYUVOverlay(image); + +} + + +void ImageDeskSDL::putImage(int w, int h) { + SDL_Rect dest; + dest.x=0; + dest.y=0; + dest.w=rect->w; + dest.h=rect->h; + if (imageMode & _IMAGE_RESIZE) { + dest.w = w; + dest.h = h; + } + + if (imageMode & _IMAGE_DOUBLE) { + dest.w*=2; + dest.h*=2; + } + SDL_DisplayYUVOverlay(image,&dest); + +} + +#endif + diff --git a/mpeglib/lib/util/render/sdl/imageDeskSDL.h b/mpeglib/lib/util/render/sdl/imageDeskSDL.h new file mode 100644 index 00000000..1bccb94a --- /dev/null +++ b/mpeglib/lib/util/render/sdl/imageDeskSDL.h @@ -0,0 +1,65 @@ +/* + SDL surface output + 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 __IMAGEDESKSDL_H +#define __IMAGEDESKSDL_H + +#include "../imageBase.h" + + + +#ifndef SDL_WRAPPER + class ImageDeskSDL : public ImageBase { + }; +#endif + +#ifdef SDL_WRAPPER + +#if defined WIN32 +#include <SDL.h> +#include <SDL_video.h> +#else +#include <SDL/SDL.h> +#include <SDL/SDL_video.h> +#endif + +class ImageDeskSDL : public ImageBase { + + int lSupport; + SDL_Overlay *image; + + SDL_Surface* surface; + SDL_Rect* rect; + int imageMode; + + public: + ImageDeskSDL(); + ~ImageDeskSDL(); + + int support(); + void init(XWindow* xWindow, YUVPicture* pic=NULL); + + + int openImage(int imageMode); + int closeImage(); + + void ditherImage(YUVPicture* pic); + + void putImage(int w, int h); + + + +}; +#endif + +#endif diff --git a/mpeglib/lib/util/render/sdl/sdlSurface.cpp b/mpeglib/lib/util/render/sdl/sdlSurface.cpp new file mode 100644 index 00000000..86ef41bb --- /dev/null +++ b/mpeglib/lib/util/render/sdl/sdlSurface.cpp @@ -0,0 +1,219 @@ +/* + surface wrapper for SDL + 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 "sdlSurface.h" + + +#ifdef SDL_WRAPPER + + +SDLSurface::SDLSurface() { + surface=NULL; + lOpen=false; + imageMode=_IMAGE_NONE; + lSDLInit=false; + imageDeskSDL=new ImageDeskSDL(); +} + + +SDLSurface::~SDLSurface() { + close(); + if (imageCurrent != NULL) { + imageCurrent->closeImage(); + delete imageCurrent; + // otherwise test of NULL will fail + imageCurrent = NULL; + } +} + + +int SDLSurface::isOpen() { + return lOpen; +} + +int SDLSurface::getImageMode() { + return imageMode; +} + +int SDLSurface::open(int width, int height,const char *title,bool border) { + cout << "SDL openImage:"<<title<<endl; + + sdlinit(); + + rect.x = 0; + rect.y = 0; + rect.w = width; + rect.h = height; + + return true; +} + + +int SDLSurface::close() { + if (isOpen()==false) { + cout << "WindowOut::closeWindow already closed"<<endl; + return true; + } + if(surface) { + SDL_FreeSurface(surface); + surface = NULL; + } + + lOpen=false; + return true; +} + + +int SDLSurface::getHeight() { + return rect.h; +} + + +int SDLSurface::getWidth() { + return rect.w; +} + + +int SDLSurface::getDepth() { + return video_bpp; +} + +int SDLSurface::putImage(YUVPicture* ) { + return true; +} + + +int SDLSurface::openImage(int imageMode, YUVPicture* pic) { + if (this->imageMode != _IMAGE_NONE) { + cout << "bad open error X11Surface::openImage"<<endl; + exit(0); + } + cout << "************* openImage SDL"<<imageMode<<endl; + this->imageMode=imageMode; + imageCurrent=NULL; + int w=getWidth(); + int h=getHeight(); + if(imageMode & _IMAGE_RESIZE) { + w=resize_rect.w; + h=resize_rect.h; + } + + if (imageMode & _IMAGE_DOUBLE) { + w=rect.w*2; + h=rect.h*2; + } + + if (imageMode & _IMAGE_DESK) { + if (imageDeskSDL->support()) { + imageCurrent=imageDeskSDL; + int video_flags = SDL_SWSURFACE; + video_flags |= SDL_ASYNCBLIT; + video_flags |= SDL_RESIZABLE; + if(surface) + SDL_FreeSurface(surface); + surface = SDL_SetVideoMode(w, h, video_bpp, video_flags); + + } + } + if (imageMode & _IMAGE_FULL) { + if (imageDeskSDL->support()) { + imageCurrent=imageDeskSDL; + int video_flags = SDL_FULLSCREEN; + video_flags |= SDL_ASYNCBLIT; + video_flags |= SDL_HWSURFACE; + if(surface) + SDL_FreeSurface(surface); + surface = SDL_SetVideoMode(w, h, video_bpp, video_flags); + } + } + if (imageCurrent != NULL) { + cout << "surface:"<<surface<<endl; + imageCurrent->init((XWindow*)surface,(YUVPicture*)&rect); + imageCurrent->openImage(imageMode); + } + return (imageCurrent != NULL); +} + + +int SDLSurface::closeImage() { + this->imageMode = _IMAGE_NONE; + if (imageCurrent != NULL) { + imageCurrent->closeImage(); + } + imageCurrent=NULL; + return true; +} + +int SDLSurface::checkEvent(int* newMode) { + int back=false; + SDL_Event event; + SDL_PollEvent(&event); + switch (event.type) { + case SDL_MOUSEBUTTONDOWN: { + int button=event.button.button; + if (button == 1) { + *newMode = imageMode ^ _IMAGE_DOUBLE; + back=true; + } + if (button == 3) { + *newMode = imageMode ^ _IMAGE_DESK ^ _IMAGE_FULL; + back=true; + } + break; + } + case SDL_VIDEORESIZE : { + resize_rect.w = event.resize.w; + resize_rect.h = event.resize.h; + *newMode = imageMode | _IMAGE_RESIZE; + back = true; + break; + } + + } + return back; +} + +int SDLSurface::dither(YUVPicture* pic) { + if (imageCurrent != NULL) { + imageCurrent->ditherImage(pic); + if(imageMode & _IMAGE_RESIZE) { + imageCurrent->putImage(resize_rect.w, resize_rect.h); + } else { + imageCurrent->putImage(rect.w, rect.h); + } + } + return true; +} + +void SDLSurface::sdlinit() { + if (lSDLInit == false) { + if (SDL_Init(SDL_INIT_VIDEO) < 0 ) { + fprintf(stderr, "Warning: Couldn't init SDL video: %s\n", + SDL_GetError()); + fprintf(stderr, "Will ignore video stream\n"); + exit(0); + } + atexit(SDL_Quit); + cout << "****************** SDL VIDEO System **********"<<endl; + /* Get the "native" video mode */ + video_info=SDL_GetVideoInfo(); + video_bpp=video_info->vfmt->BitsPerPixel; + imageMode=_IMAGE_NONE; + + imageCurrent=NULL; + } + lSDLInit=true; +} + +#endif diff --git a/mpeglib/lib/util/render/sdl/sdlSurface.h b/mpeglib/lib/util/render/sdl/sdlSurface.h new file mode 100644 index 00000000..aca5f293 --- /dev/null +++ b/mpeglib/lib/util/render/sdl/sdlSurface.h @@ -0,0 +1,78 @@ +/* + surface wrapper for SDL + 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 __SDLSURFACE_H +#define __SDLSURFACE_H + + +#include "../surface.h" +#include "imageDeskSDL.h" + + + +#ifndef SDL_WRAPPER + class SDLSurface : public Surface { + }; +#endif + +#ifdef SDL_WRAPPER +#if defined WIN32 +#include <SDL.h> +#include <SDL_video.h> +#else +#include <SDL/SDL.h> +#include <SDL/SDL_video.h> +#endif + + +class SDLSurface : public Surface { + + int lOpen; + int imageMode; + int lSDLInit; + int video_bpp; + SDL_Surface* surface; + SDL_Rect rect; + SDL_Rect resize_rect; + const SDL_VideoInfo *video_info; + + ImageBase* imageCurrent; + + ImageDeskSDL* imageDeskSDL; + + public: + SDLSurface(); + ~SDLSurface(); + + int isOpen(); + int open(int width, int height,const char *title, bool border=false); + int close(); + int getHeight(); + int getWidth(); + int getDepth(); + int getImageMode(); + int checkEvent(int* mode); + + int openImage(int imageMode, YUVPicture* pic = NULL); + int closeImage(); + int dither(YUVPicture* pic); + int putImage(YUVPicture* pic); + + + private: + void sdlinit(); +}; +#endif + +#endif diff --git a/mpeglib/lib/util/render/surface.cpp b/mpeglib/lib/util/render/surface.cpp new file mode 100644 index 00000000..12a15410 --- /dev/null +++ b/mpeglib/lib/util/render/surface.cpp @@ -0,0 +1,117 @@ +/* + surface base class + 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 "surface.h" + +#include <iostream> + +using namespace std; + +Surface::Surface() { +} + + +Surface::~Surface() { +} + + +int Surface::isOpen() { + cout << "direct virtual call Surface::isOpen "<<endl; + return false; +} + + +int Surface::open(int width, int height,const char *title, bool border) { + cout << "direct virtual call Surface::open "<<endl; + cout << "width:"<<width<<" height:"<<height + << " title:"<<title<<endl; + return false; +} + + +int Surface::close() { + cout << "direct virtual call Surface::close "<<endl; + return true; +} + + +int Surface::getHeight() { + cout << "direct virtual call Surface::getHeight "<<endl; + return 0; +} + + +int Surface::getWidth() { + cout << "direct virtual call Surface::getWidth "<<endl; + return 0; +} + + +int Surface::getDepth() { + cout << "direct virtual call Surface::getDepth "<<endl; + return 0; +} + +int Surface::getImageMode() { + cout << "direct virtual call Surface::getImageMode "<<endl; + return 0; +} + +int Surface::x11WindowId() { + cout << "direct virtual call Surface::x11WindowId " << endl; + return -1; +} + +ImageBase *Surface::findImage(int) +{ + cout << "direct virtual call: Surface::findImage "<<endl; + return NULL; +} + +int Surface::openImage(int mode, YUVPicture*) { + cout << "direct virtual call Surface::openImage "<<endl; + cout << "imageMode:"<<mode<<endl; + return false; +} + + +int Surface::closeImage() { + cout << "direct virtual call Surface::closeImage "<<endl; + return true; +} + + +int Surface::dither(YUVPicture* pic) { + cout << "direct virtual call Surface::dither "<<endl; + pic->print("Surface::dither"); + return false; +} + + +int Surface::putImage(YUVPicture* pic) { + cout << "direct virtual call Surface::putImage "<<endl; + pic->print("Surface::putImage"); + return false; +} + +int Surface::checkEvent(int*) { + cout << "direct virtual call Surface::checkEvent "<<endl; + return false; +} + +void Surface::config(const char* , + const char* ,void* ) { + cout << "direct virtual call Surface::config"<<endl; +} + diff --git a/mpeglib/lib/util/render/surface.h b/mpeglib/lib/util/render/surface.h new file mode 100644 index 00000000..84de996a --- /dev/null +++ b/mpeglib/lib/util/render/surface.h @@ -0,0 +1,55 @@ +/* + surface base class + 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 __SURFACE_H +#define __SURFACE_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "yuvPicture.h" + +class ImageBase; + +class Surface { + + public: + Surface(); + virtual ~Surface(); + + virtual int isOpen(); + virtual int open(int width, int height,const char *title, bool border=false); + virtual int close(); + virtual int getHeight(); + virtual int getWidth(); + virtual int getDepth(); + virtual int getImageMode(); + virtual int x11WindowId(); + + virtual ImageBase *findImage(int imageMode); + + virtual int openImage(int mode, YUVPicture* pic = NULL); + virtual int closeImage(); + virtual int dither(YUVPicture* pic); + virtual int putImage(YUVPicture* pic); + + virtual int checkEvent(int* mode); + + // config surface + virtual void config(const char* key, + const char* value,void* user_data); + + +}; +#endif diff --git a/mpeglib/lib/util/render/x11/Makefile.am b/mpeglib/lib/util/render/x11/Makefile.am new file mode 100644 index 00000000..97ab0d67 --- /dev/null +++ b/mpeglib/lib/util/render/x11/Makefile.am @@ -0,0 +1,48 @@ +# player - Makefile.am + +INCLUDES = $(all_includes) + + +noinst_LTLIBRARIES = libutilx11.la + + +noinst_HEADERS = initDisplay.h \ + imageDeskX11.h imageDGAFull.h \ + imageXVDesk.h x11Surface.h xinit.h + +libutilx11_la_SOURCES = initDisplay.cpp \ + imageDeskX11.cpp \ + imageDGAFull.cpp imageXVDesk.cpp \ + x11Surface.cpp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mpeglib/lib/util/render/x11/imageDGAFull.cpp b/mpeglib/lib/util/render/x11/imageDGAFull.cpp new file mode 100644 index 00000000..6e07b658 --- /dev/null +++ b/mpeglib/lib/util/render/x11/imageDGAFull.cpp @@ -0,0 +1,289 @@ +/* + xfree 4.0 dga fullscreen mode + Copyright (C) 2000 Martin Vogt, Christian Gerlach + + 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 "imageDGAFull.h" + +#include <iostream> + +using namespace std; + +ImageDGAFull::ImageDGAFull() { + + m_iMode = -1; + m_bIsActive = false; + lSupport=false; + m_pxWindow = NULL; + m_iImageMode = _IMAGE_NONE; + ditherWrapper=NULL; + supportedModes = _IMAGE_NONE; + setIdentifier("DGA"); +} + + +ImageDGAFull::~ImageDGAFull() { + if (ditherWrapper != NULL) { + delete ditherWrapper; + } +} + +void ImageDGAFull::init(XWindow *xWindow, YUVPicture*) +{ + int uid; + + m_pxWindow = xWindow; + if (ditherWrapper == NULL) { + ditherWrapper=new DitherWrapper(xWindow->depth, + xWindow->redMask, + xWindow->greenMask, + xWindow->blueMask, + xWindow->pixel); + } + +#ifndef X11_DGA2 + return; +#endif + +#ifdef X11_DGA2 + m_pDGAModes=NULL; + m_iNumberModes = 0; + + m_iVideoWidth = xWindow->width; + m_iVideoHeight = xWindow->height; + uid=getuid(); + if (uid != 0) { + //cout << "you are :"<<uid<<" and not root(0). DGA 2.0 needs root"<<endl; + return; + } + + if ((m_pDisplay =xWindow->display)==NULL ) { + fprintf( stderr, " cannot connect to X server %s\n", XDisplayName(NULL)); + return; + } + + m_iScreen = DefaultScreen(xWindow->display); + + + if (!XF86DGAQueryVersion(xWindow->display, + &m_iMajorVersion, &m_iMinorVersion)) { + fprintf(stderr, "Unable to query video extension version\n"); + return ; + } + printf("DGA version %d.%d detected!\n", m_iMajorVersion, m_iMinorVersion); + + // Fail if the extension version in the server is too old + if (m_iMajorVersion < DGA_MINMAJOR || + (m_iMajorVersion == DGA_MINMAJOR && m_iMinorVersion < DGA_MINMINOR)) { + fprintf(stderr, "Xserver is running an old XFree86-DGA version" + " (%d.%d)\n", m_iMajorVersion, m_iMinorVersion); + fprintf(stderr, "Minimum required version is %d.%d\n", + DGA_MINMAJOR, DGA_MINMINOR); + return ; + } + + if (!XF86DGAQueryExtension(m_pDisplay, &m_iEventBase, &m_iErrorBase)) { + fprintf(stderr, "Unable to query video extension information\n"); + return ; + } + printf("Event base %d\n", m_iEventBase); + printf("Error base %d\n", m_iErrorBase); + + lSupport=true; + supportedModes = _IMAGE_FULL; +#endif +} + +int ImageDGAFull::support() { + return lSupport; +} + + +int ImageDGAFull::openImage(int mode) { +#ifdef X11_DGA2 + int width, bank, ram; + m_bAllowZoom = IS_DOUBLE(mode); + m_iImageMode = mode; + + /* Open access to the framebuffer */ + if ( ! XDGAOpenFramebuffer(m_pDisplay,m_iScreen) ) { + return(false); + } + + findMode(m_pxWindow->width, m_pxWindow->height, m_pxWindow->depth); + m_pDevice = XDGASetMode(m_pDisplay, m_iScreen, m_pDGAModes[m_iMode].num); + + + XDGASelectInput(m_pDisplay, m_iScreen, + KeyPressMask | ButtonPressMask | PointerMotionMask); + + XF86DGAGetVideo(m_pDisplay,m_iScreen,&m_pAddr,&width,&bank,&ram); + + + if(bank < (ram * 1024)) { + XF86DGASetVidPage(m_pxWindow->display, + DefaultScreen(m_pxWindow->display), 0); + } + + XF86DGASetViewPort(m_pxWindow->display, + DefaultScreen(m_pxWindow->display),0,0); + + + printf("Offset:%8x\n",m_iOffsetScreen); + m_pStartAddr = m_pAddr + m_iOffsetScreen; + m_iOffsetLine = (m_iBytesPerLine - m_iBytesPerRow) / m_iBytesPerPixel; + cout << "LineOffset: " << m_iOffsetLine << endl; + + // Clear the screen + memset(m_pAddr, 0, m_iBytesPerLine * m_iScreenHeight); + /* char *pos = m_pStartAddr; + int end = (m_bZoom) ? 2*m_iVideoHeight : m_iVideoHeight; + for (int line=0 ; line<end ; line++) { + memset(pos, 80, m_iBytesPerRow); + pos += m_iBytesPerRow + m_iOffsetLine * m_iBytesPerPixel; + } + sleep(2);*/ + + m_bIsActive = true; +#endif + return true; +} + + +int ImageDGAFull::closeImage() { +#ifdef X11_DGA2 + m_bIsActive = false; + stop(); + + // delete resources + if (m_pDGAModes != NULL) { + delete m_pDGAModes; + m_pDGAModes=NULL; + } +#endif + return true; +} + + +unsigned char* ImageDGAFull::address() { + return (unsigned char*) m_pStartAddr; +} + + +int ImageDGAFull::offset() { + return m_iOffsetLine; +} + + +void ImageDGAFull::ditherImage(YUVPicture* pic) { + + int useMode = (m_bZoom) ? m_iImageMode : m_iImageMode & (!_IMAGE_DOUBLE); + + ditherWrapper->doDither(pic,m_pxWindow->depth,useMode, + address(),offset()); +} + + +void ImageDGAFull::putImage() { + + if (event()) + closeImage(); +} + + +int ImageDGAFull::findMode(int width, int height, int bpp) { +#ifdef X11_DGA2 + int minBorder = INT_MAX; + int yBorder=0; + int border; + + // TODO: also check the y-axis + + m_iMode = -1; + m_iNumberModes = 0; + m_pDGAModes = XDGAQueryModes(m_pDisplay, m_iScreen, &m_iNumberModes); + printf("Number modes: %d\n", m_iNumberModes); + + for (int count=0 ; count<m_iNumberModes ; count++) { + + + if (m_pDGAModes[count].depth != bpp) + continue; + + printf("Mode: %d %dx%d \t bpp %d\n", + count, + m_pDGAModes[count].viewportWidth, + m_pDGAModes[count].viewportHeight, + m_pDGAModes[count].bitsPerPixel); + + // test normal video + border = m_pDGAModes[count].viewportWidth - width; + if ((border >= 0) && (border < minBorder)) { + minBorder = border; + m_iMode = count; + m_bZoom = false; + yBorder = m_pDGAModes[count].viewportHeight - height; + } + + // test zoomed video + if (m_bAllowZoom) { + border = m_pDGAModes[count].viewportWidth - 2 * width; + if ((border >= 0) && (border < minBorder)) { + minBorder = border; + m_iMode = count; + m_bZoom = true; + yBorder = m_pDGAModes[count].viewportHeight-2*height; + } + } + } + + if (m_iMode != -1) { + m_iScreenWidth = m_pDGAModes[m_iMode].viewportWidth; + m_iScreenHeight = m_pDGAModes[m_iMode].viewportHeight; + + m_iBytesPerPixel = m_pDGAModes[m_iMode].bitsPerPixel / 8; + m_iBytesPerLine = m_pDGAModes[m_iMode].bytesPerScanline; + m_iBytesPerRow = width * m_iBytesPerPixel; + if (m_bZoom) { + m_iBytesPerRow += m_iBytesPerRow; + } + + m_iOffsetScreen = minBorder * (m_iBytesPerPixel / 2) + + (yBorder / 2) * m_iBytesPerLine; + } + + cout << "Best Mode: " << m_iMode << endl; + cout << "Border Size: " << minBorder / 2 << endl; + cout << "Zoom: " << m_bZoom << endl; + cout << "Bytes per Line: " << m_iBytesPerLine << endl; + cout << "Bytes per Row: " << m_iBytesPerRow << endl; + cout << "Bytes per Pixel:" << m_iBytesPerPixel << endl; + cout << "Total offset: " << m_iOffsetScreen << endl; +#endif + return (m_iMode != -1); +} + + + +int ImageDGAFull::event() { + XEvent event; + return XCheckTypedEvent(m_pDisplay, ButtonPress + m_iEventBase, &event); +} + +void ImageDGAFull::stop() { +#ifdef X11_DGA2 + m_bIsActive = false; + XF86DGADirectVideo(m_pDisplay, m_iScreen, 0); + + XUngrabPointer(m_pDisplay, CurrentTime); + XUngrabKeyboard(m_pDisplay, CurrentTime); +#endif +} diff --git a/mpeglib/lib/util/render/x11/imageDGAFull.h b/mpeglib/lib/util/render/x11/imageDGAFull.h new file mode 100644 index 00000000..ddb8f493 --- /dev/null +++ b/mpeglib/lib/util/render/x11/imageDGAFull.h @@ -0,0 +1,131 @@ +/* + xfree 4.0 dga fullscreen mode + Copyright (C) 2000 Martin Vogt, Christian Gerlach + + 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 __IMAGEDGAFULL_H +#define __IMAGEDGAFULL_H +#include "xinit.h" + +#include "../imageBase.h" + + + +#include <stdio.h> +#include <unistd.h> +#include <limits.h> +#include <sys/types.h> + + + + +#define DGA_MINMAJOR 2 +#define DGA_MINMINOR 0 + + + + +/** + + Displays and renders X11 images in software with the help + of the ditherWrapper class. It switches to xfree 4.0 dga 2.0 + and needs root priviliges for that + +*/ + + +class ImageDGAFull : public ImageBase { + + + XWindow* m_pxWindow; + + // DGA status + int m_iMajorVersion; + int m_iMinorVersion; + int m_iEventBase; + int m_iErrorBase; + + int m_iScreen; + + Display *m_pDisplay; + + int m_iNumberModes; + +#ifdef X11_DGA2 + XDGAMode *m_pDGAModes; + XDGADevice *m_pDevice; +#endif + + int m_iScreenWidth; + int m_iScreenHeight; + + char *m_pAddr; // Base address of the screen + + // DGA parameter + int m_iVideoWidth; + int m_iVideoHeight; + + int m_iBytesPerLine; + int m_iBytesPerRow; // Size of one image line + int m_iBytesPerPixel; + int m_iOffsetScreen; + int m_iOffsetLine; + char *m_pStartAddr; // Start address for a centered image + + int m_iImageMode; + int m_iMode; + bool m_bZoom; + bool m_bAllowZoom; + + bool m_bIsActive; + + int lSupport; + DitherWrapper* ditherWrapper; + + + public: + ImageDGAFull(); + ~ImageDGAFull(); + + void init(XWindow *xWindow, YUVPicture* pic = NULL); + + int support(); + + int openImage(int mode); + int closeImage(); + + void ditherImage(YUVPicture* pic); + void putImage(); + + int active() { return m_bIsActive; } + + private: + + // Tries to find a fullscreen-mode which matches the resolution best + int findMode(int width, int height, int bpp); + + // Returns TRUE if an event is waiting + int event(); + + // Returns the start address of the upper left corner of the video frame + unsigned char *address(); + + // Number of bytes from the end of a row to the beginning of next one + int offset(); + + // Disables DGA-View (performs a mode-switch if neccesary) + void stop(); + + + +}; + +#endif diff --git a/mpeglib/lib/util/render/x11/imageDeskX11.cpp b/mpeglib/lib/util/render/x11/imageDeskX11.cpp new file mode 100644 index 00000000..9607d749 --- /dev/null +++ b/mpeglib/lib/util/render/x11/imageDeskX11.cpp @@ -0,0 +1,439 @@ +/* + standard and shared mem X11 images + 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 "imageDeskX11.h" + +#include <iostream> + +using namespace std; + +static int lXerror; + +static int dummy(Display* , XErrorEvent*) { + lXerror=true; + return true; +} + + + +ImageDeskX11::ImageDeskX11() { + lSupport=true; + supportedModes = _IMAGE_DESK | _IMAGE_DOUBLE | _IMAGE_FULL; + setIdentifier("Standard X11"); + xWindow = NULL; + ditherWrapper=NULL; +#ifdef X11_XVIDMODE + iOldMode = -1; + vm_modelines = NULL; +#endif +} + + +ImageDeskX11::~ImageDeskX11() { + destroyImage(); + if (ditherWrapper != NULL) { + delete ditherWrapper; + } +} + + +void ImageDeskX11::init(XWindow* xWindow, YUVPicture*) +{ + videoaccesstype=VIDEO_XI_NONE; + this->xWindow=xWindow; + virtualscreen=NULL; + ximage=NULL; + imageMode=_IMAGE_NONE; + if (ditherWrapper == NULL) { + ditherWrapper=new DitherWrapper(xWindow->depth, + xWindow->redMask, + xWindow->greenMask, + xWindow->blueMask, + xWindow->pixel); + } + +#ifdef X11_SHARED_MEM + shmseginfo=NULL; +#endif +} + +int ImageDeskX11::support() { + return lSupport; +} + + +int ImageDeskX11::openImage(int mode) { + + if (xWindow == NULL) { + cout << "ImageDeskX11::openImage - call init before open!" << endl; + return false; + } + + closeImage(); + imageMode = mode; + int err; + + if ((err=createImage(VIDEO_XI_SHMSTD,imageMode)) != ERR_XI_OK) { + printf("\nX initialisation error:\n *** %s\n",ERR_XI_STR[err]); + printf("check ipcs and delete resources with ipcrm\n"); + if ((err=createImage(VIDEO_XI_STANDARD,imageMode)) != ERR_XI_OK) { + printf("\nX initialisation error:\n *** %s\n",ERR_XI_STR[err]); + videoaccesstype=VIDEO_XI_NONE; + } else { + lSupport=true; + } + } else { + lSupport=true; + } + switch(videoaccesstype) { + case VIDEO_XI_STANDARD: + //printf(" # using conventional Xlib calls.\n\n"); + break; + case VIDEO_XI_SHMSTD: + //printf(" # Using Xlib shared memory extension %d.%d\n\n", + //XShmMajor,XShmMinor); + break; + default: + cout << "could not create image->no video output possible"<<endl; + + } + + iOffsetX = iOffsetY = 0; + int w = xWindow->width; + int h = xWindow->height; + if (IS_FULL(imageMode)) { + switchMode(xWindow->width, xWindow->height, IS_DOUBLE(imageMode)); + iOffsetX = (iWidth - w) / 2; + iOffsetY = (iHeight - h) / 2; + if (bZoom) { + iOffsetX -= w / 2; + iOffsetY -= h / 2; + } + XResizeWindow(xWindow->display, xWindow->window, iWidth, iHeight); + } else if (IS_DOUBLE(imageMode)) { + XResizeWindow(xWindow->display, xWindow->window, + xWindow->width * 2, xWindow->height * 2); + } + + if (lSupport==true) { + return true; + } + return false; +} + + +int ImageDeskX11::closeImage() { + destroyImage(); + +#ifdef X11_XVIDMODE + if (iOldMode != -1) { + cout << "switch back to original videomode" << endl; + XF86VidModeSwitchToMode(xWindow->display,XDefaultScreen(xWindow->display), + vm_modelines[iOldMode]); + XFlush(xWindow->display); + iOldMode=-1; + } +#endif + + return true; +} + + +void ImageDeskX11::ditherImage(YUVPicture* pic) { + if (xWindow == NULL) { + cout << "ImageDeskX11::ditherImage - you have to call init first!" << endl; + return; + } + + ditherWrapper->doDither(pic,xWindow->depth,imageMode, + virtualscreen,0); +} + + +void ImageDeskX11::putImage(){ + if (xWindow == NULL) { + cout << "ImageDeskX11::putImage - you have to call init first!" << endl; + return; + } + + + int height=xWindow->height; + int width=xWindow->width; + + if (imageMode & _IMAGE_DOUBLE) { + height=2*height; + width=2*width; + } + +#ifdef X11_SHARED_MEM + switch(videoaccesstype) { + case VIDEO_XI_SHMSTD: + XShmPutImage(xWindow->display,xWindow->window, + xWindow->gc,ximage, + 0, 0, iOffsetX, iOffsetY, width, height, False); + XSync(xWindow->display,false); /* true not needed, done by XPending */ + break; + + + case VIDEO_XI_STANDARD: +#endif + XPutImage(xWindow->display,xWindow->window, + xWindow->gc, ximage, + 0, 0, iOffsetX, iOffsetY, width, height); + XSync(xWindow->display,false); /* true not needed, done by XPending */ +#ifdef X11_SHARED_MEM + break; + } +#endif +} + + + +int ImageDeskX11::createImage(int createType,int mode) { + + if (xWindow == NULL) { + cout << "ImageDeskX11::createImage - you have to call init first!" << endl; + return false; + } + + videoaccesstype=VIDEO_XI_NONE; + +#ifdef X11_SHARED_MEM + if(XShmQueryVersion(xWindow->display,&XShmMajor,&XShmMinor,&XShmPixmaps)) { + if (XShmPixmaps==True) { + if (createType & VIDEO_XI_SHMSTD) { + videoaccesstype=VIDEO_XI_SHMSTD; + } + } + } else { + if (createType & VIDEO_XI_SHMSTD) { + return ERR_XI_NOSHAREDMEMORY; + } + } +#endif + if (videoaccesstype == VIDEO_XI_NONE) { + videoaccesstype=createType; + } + + switch(videoaccesstype) + { +#ifdef X11_SHARED_MEM + + + case VIDEO_XI_SHMSTD: + + lXerror=false; + XSetErrorHandler(dummy); + + shmseginfo=(XShmSegmentInfo *)malloc(sizeof(XShmSegmentInfo)); + if(!shmseginfo) + return ERR_XI_SHMALLOC; + + memset(shmseginfo,0, sizeof(XShmSegmentInfo)); + + if (imageMode & _IMAGE_DOUBLE) { + ximage=XShmCreateImage(xWindow->display,xWindow->visual, + xWindow->depth, + ZPixmap,NULL,shmseginfo,2*xWindow->width, + 2*xWindow->height); + } else { + ximage=XShmCreateImage(xWindow->display,xWindow->visual, + xWindow->depth, + ZPixmap,NULL,shmseginfo,xWindow->width, + xWindow->height); + } + + if(!ximage) + return ERR_XI_SHMXIMAGE; + + shmseginfo->shmid=shmget(IPC_PRIVATE, + ximage->bytes_per_line* + ximage->height,IPC_CREAT|0777); + + if(shmseginfo->shmid<0) + return ERR_XI_SHMSEGINFO; + + shmseginfo->shmaddr=(char*)shmat(shmseginfo->shmid,NULL,0); + ximage->data=shmseginfo->shmaddr; + virtualscreen=(unsigned char *)ximage->data; + + if(!virtualscreen) + return ERR_XI_SHMVIRTALLOC; + + shmseginfo->readOnly=False; + + XShmAttach(xWindow->display,shmseginfo); + XSync(xWindow->display, False); + XSetErrorHandler(NULL); + XFlush(xWindow->display); + if (lXerror) { + cout << "ERR_XI_SHMATTACH -2"<<endl; + return ERR_XI_SHMATTACH; + } + + break; +#endif + + case VIDEO_XI_STANDARD: + if (mode & _IMAGE_DOUBLE) { + virtualscreen=(unsigned char *) + malloc(xWindow->screensize*sizeof(char)*4); + + if(virtualscreen==NULL) + return ERR_XI_VIRTALLOC; + + ximage=XCreateImage(xWindow->display,xWindow->visual, + xWindow->depth,ZPixmap, + 0,(char*)virtualscreen, + 2*xWindow->width,2*xWindow->height, + 32,2*xWindow->width*xWindow->pixelsize); + } else { + virtualscreen=(unsigned char *) + malloc(xWindow->screensize*sizeof(char)); + + if(virtualscreen==NULL) + return ERR_XI_VIRTALLOC; + + ximage=XCreateImage(xWindow->display,xWindow->visual, + xWindow->depth,ZPixmap, + 0,(char*)virtualscreen, + xWindow->width,xWindow->height, + 32,xWindow->width*xWindow->pixelsize); + } + + if(!ximage) + return ERR_XI_XIMAGE; + break; + + default: + return ERR_XI_FAILURE; + + } + + if ( (videoaccesstype == VIDEO_XI_STANDARD) || + (videoaccesstype == VIDEO_XI_SHMSTD) ) { +#ifndef WORDS_BIGENDIAN + ximage->byte_order = LSBFirst; + ximage->bitmap_bit_order = LSBFirst; +#else + ximage->byte_order = MSBFirst; + ximage->bitmap_bit_order = MSBFirst; +#endif + + } + return ERR_XI_OK; +} + + + +int ImageDeskX11::destroyImage() { + if(xWindow && xWindow->display && xWindow->window) { + switch(videoaccesstype) { +#ifdef X11_SHARED_MEM + case VIDEO_XI_SHMSTD: + if (shmseginfo) { + XShmDetach(xWindow->display,shmseginfo); + if(ximage) { + XDestroyImage(ximage); + ximage=NULL; + } + if(shmseginfo->shmaddr) { + shmdt(shmseginfo->shmaddr); + shmseginfo->shmaddr=NULL; + } + if(shmseginfo->shmid>=0) + shmctl(shmseginfo->shmid,IPC_RMID,NULL); + + free(shmseginfo); + } + shmseginfo=NULL; + break; + +#endif + case VIDEO_XI_STANDARD: + if(ximage) { + XDestroyImage(ximage); + ximage=NULL; + /* + XDestroyImage function calls frees both the image structure + and the data pointed to by the image structure. + */ + virtualscreen=NULL; + } + break; + + default: + // cout << "no open window to close"<<endl; + break; + } + } + videoaccesstype=VIDEO_XI_NONE; + imageMode=_IMAGE_NONE; + return true; +} + + +bool ImageDeskX11::switchMode(int width, int , bool zoom) +{ + iWidth = xWindow->screenptr->width; + iHeight = xWindow->screenptr->height; + +#ifdef X11_XVIDMODE + iOldMode = -1; + int vm_count,i; + + cout << "Find best matching videomode ..." << endl; + + if (!XF86VidModeGetAllModeLines(xWindow->display,XDefaultScreen(xWindow->display), + &vm_count,&vm_modelines)) { + return false; + } + + int bestMode = -1; + int border, minBorder = INT_MAX; + + for (i = 0; i < vm_count; i++) { + printf("mode %d: %dx%d\n",i, vm_modelines[i]->hdisplay,vm_modelines[i]->vdisplay); + + if (xWindow->screenptr->width == vm_modelines[i]->hdisplay) + iOldMode = i; + + border = vm_modelines[i]->hdisplay - width; + if ((border > 0) && (border < minBorder)) { + bestMode = i; + minBorder = border; + bZoom = false; + } + if (zoom) { + border = vm_modelines[i]->hdisplay - 2 * width; + if ((border > 0) && (border < minBorder)) { + bestMode = i; + minBorder = border; + bZoom = true; + } + } + } + cout << "best mode: " << bestMode << endl; + + iWidth = vm_modelines[bestMode]->hdisplay; + iHeight = vm_modelines[bestMode]->vdisplay; + + if (XF86VidModeSwitchToMode(xWindow->display,XDefaultScreen(xWindow->display), + vm_modelines[bestMode])) { + XF86VidModeSetViewPort(xWindow->display,XDefaultScreen(xWindow->display), 0, 0); + XFlush(xWindow->display); + return true; + } +#endif + return false; +} diff --git a/mpeglib/lib/util/render/x11/imageDeskX11.h b/mpeglib/lib/util/render/x11/imageDeskX11.h new file mode 100644 index 00000000..efbd4e90 --- /dev/null +++ b/mpeglib/lib/util/render/x11/imageDeskX11.h @@ -0,0 +1,85 @@ +/* + standard and shared mem X11 images + 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 __IMAGEDESKX11_H +#define __IMAGEDESKX11_H +#include <limits.h> +#include "xinit.h" + +#include "../imageBase.h" + +#define VIDEO_XI_NONE 0x00 /* No access defined */ +#define VIDEO_XI_STANDARD 0x01 /* Use standard Xlib calls */ +#define VIDEO_XI_SHMSTD 0X02 /* Use Xlib shared memory extension */ + +/** + + Displays and renders X11 images in software with the help + of the ditherWrapper class. +*/ + + +class ImageDeskX11 : public ImageBase { + +#ifdef X11_SHARED_MEM + XShmSegmentInfo *shmseginfo; +#endif + + unsigned char *virtualscreen; + int videoaccesstype; + XImage *ximage; + int lSupport; + + int XShmMajor,XShmMinor; + Bool XShmPixmaps; + + XWindow* xWindow; + int imageMode; + DitherWrapper* ditherWrapper; + + int iOffsetX; + int iOffsetY; + int iWidth; + int iHeight; + +#ifdef X11_XVIDMODE + XF86VidModeModeInfo **vm_modelines; + + int iOldMode; +#endif + + bool bZoom; + + public: + ImageDeskX11(); + ~ImageDeskX11(); + + void init(XWindow* xWindow, YUVPicture* pic = NULL); + + int support(); + + int openImage(int ditherSize); + int closeImage(); + + void ditherImage(YUVPicture* pic); + void putImage(); + + private: + int createImage(int createType,int size); + int destroyImage(); + + bool switchMode(int width, int height, bool zoom); + +}; + +#endif diff --git a/mpeglib/lib/util/render/x11/imageXVDesk.cpp b/mpeglib/lib/util/render/x11/imageXVDesk.cpp new file mode 100644 index 00000000..e087ba40 --- /dev/null +++ b/mpeglib/lib/util/render/x11/imageXVDesk.cpp @@ -0,0 +1,405 @@ +/* + xfree 4.0 XV extension desk mode + 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 "imageXVDesk.h" + +#include <iostream> + +using namespace std; + +ImageXVDesk::ImageXVDesk() { + + lSupport=false; + + ditherWrapper=NULL; + supportedModes = _IMAGE_NONE; + setIdentifier("XV"); + + xWindow = NULL; + +#ifdef X11_XV + keepRatio = false; + +#endif +} + + +ImageXVDesk::~ImageXVDesk() { + if (ditherWrapper != NULL) { + delete ditherWrapper; + } + freeImage(); +} + +void ImageXVDesk::init(XWindow* xWindow, YUVPicture*) +{ +#ifdef X11_XV + this->xWindow=xWindow; + + xv_port=-1; + shmem_flag = 0; + yuv_image=NULL; + yuv_shminfo.shmaddr=NULL; + yuv_shminfo.shmid=-1; + + if (XShmQueryExtension(xWindow->display)) shmem_flag = 1; + if (!shmem_flag) { + printf("no shmem available.\n"); + return; + } + + + if (haveXVSupport(xWindow)==true) { + supportedModes = _IMAGE_DESK | _IMAGE_DOUBLE | _IMAGE_FULL | _IMAGE_RESIZE; + lSupport=true; + } else { + return; + } + + if (ditherWrapper == NULL) { + ditherWrapper=new Dither2YUV(); + } + imageID = -1; +#endif +} + +int ImageXVDesk::support() { + return lSupport; +} + +int ImageXVDesk::openImage(int imageMode) { + + + if (imageMode & _IMAGE_FULL) { + XResizeWindow(xWindow->display, xWindow->window, + xWindow->screenptr->width, xWindow->screenptr->height); + setKeepRatio(true); + } else if (imageMode & _IMAGE_DOUBLE) { + XResizeWindow(xWindow->display, xWindow->window, + xWindow->width * 2, xWindow->height * 2); + setKeepRatio(false); + } else { + setKeepRatio(false); + } + + return true; +} + + +int ImageXVDesk::closeImage() { + freeImage(); + return true; +} + +void ImageXVDesk::ditherImage(YUVPicture* pic) { + +#ifdef X11_XV + int x_return; + int y_return; + int height, dy; + unsigned int border_width_return; + unsigned int depth_return; + unsigned int _w; + unsigned int _h; + Window _dw; + + if (xWindow == NULL) { + cout << "ImageXVDesk::ditherImage - you have to call before dithering an image!" << endl; + return; + } + + // check for not supported formats and if possible convert them + int inputType=pic->getImageType(); + if (inputType == PICTURE_RGB_FLIPPED) { + cout << "xv for flipped rgb not implemented"<<endl; + return; + } + + // create xv image + int id; + if (imageID != pic->getImageType()) { + imageID = pic->getImageType(); + switch (imageID) { + case PICTURE_YUVMODE_CR_CB: + case PICTURE_YUVMODE_CB_CR: + case PICTURE_RGB: + id = GUID_YUV12_PLANAR; + break; + case PICTURE_YUVMODE_YUY2: + id = GUID_YUY2_PACKED; + break; + case PICTURE_YUVMODE_UYVY: + id = GUID_UYVY_PACKED; + break; + default: + cout << "unknown type for yuv image!" << endl; + return; + } + freeImage(); + + createImage(id); + } + + XGetGeometry(xWindow->display,(Drawable)xWindow->window, + &_dw, &x_return, &y_return, &_w, &_h, + &border_width_return, &depth_return); + + // now dither the image + + // we (currently) cannot create yuvPicture _in_ + // the shared segment here we copy it + + unsigned char* image=pic->getImagePtr(); + if (inputType == PICTURE_RGB) { + ditherWrapper->doDither(pic, + DefaultDepth(xWindow->display,xWindow->screennum), + _SIZE_NORMAL, (unsigned char*) yuv_image->data, 0); + } else { + memcpy(yuv_image->data,image,pic->getImageSize()); + } + + if (keepRatio) { + height = (_w * yuv_image->height) / yuv_image->width; + dy = (((int) _h) - height + 1) / 2; + XvShmPutImage(xWindow->display, xv_port,xWindow->window, + xWindow->gc, yuv_image, + 0, 0, yuv_image->width, yuv_image->height, + 0, dy, _w, height, False); + if (dy > 0) { + XFillRectangle(xWindow->display, xWindow->window,xWindow->gc, + 0, 0, _w, dy); + XFillRectangle(xWindow->display, xWindow->window,xWindow->gc, + 0, height+dy-1, _w, dy+1); + } + } else { + XvShmPutImage(xWindow->display, xv_port,xWindow->window, + xWindow->gc, yuv_image, + 0, 0, yuv_image->width, yuv_image->height, + 0, 0, _w, _h, False); + } +#endif +} + + +void ImageXVDesk::putImage() { + + //XFlush(xWindow->display); + XSync(xWindow->display, false); +} + +void ImageXVDesk::setKeepRatio(bool enable) +{ +#ifdef X11_XV + keepRatio = enable; +#endif +} + + +int ImageXVDesk::haveXVSupport(XWindow* xWindow) { +#ifdef X11_XV + int ret; + unsigned int p_version=0; + unsigned int p_release=0; + unsigned int p_request_base=0; + unsigned int p_event_base=0; + unsigned int p_error_base=0; + + unsigned int p_num_adaptors=0; + + /**------------------------------- XV ------------------------------------*/ + + /** query and print Xvideo properties */ + + ret = XvQueryExtension(xWindow->display, + &p_version, &p_release, &p_request_base, + &p_event_base, &p_error_base); + if (ret != Success) { + if (ret == XvBadExtension) { + printf("XvBadExtension returned at XvQueryExtension.\n"); + } else if (ret == XvBadAlloc) { + printf("XvBadAlloc returned at XvQueryExtension.\n"); + } else { + printf("other error happened at XvQueryExtension.\n"); + } + return false; + } + /* + printf("========================================\n"); + printf("XvQueryExtension returned the following:\n"); + printf("p_version : %u\n", p_version); + printf("p_release : %u\n", p_release); + printf("p_request_base : %u\n", p_request_base); + printf("p_event_base : %u\n", p_event_base); + printf("p_error_base : %u\n", p_error_base); + printf("========================================\n"); + */ + + ret = XvQueryAdaptors(xWindow->display, DefaultRootWindow(xWindow->display), + &p_num_adaptors, &ai); + + if (ret != Success) { + if (ret == XvBadExtension) { + printf("XvBadExtension returned at XvQueryExtension.\n"); + } else if (ret == XvBadAlloc) { + printf("XvBadAlloc returned at XvQueryExtension.\n"); + } else { + printf("other error happaned at XvQueryAdaptors.\n"); + } + return false; + } + /* + printf("=======================================\n"); + printf("XvQueryAdaptors returned the following:\n"); + printf("%d adaptors available.\n", p_num_adaptors); + */ + if (p_num_adaptors == 0) { + //cout << "no adaptors found. XV not possible"<<endl; + return false; + } + + unsigned int i; + unsigned int j; + + for (i = 0; i < p_num_adaptors; i++) { + /* + printf(" name: %s\n" + " type: %s%s%s%s%s\n" + " ports: %ld\n" + " first port: %ld\n", + ai[i].name, + (ai[i].type & XvInputMask) ? "input | " : "", + (ai[i].type & XvOutputMask) ? "output | " : "", + (ai[i].type & XvVideoMask) ? "video | " : "", + (ai[i].type & XvStillMask) ? "still | " : "", + (ai[i].type & XvImageMask) ? "image | " : "", + ai[i].num_ports, + ai[i].base_id); + */ + xv_port = ai[i].base_id; + + //printf("adaptor %d ; format list:\n", i); + for (j = 0; j < ai[i].num_formats; j++) { + /* + printf(" depth=%d, visual=%ld\n", + ai[i].formats[j].depth, + ai[i].formats[j].visual_id); + */ + } + unsigned int p; + unsigned int encodings; + int attributes; + int formats; + + for (p = ai[i].base_id; p < ai[i].base_id+ai[i].num_ports; p++) { + + //printf(" encoding list for port %d\n", p); + if (XvQueryEncodings(xWindow->display, p, &encodings, &ei) != Success) { + //printf("XvQueryEncodings failed.\n"); + continue; + } + for (j = 0; j < encodings; j++) { + /* + printf(" id=%ld, name=%s, size=%ldx%ld, numerator=%d, denominator=%d\n", + ei[j].encoding_id, ei[j].name, ei[j].width, ei[j].height, + ei[j].rate.numerator, ei[j].rate.denominator); + */ + } + XvFreeEncodingInfo(ei); + int k; + //printf(" attribute list for port %d\n", p); + at = XvQueryPortAttributes(xWindow->display, p, &attributes); + for (k = 0; k < attributes; k++) { + /* + printf(" name: %s\n" + " flags: %s%s\n" + " min_color: %i\n" + " max_color: %i\n", + at[k].name, + (at[k].flags & XvGettable) ? " get" : "", + (at[k].flags & XvSettable) ? " set" : "", + at[k].min_value, at[k].max_value); + */ + } + if (at) + XFree(at); + + //printf(" image format list for port %d\n", p); + fo = XvListImageFormats(xWindow->display, p, &formats); + for (k = 0; k < formats; k++) { + /* + printf(" 0x%x (%4.4s) %s\n", + fo[k].id, + (char *)&fo[k].id, + (fo[k].format == XvPacked) ? "packed" : "planar"); + */ + } + if (fo) + XFree(fo); + } + printf("\n"); + } + if (p_num_adaptors > 0) + XvFreeAdaptorInfo(ai); + if (xv_port == -1) { + return false; + } +#endif + return true; + +} + + +void ImageXVDesk::freeImage() { +#ifdef X11_XV + if (xWindow == NULL) { + return; + } + if (yuv_shminfo.shmid >=0) { + XShmDetach(xWindow->display,&yuv_shminfo); + if(yuv_shminfo.shmaddr) { + shmdt(yuv_shminfo.shmaddr); + XFree(yuv_image); + yuv_shminfo.shmaddr=NULL; + } + XSync(xWindow->display, False); + yuv_shminfo.shmid=-1; + } +#endif +} + + +void ImageXVDesk::createImage(int id) { +#ifdef X11_XV + if (xWindow == NULL) { + cout << "ImageXVDesk::freeImage - you have to call init before creating an image!" << endl; + return; + } + + yuv_image = XvShmCreateImage(xWindow->display, xv_port, + id, 0, + xWindow->width, + xWindow->height, &yuv_shminfo); + + yuv_shminfo.shmid = shmget(IPC_PRIVATE, + yuv_image->data_size, IPC_CREAT | 0777); + yuv_shminfo.shmaddr = yuv_image->data = + (char*)shmat(yuv_shminfo.shmid, 0, 0); + yuv_shminfo.readOnly = False; + + if (!XShmAttach(xWindow->display, &yuv_shminfo)) { + printf("XShmAttach failed !\n"); + lSupport=false; + return; + } + shmctl(yuv_shminfo.shmid, IPC_RMID, 0); +#endif +} diff --git a/mpeglib/lib/util/render/x11/imageXVDesk.h b/mpeglib/lib/util/render/x11/imageXVDesk.h new file mode 100644 index 00000000..44124428 --- /dev/null +++ b/mpeglib/lib/util/render/x11/imageXVDesk.h @@ -0,0 +1,88 @@ +/* + xfree 4.0 XV extension desk mode + 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 __IMAGEXVDESK_H +#define __IMAGEXVDESK_H + +#include "xinit.h" + +#include "../imageBase.h" +#include "../dither2YUV/dither2YUV.h" + +#include <stdio.h> + +#if !defined(__NetBSD__) +#include <semaphore.h> +#endif + +//#undef X11_XV + +#define GUID_YUV12_PLANAR 0x32315659 +#define GUID_I420_PLANAR 0x30323449 +#define GUID_YUY2_PACKED 0x32595559 +#define GUID_UYVY_PACKED 0x59565955 + +/** + The XV extension dither yuv images in hardware and allows + scaling of images. + But its currently not supported by many drivers. + +*/ + + +class ImageXVDesk : public ImageBase { + +#ifdef X11_XV + XvAdaptorInfo *ai; + XvEncodingInfo *ei; + XvAttribute *at; + XvImageFormatValues *fo; + + XvImage *yuv_image; + bool keepRatio; + + int xv_port; + int imageID; + + int shmem_flag; + XShmSegmentInfo yuv_shminfo; +#endif + Dither2YUV* ditherWrapper; + + int lSupport; + XWindow* xWindow; + + public: + ImageXVDesk(); + ~ImageXVDesk(); + + void init(XWindow* xWindow, YUVPicture* pic = NULL); + + int support(); + + int openImage(int imageMode); + int closeImage(); + + void ditherImage(YUVPicture* pic); + void putImage(); + + void setKeepRatio(bool enable); + + private: + int haveXVSupport(XWindow* xWindow); + void freeImage(); + void createImage(int id); + +}; + +#endif diff --git a/mpeglib/lib/util/render/x11/initDisplay.cpp b/mpeglib/lib/util/render/x11/initDisplay.cpp new file mode 100644 index 00000000..d0029eb6 --- /dev/null +++ b/mpeglib/lib/util/render/x11/initDisplay.cpp @@ -0,0 +1,255 @@ +/* + here are the different initialisation routines for different displays + 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 "initDisplay.h" + +#include <iostream> + +using namespace std; + + + +static unsigned long wpixel[256]; + + + + +/* + *-------------------------------------------------------------- + * + * InitColorDisplay -- + * + * Initialized display for full color output. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +void initColorDisplay(XWindow* xwindow) { + XWindowAttributes winattr; + + + XGetWindowAttributes(xwindow->display, xwindow->window, &winattr); + + xwindow->redMask = winattr.visual->red_mask; + xwindow->greenMask = winattr.visual->green_mask; + xwindow->blueMask = winattr.visual->blue_mask; +} + + + + + + + +/* + *-------------------------------------------------------------- + * + * FindFullColorVisual + * + * Returns a pointer to a full color bit visual on the display + * + * Results: + * See above. + * + * Side effects: + * Unknown. + * + *-------------------------------------------------------------- + */ +Visual* FindFullColorVisual (Display* dpy,int* depth) { + XVisualInfo vinfo; + XVisualInfo *vinfo_ret; + int numitems, maxdepth; + +#if defined(__cplusplus) || defined(c_plusplus) + vinfo.c_class = TrueColor; +#else + vinfo.class = TrueColor; +#endif + + vinfo_ret = XGetVisualInfo(dpy, VisualClassMask, &vinfo, &numitems); + + if (numitems == 0) return NULL; + + maxdepth = 0; + while(numitems > 0) { + if (vinfo_ret[numitems-1].depth > maxdepth) { + maxdepth = vinfo_ret[numitems-1 ].depth; + } + numitems--; + } + XFree((void *) vinfo_ret); + + if (maxdepth < 16) return NULL; + + if (XMatchVisualInfo(dpy, DefaultScreen(dpy), maxdepth, + TrueColor, &vinfo)) { + *depth = maxdepth; + return vinfo.visual; + } + + return NULL; +} + + +/* + *-------------------------------------------------------------- + * + * CreateFullColorWindow + * + * Creates a window capable of handling 32 bit color. + * + * Results: + * See above. + * + * Side effects: + * Unknown. + * + *-------------------------------------------------------------- + */ +void CreateFullColorWindow (XWindow* xwindow) { + int depth; + Visual *visual; + XSetWindowAttributes xswa; + unsigned long mask; + unsigned int c_class; + int screen; + Display *dpy=xwindow->display; + /* + int x = xinfo->hints.x, + y = xinfo->hints.y; + unsigned int w = xinfo->hints.width, + h = xinfo->hints.height; + */ + screen = XDefaultScreen(dpy); + c_class = InputOutput; /* Could be InputOnly */ + if (xwindow->visual == NULL) { + xwindow->visual = visual = FindFullColorVisual (dpy, &depth); + xwindow->depth = depth; + } else { + visual=xwindow->visual; + depth=xwindow->depth; + } + + if (visual == NULL) { + cout << "visual is null"<<endl; + return; + } + mask = CWBackPixel | CWColormap | CWBorderPixel; + if (xwindow->colormap==0) { + xswa.colormap = XCreateColormap(dpy, + XRootWindow(dpy, screen), + visual, AllocNone); + } else xswa.colormap = xwindow->colormap; + xswa.background_pixel = BlackPixel(dpy, DefaultScreen(dpy)); + xswa.border_pixel = WhitePixel(dpy, DefaultScreen(dpy)); + XSetWindowColormap(xwindow->display,xwindow->window,xwindow->colormap); + + + /* + xwindow->window = XCreateWindow(dpy, RootWindow(dpy, screen), x, y, w, h, + (unsigned int) 1, depth, c_class, + visual, mask, &xswa); + */ +} + + + + + + + +/* + *-------------------------------------------------------------- + * + * InitSimpleDisplay -- + * + * Initialized display, sets up colormap, etc. Use for 8 Bit color + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +void initSimpleDisplay(XWindow* xwindow) { + int ncolors = LUM_RANGE*CB_RANGE*CR_RANGE; + XColor xcolor; + int i, lum_num, cr_num, cb_num; + unsigned char r, g, b; + Colormap dcmap; + Display *display; + ColorTable8Bit colorTable8Bit; + + display = xwindow->display; + + + xwindow->colormap = XDefaultColormap(display, DefaultScreen(display)); + dcmap = xwindow->colormap; + + xcolor.flags = DoRed | DoGreen | DoBlue; + + + //if (xinfo->owncmFlag) goto create_map; + +retry_alloc_colors: + for (i=0; i<ncolors; i++) { + + lum_num = (i / (CR_RANGE*CB_RANGE))%LUM_RANGE; + cr_num = (i / CB_RANGE)%CR_RANGE; + cb_num = i % CB_RANGE; + + colorTable8Bit.ConvertColor(lum_num, cr_num, cb_num, &r, &g, &b); + + xcolor.red = r * 256; + xcolor.green = g * 256; + xcolor.blue = b * 256; + + if ((XAllocColor(display,xwindow->colormap , &xcolor) == 0 + && xwindow->colormap == dcmap)) { + int j; + unsigned long tmp_pixel; + XWindowAttributes xwa; + + // Free colors. + for (j = 0; j < i; j ++) { + tmp_pixel = wpixel[j]; + XFreeColors(display,xwindow->colormap , &tmp_pixel, 1, 0); + } + + + //create_map: + XGetWindowAttributes(display, xwindow->window, &xwa); + xwindow->colormap = XCreateColormap(display, xwindow->window, + xwa.visual, AllocNone); + XSetWindowColormap(display, xwindow->window,xwindow->colormap ); + + goto retry_alloc_colors; + } + xwindow->pixel[i]=xcolor.pixel; + wpixel[i] = xcolor.pixel; + } + +} + + diff --git a/mpeglib/lib/util/render/x11/initDisplay.h b/mpeglib/lib/util/render/x11/initDisplay.h new file mode 100644 index 00000000..62841f19 --- /dev/null +++ b/mpeglib/lib/util/render/x11/initDisplay.h @@ -0,0 +1,34 @@ +/* + here are the different initialisation routines for different displays + 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 __INITDISPLAY_H +#define __INITDISPLAY_H + +#include "math.h" +#include "xinit.h" +#include "../dither/colorTable8Bit.h" + + + +extern void initColorDisplay(XWindow* xwindow); +extern void initSimpleDisplay(XWindow* xwindow); + +// helper functions +Visual *FindFullColorVisual (Display *dpy ,int *depth); +void CreateFullColorWindow (XWindow* xwindow); + + + +#endif diff --git a/mpeglib/lib/util/render/x11/x11Surface.cpp b/mpeglib/lib/util/render/x11/x11Surface.cpp new file mode 100644 index 00000000..d7b8f052 --- /dev/null +++ b/mpeglib/lib/util/render/x11/x11Surface.cpp @@ -0,0 +1,389 @@ +/* + surface wrapper for X11 Window + 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 "x11Surface.h" + +#include <iostream> + +using namespace std; + +const char *ERR_XI_STR[] = { + "X initialisation OK!", + "No Shared Memory available", + "cannot open Display", + "bad color depth", + "can't create Window", + "can't alloc memory for virtual screen", + "cannot create XImage", + "can't alloc memory for Shared memory segment info", + "cannot create Shared Memory XImage", + "Shared memory segment info error", + "Shared memory virtual screen allocation failed", + "cannot attach Shared Memory segment to display" +}; + + +#ifndef KDE_USE_FINAL +static int dummy(Display* , XErrorEvent*) { + cout << "received x11 error!"<<endl; + return true; +} +#endif + +X11Surface::X11Surface() { + xWindow=(XWindow *)malloc(sizeof(XWindow)); + xWindow->lOpen=false; + xWindow->x = xWindow->y = 0; + xWindow->window = 0; + m_windowIdAvailable = false; + + imageMode=_IMAGE_NONE; + + imageCurrent=NULL; + xWindow->lOpen=false; + + + xWindow->display=XOpenDisplay(NULL); + if (xWindow->display) + XFlush(xWindow->display); + xWindow->redMask=0; + xWindow->greenMask=0; + xWindow->blueMask=0; + lXVAllow=true; + + images=0; + imageList = new ImageBase* [4]; + imageList[images++] = new ImageXVDesk(); + imageList[images++] = new ImageDGAFull(); + imageList[images++] = new ImageDeskX11(); + imageList[images] = NULL; +} + + +X11Surface::~X11Surface() { + close(); + if (xWindow->display) + XCloseDisplay(xWindow->display); + free(xWindow); + + for (int count=0 ; count<images ; count++) { + if (imageList[count] != NULL) + delete imageList[count]; + } + delete [] imageList; +} + + +int X11Surface::getHeight() { + return xWindow->height; +} + + +int X11Surface::getWidth() { + return xWindow->width; +} + +int X11Surface::isOpen() { + return xWindow->lOpen; +} + +int X11Surface::x11WindowId() { + if(m_windowIdAvailable) + return xWindow->window; + else + return -1; +} + +int X11Surface::open(int width, int height,const char *title, bool border) { + + close(); + xWindow->width=width; + xWindow->height=height; + + if(!xWindow->display) { + printf("\nX initialisation error:\n *** %s\n",ERR_XI_STR[ERR_XI_DISPLAY]); + printf("check ipcs and delete resources with ipcrm\n"); + exit(0); + } + + xWindow->screennum=DefaultScreen(xWindow->display); + xWindow->screenptr=DefaultScreenOfDisplay(xWindow->display); + xWindow->visual=DefaultVisualOfScreen(xWindow->screenptr); + xWindow->depth=DefaultDepth(xWindow->display,xWindow->screennum); + + switch(xWindow->depth) { + case 8: + xWindow->pixelsize=1; + break; + case 16: + xWindow->pixelsize=2; + break; + case 24: + xWindow->pixelsize=4; + break; + case 32: + xWindow->pixelsize=4; + break; + default: + cout << "unknown pixelsize for depth:"<<xWindow->depth<<endl; + exit(0); + } + + XColor background, ignored; + XAllocNamedColor (xWindow->display, + DefaultColormap (xWindow->display, xWindow->screennum), + "black", &background, &ignored); + + XSetWindowAttributes attributes; + attributes.background_pixel=background.pixel; + attributes.backing_store=NotUseful; + attributes.override_redirect=True; + + xWindow->window=XCreateWindow(xWindow->display, + RootWindowOfScreen(xWindow->screenptr), + 0,0, + xWindow->width, + xWindow->height,0, + xWindow->depth, + InputOutput, xWindow->visual, + (border) ? CWBackingStore : CWBackPixel|CWOverrideRedirect, + &attributes); + + m_windowIdAvailable = true; + if(!xWindow->window) { + printf("\nX initialisation error:\n *** %s\n",ERR_XI_STR[ERR_XI_WINDOW]); + printf("check ipcs and delete resources with ipcrm\n"); + return false; + } + + WM_DELETE_WINDOW = XInternAtom(xWindow->display, "WM_DELETE_WINDOW", False); + XSetWMProtocols(xWindow->display, xWindow->window, &WM_DELETE_WINDOW, 1); + + XSetErrorHandler(dummy); + + XStoreName(xWindow->display,xWindow->window,title); + XSelectInput(xWindow->display,xWindow->window, + ExposureMask|KeyPressMask|KeyReleaseMask|ButtonPressMask); + xWindow->gc=XCreateGC(xWindow->display,xWindow->window,0,NULL); + XMapRaised(xWindow->display,xWindow->window); + + if (xWindow->depth >= 16) { + initColorDisplay(xWindow); + + } else { + // depth is <= 8 + // allocate memory for dithertables + // gets the rgb masks + initColorDisplay(xWindow); + // create 8 bit dithertables + // create private colormap + initSimpleDisplay(xWindow); + + } + + xWindow->palette=NULL; + xWindow->screensize=xWindow->height*xWindow->width*xWindow->pixelsize; + xWindow->lOpen=true; + + for (int count=0 ; count<images ; count++) { + if (imageList[count] != NULL) + imageList[count]->init(xWindow); + } + + return true; +} + + +int X11Surface::close() { + if (isOpen()==false) { + return true; + } + closeImage(); + + XFreeGC(xWindow->display,xWindow->gc); + XDestroyWindow(xWindow->display,xWindow->window); + + xWindow->lOpen=false; + + + return true; +} + +ImageBase *X11Surface::findImage(int mode) { + for (int count=0 ; count<images ; count++) { + if ((imageList[count] == NULL) || (IS_DISABLED(imageList[count]))) + continue; + + if (imageList[count]->supportedModes & mode) + return imageList[count]; + } + return NULL; +} + +ImageBase **X11Surface::getModes() { + return imageList; +} + +void X11Surface::setModes(ImageBase **modes) { + imageList = modes; +} + +int X11Surface::openImage(int mode, YUVPicture*) { + if (imageMode != _IMAGE_NONE) { + cout << "bad open error X11Surface::openImage"<<endl; + return false; + } + if (mode == _IMAGE_NONE) { + cout << "X11Surface::openImage - no valid mode specified"<<endl; + return false; + } + + ImageBase *newImage=findImage(mode); + + if (newImage == NULL) { + cout << " X11Surface::openImage - no matching image found"<<endl; + imageMode=_IMAGE_NONE; + } else { + /* + printf("Best image found: %s\n", newImage->getIdentifier()); + printf("\tsupported modes: desk=%d, double=%d, full=%d, resize=%d\n", + HAS_DESK(newImage), + HAS_DOUBLE(newImage), + HAS_FULL(newImage), + HAS_RESIZE(newImage)); + */ + + open(xWindow->width, xWindow->height, "mpeglib", !(mode & _IMAGE_FULL)); + newImage->openImage(mode); + if (!IS_FULL(mode)) { + XMoveWindow(xWindow->display, xWindow->window, + xWindow->x, xWindow->y); + + XSizeHints hints; + hints.flags = PMaxSize; + if (HAS_RESIZE(newImage)) { + hints.max_width = INT_MAX; + hints.max_height = INT_MAX; + } else { + hints.max_width = xWindow->width; + hints.max_height = xWindow->height; + } + XSetWMNormalHints(xWindow->display, xWindow->window, &hints); + } + + imageMode=mode; + } + imageCurrent = newImage; + XSync(xWindow->display,true); + return (imageCurrent != NULL); +} + + +int X11Surface::closeImage() { + + if ((imageMode == _IMAGE_NONE) || (!xWindow->lOpen)) + return false; + + ImageBase *old = imageCurrent; + imageCurrent=NULL; + + XWindowAttributes attr; + Window junkwin; + + if (!IS_FULL(imageMode)) { + if (!XGetWindowAttributes(xWindow->display, xWindow->window, &attr)) + cout << "Can't get window attributes." << endl; + + XTranslateCoordinates (xWindow->display, xWindow->window, attr.root, + -attr.border_width, + -attr.border_width, + &xWindow->x, &xWindow->y, &junkwin); + } + + imageMode=_IMAGE_NONE; + old->closeImage(); + + return true; +} + + +int X11Surface::dither(YUVPicture* pic) { + if (imageCurrent != NULL) { + imageCurrent->ditherImage(pic); + } + return true; +} + + +int X11Surface::putImage(YUVPicture* ) { + if (imageCurrent != NULL) { + imageCurrent->putImage(); + } + return true; +} + + +int X11Surface::getDepth() { + return xWindow->depth; +} + +int X11Surface::getImageMode() { + return imageMode; +} + +int X11Surface::checkEvent(int* newMode) { + XEvent event; + + if (isOpen()==false) + return false; + + // check if we forward the call to the FULLSCREEN mode + if (!imageCurrent->active()) { + if (IS_FULL(imageMode)) { + *newMode=imageMode ^ _IMAGE_FULL; + return true; + } + } + + // normal X11 images use the X11 event queue + if (XCheckTypedWindowEvent(xWindow->display, + xWindow->window,ButtonPress,&event)) { + if (event.xbutton.button == Button1) { + if (findImage(_IMAGE_DOUBLE) != NULL) + *newMode = imageMode ^ _IMAGE_DOUBLE; + } else if (event.xbutton.button == Button3) { + if (findImage(_IMAGE_FULL) != NULL) + *newMode = imageMode ^ _IMAGE_DESK ^ _IMAGE_FULL; + } + return true; + } + // now check if there are unneeded events in the queue, + // then delete them + int eventCnt=XPending(xWindow->display); + if (eventCnt > 10) { + XSync(xWindow->display,true); + } + return false; + + +} + + + +void X11Surface::config(const char* key, + const char* value, void* ) { + if (strcmp(key,"xvAllow")==0) { + lXVAllow=atoi(value); + } +} + diff --git a/mpeglib/lib/util/render/x11/x11Surface.h b/mpeglib/lib/util/render/x11/x11Surface.h new file mode 100644 index 00000000..54a6582d --- /dev/null +++ b/mpeglib/lib/util/render/x11/x11Surface.h @@ -0,0 +1,79 @@ +/* + surface wrapper for X11 Window + 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 __X11SURFACE_H +#define __X11SURFACE_H + +#include <limits.h> +#include "xinit.h" +#include "../surface.h" +#include "initDisplay.h" +#include "../dither/ditherWrapper.h" +#include "imageDeskX11.h" +#include "imageDGAFull.h" +#include "imageXVDesk.h" + + + +class X11Surface : public Surface { + + int lOpen; + int imageMode; + + XWindow* xWindow; + + ImageBase** imageList; + int images; + + ImageBase* imageCurrent; + + Atom WM_DELETE_WINDOW; + Atom WM_RESIZE_WINDOW; + int lXVAllow; + + public: + X11Surface(); + ~X11Surface(); + + int isOpen(); + int open(int width, int height,const char *title, bool border = false); + int close(); + int getHeight(); + int getWidth(); + int getDepth(); + int getImageMode(); + int x11WindowId(); + + ImageBase *findImage(int mode); + + // these functions grant access to the supported images. be careful when changing + // entries, because these are no copies. they are the original values! + ImageBase **getModes(); + void setModes(ImageBase **modes); + + int openImage(int mode, YUVPicture* pic = NULL); + int closeImage(); + int dither(YUVPicture* pic); + int putImage(YUVPicture* pic); + + int checkEvent(int* mode); + + void config(const char* key, + const char* value,void* user_data); + + + private: + int initX11(); + bool m_windowIdAvailable; +}; +#endif diff --git a/mpeglib/lib/util/render/x11/xinit.h b/mpeglib/lib/util/render/x11/xinit.h new file mode 100644 index 00000000..c42c290f --- /dev/null +++ b/mpeglib/lib/util/render/x11/xinit.h @@ -0,0 +1,99 @@ + +#ifndef __XINIT_H__ +#define __XINIT_H__ + +#define __USE_X_SHAREDMEMORY__ + +#include <pthread.h> + + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + + +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/keysym.h> +#include <X11/Xatom.h> + + + +#ifdef X11_SHARED_MEM +#include <X11/extensions/XShm.h> +#include <sys/ipc.h> +#include <sys/shm.h> +#endif + + +#ifdef X11_XV +#include <X11/extensions/Xv.h> +#include <X11/extensions/Xvlib.h> +#include <X11/extensions/XShm.h> +#endif + +#ifdef X11_XVIDMODE +#include <X11/extensions/xf86vmode.h> +#endif + +#ifdef X11_DGA2 +#include <X11/extensions/xf86dga.h> +#endif + +#define ERR_XI_FAILURE 0xFF +#define ERR_XI_OK 0x00 +#define ERR_XI_NOSHAREDMEMORY 0x01 +#define ERR_XI_DISPLAY 0x02 +#define ERR_XI_BADDEPTH 0x03 +#define ERR_XI_WINDOW 0x04 +#define ERR_XI_VIRTALLOC 0x05 +#define ERR_XI_XIMAGE 0x06 +#define ERR_XI_SHMALLOC 0x07 +#define ERR_XI_SHMXIMAGE 0x08 +#define ERR_XI_SHMSEGINFO 0x09 +#define ERR_XI_SHMVIRTALLOC 0x0A +#define ERR_XI_SHMATTACH 0x0B + + + + +#define PIXEL unsigned long + +extern const char *ERR_XI_STR[]; + +struct XWindow { + + Display *display; + Window window; + Screen *screenptr; + int screennum; + Visual *visual; + GC gc; + + Colormap colormap; + PIXEL *palette; + int colorcells; + + int x; + int y; + int width; + int height; + int depth; + int pixelsize; + int screensize; + int lOpen; + + // colorMask + unsigned int redMask; + unsigned int greenMask; + unsigned int blueMask; + + // colortable for 8 bit colormap + // (created with interference by the XServer) + unsigned char pixel[256]; + +}; + + +#endif /* __XINIT_H__ */ diff --git a/mpeglib/lib/util/render/yuvPicture.cpp b/mpeglib/lib/util/render/yuvPicture.cpp new file mode 100644 index 00000000..e79d3bde --- /dev/null +++ b/mpeglib/lib/util/render/yuvPicture.cpp @@ -0,0 +1,253 @@ +/* + describes a picture in yuv format + 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 "yuvPicture.h" + +#include <iostream> + +using namespace std; + +static int instanceCnt=0; + +YUVPicture::YUVPicture(int width,int height) { + this->width=width; + this->height=height; + + instance=instanceCnt; + instanceCnt++; + imagePtr=NULL; + + setImageType(PICTURE_YUVMODE_CR_CB); + + + startTimeStamp=new TimeStamp(); + waitTime=new TimeStamp(); + earlyTime=new TimeStamp(); + mpegType=-1; + +} + + +YUVPicture::~YUVPicture() { + delete imagePtr; + delete earlyTime; + delete startTimeStamp; + delete waitTime; +} + + + +int YUVPicture::getHeight() { + return height; +} + + +int YUVPicture::getWidth() { + return width; +} + + + +int YUVPicture::getLumLength() { + return lumLength; +} + + +int YUVPicture::getColorLength() { + return colorLength; +} + +int YUVPicture::getImageSize() { + return imageSize; +} + + + + + + + +void YUVPicture::print(const char* title) { + cout << title <<":"; + printf(" instance:%d ",instance); + printf(" width:%d ",width); + printf(" height:%d ",height); + cout <<" picPerSec:"<<picPerSec; + switch(mpegType) { + case 1: + printf("I_FRAME "); + break; + case 2: + printf("P_FRAME "); + break; + case 3: + printf("B_FRAME "); + break; + case 4: + printf("D_FRAME "); + break; + default: + printf("<unknown> "); + } + printf("\n"); + + +} + + +void YUVPicture::setPicturePerSecond(float val) { + this->picPerSec=val; +} + + +float YUVPicture::getPicturePerSecond() { + return picPerSec; +} + + +void YUVPicture::setStartTimeStamp(TimeStamp* aStamp) { + aStamp->copyTo(startTimeStamp); +} + + +TimeStamp* YUVPicture::getStartTimeStamp() { + return startTimeStamp; +} + +void YUVPicture::setWaitTime(TimeStamp* aStamp) { + aStamp->copyTo(waitTime); +} + + +TimeStamp* YUVPicture::getWaitTime() { + return waitTime; +} + +void YUVPicture::setEarlyTime(TimeStamp* earlyTime) { + this->earlyTime=earlyTime; +} + + +TimeStamp* YUVPicture::getEarlyTime() { + return earlyTime; +} + + + +void YUVPicture::setMpegPictureType(int type) { + this->mpegType=type; +} + + +int YUVPicture::getMpegPictureType() { + return mpegType; +} + + +void YUVPicture::setImageType(int imageType) { + + + // + // Reset everything + // + + if (imagePtr != NULL) { + delete [] imagePtr; + imagePtr=NULL; + } + this->imageType=imageType; + + lumLength=0; + colorLength=0; + Cr_mode=NULL; + Cb_mode=NULL; + luminance_mode=NULL; + + + // + // YUV Images + // + if ( (imageType == PICTURE_YUVMODE_CR_CB) || + (imageType == PICTURE_YUVMODE_CB_CR) ) { + + + lumLength=width * height; + colorLength=width * height / 4; + imageSize=lumLength+colorLength+colorLength; + + // the 64 is some "security" space + imagePtr=new unsigned char[imageSize+64]; + + if (imagePtr == NULL) { + cout << "cannot create image"<<endl; + exit(0); + } + + // now caculate pointers to start addresses of lum/Cr/Cb blocks + // we need the yuvPtr for direct dither in hardware + // this should save a memcpy + + luminance = imagePtr; + Cr = imagePtr+lumLength; + Cb = imagePtr+lumLength+colorLength; + + + if ( (luminance == NULL) || + (Cr == NULL) || + (Cb == NULL) ) { + cout << "allocation luminance/Cr/Cb error"<<endl; + exit(0); + } + + switch(imageType) { + case PICTURE_YUVMODE_CR_CB: + Cr_mode=Cr; + Cb_mode=Cb; + luminance_mode=imagePtr; + break; + case PICTURE_YUVMODE_CB_CR: + Cr_mode=Cb; + Cb_mode=Cr; + luminance_mode=imagePtr; + break; + default: + cout << "unknown yuv mode:"<<imageType<<endl; + } + } + else if ( (imageType == PICTURE_YUVMODE_YUY2) || + (imageType == PICTURE_YUVMODE_UYVY) ) { + // these yuv-modes are packed + + imageSize=width * height * 2; + + // the 64 is some "security" space + imagePtr=new unsigned char[imageSize+64]; + + if (imagePtr == NULL) { + cout << "cannot create image"<<endl; + exit(0); + } + } + + // + // RGB Imcdages + // + + if ( (imageType == PICTURE_RGB) || + (imageType == PICTURE_RGB_FLIPPED) ){ + imageSize=width*height*4; + imagePtr=new unsigned char[imageSize]; + } + memset(imagePtr,0,imageSize); +} diff --git a/mpeglib/lib/util/render/yuvPicture.h b/mpeglib/lib/util/render/yuvPicture.h new file mode 100644 index 00000000..1995b473 --- /dev/null +++ b/mpeglib/lib/util/render/yuvPicture.h @@ -0,0 +1,110 @@ +/* + describes a picture in yuv format + 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 __YUVPICTURE_H +#define __YUVPICTURE_H + + +extern "C" { +#include <stdio.h> +#include <string.h> +} + +#include "../timeStamp.h" + +#define PICTURE_NO_TYPE -1 + +#define PICTURE_YUVMODE_CR_CB 1 +#define PICTURE_YUVMODE_CB_CR 2 +#define PICTURE_RGB 3 +#define PICTURE_RGB_FLIPPED 4 +#define PICTURE_YUVMODE_YUY2 5 +#define PICTURE_YUVMODE_UYVY 6 + +class YUVPicture { + + unsigned char* imagePtr; /* Pointer to complete yuv image */ + + unsigned char* luminance; /* Luminance plane. */ + unsigned char* Cr; /* Cr plane. */ + unsigned char* Cb; /* Cb plane. */ + + + int width; + int height; + + float picPerSec; + int lumLength; + int colorLength; + int imageSize; + + TimeStamp* startTimeStamp; + TimeStamp* waitTime; + TimeStamp* earlyTime; + + int mpegType; + int instance; + int imageType; + + unsigned char* image_mode; /* start Pointer to complete image */ + unsigned char* luminance_mode; /* Luminace plane. */ + unsigned char* Cr_mode; /* Cr plane. */ + unsigned char* Cb_mode; /* Cb plane. */ + + public: + YUVPicture(int width,int height); + ~YUVPicture(); + + // + // For YUV Images + // + inline unsigned char* getLuminancePtr() {return luminance_mode;} + inline unsigned char* getCrPtr() {return Cr_mode;} + inline unsigned char* getCbPtr() {return Cb_mode;} + + // general + inline unsigned char* getImagePtr() {return imagePtr;} + + // use these to swap the image Types + inline int getImageType() { return imageType; } + void setImageType(int mode); + + + int getHeight(); + int getWidth(); + + int getLumLength(); + int getColorLength(); + int getImageSize(); + + void setPicturePerSecond(float val); + float getPicturePerSecond(); + + + void setStartTimeStamp(TimeStamp* timeStamp); + TimeStamp* getStartTimeStamp(); + + void setWaitTime(TimeStamp* waitTime); + TimeStamp* getWaitTime(); + + void setEarlyTime(TimeStamp* earlyTime); + TimeStamp* getEarlyTime(); + + void setMpegPictureType(int type); + int getMpegPictureType(); + + + void print(const char* title); +}; +#endif diff --git a/mpeglib/lib/util/syncClock.cpp b/mpeglib/lib/util/syncClock.cpp new file mode 100644 index 00000000..6e03bc4b --- /dev/null +++ b/mpeglib/lib/util/syncClock.cpp @@ -0,0 +1,59 @@ +/* + basic synchronisation Classs + 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 "syncClock.h" + +#include <iostream> + +using namespace std; + +SyncClock::SyncClock() { +} + + +SyncClock::~SyncClock() { +} + + + +int SyncClock::getSyncMode() { + cout << "direct virtual call SyncClock::getSyncMode"<<endl; + return __SYNC_NONE; +} + + +void SyncClock::setSyncMode(int) { + cout << "direct virtual call SyncClock::setSyncMode"<<endl; +} + + + +int SyncClock::syncAudio(double ,double ) { + cout << "direct virtual call SyncClock::syncAudio"<<endl; + return true; +} + + +int SyncClock::syncVideo(double,double, + TimeStamp*, + TimeStamp*) { + cout << "direct virtual call SyncClock::syncVideo"<<endl; + return true; +} + + + +void SyncClock::print(char*) { + cout << "direct virtual call print"<<endl; +} + diff --git a/mpeglib/lib/util/syncClock.h b/mpeglib/lib/util/syncClock.h new file mode 100644 index 00000000..4b6bc2bb --- /dev/null +++ b/mpeglib/lib/util/syncClock.h @@ -0,0 +1,61 @@ +/* + basic synchronisation Classs + 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 __SYNCCLOCK_H +#define __SYNCCLOCK_H + +#include "timeWrapper.h" +#include "abstract/abs_thread.h" +#include "timeStamp.h" +#include <errno.h> + +#define __SYNC_NONE 0 +#define __SYNC_AUDIO 1 +#define __SYNC_VIDEO 2 +#define __SYNC_BOTH 3 + + +/** + The idea is similar to this: + We start a clock and selext a synchronisation mode. + (AUDIO,VIDEO,BOTH,NONE) + Assume we select AUDIO. When the audio thread delivers an SCR + and an PTS, we set the SCR from this set, as the new + time reference fo rthis clock. + If a video thread enters the class, with an SCR,PTS we wait, + or directly return if the PTS is in time or out of time, + but we never set the SCR. +*/ + +class SyncClock { + + + public: + SyncClock(); + virtual ~SyncClock(); + + virtual int getSyncMode(); + virtual void setSyncMode(int syncMode); + + + virtual int syncAudio(double pts,double scr); + virtual int syncVideo(double pts,double scr, + class TimeStamp* earlyTime, + class TimeStamp* waitTime); + + virtual void print(char* text); + + +}; +#endif diff --git a/mpeglib/lib/util/syncClockMPEG.cpp b/mpeglib/lib/util/syncClockMPEG.cpp new file mode 100644 index 00000000..53ae7e2d --- /dev/null +++ b/mpeglib/lib/util/syncClockMPEG.cpp @@ -0,0 +1,221 @@ +/* + synchronisation of audio/video (PTS) against system clock stamps (SCR) + 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 "syncClockMPEG.h" + + +#include <iostream> + +using namespace std; + + +SyncClockMPEG::SyncClockMPEG() { + syncMode=__SYNC_NONE; + abs_thread_mutex_init(&scrMut); + abs_thread_mutex_init(&changeMut); + lastSCR=0.0; + lastPTS=0.0; + jitter=0.0; + oldjitter=0.0; + + TimeWrapper::gettimeofday(&lastPTS_time); + + +} + + +SyncClockMPEG::~SyncClockMPEG() { + abs_thread_mutex_destroy(&changeMut); + abs_thread_mutex_destroy(&scrMut); +} + + + +int SyncClockMPEG::getSyncMode() { + return syncMode; +} + + +void SyncClockMPEG::setSyncMode(int syncMode) { + this->syncMode=syncMode; +} + + + +int SyncClockMPEG::syncAudio(double pts,double scr) { + switch(syncMode) { + case __SYNC_AUDIO: + markLastPTSTime(scr,pts); + break; + default: + cout << "syncMode not implemented:"<<syncMode<<endl; + } + return true; +} + + +int SyncClockMPEG::syncVideo(double pts,double scr, + TimeStamp* earlyTime, + TimeStamp* waitTime) { + int back; + switch(syncMode) { + case __SYNC_AUDIO: + back=gowait(scr,pts,earlyTime,waitTime); + return back; + break; + case __SYNC_NONE: + return true; + default: + cout << "syncMode not implemented"<<endl; + } + return true; +} + + +void SyncClockMPEG::lockSyncClock() { + abs_thread_mutex_lock(&changeMut); + abs_thread_mutex_lock(&scrMut); + abs_thread_mutex_unlock(&changeMut); + +} + + +void SyncClockMPEG::unlockSyncClock() { + abs_thread_mutex_unlock(&scrMut); +} + + +double SyncClockMPEG::getPTSTime(double* window) { + lockSyncClock(); + double currentPTS; + timeval_t current_time; + timeval_t passed_time; + TimeWrapper::gettimeofday(¤t_time); + + a_Minus_b_Is_C(¤t_time,&lastPTS_time,&passed_time); + currentPTS=lastPTS+timeval2Double(&passed_time); + *window=jitter+oldjitter; + + + unlockSyncClock(); + return currentPTS; +} + + +void SyncClockMPEG::markLastPTSTime(double ,double pts) { + double tmp; + double expect_time=getPTSTime(&tmp); + + lockSyncClock(); + oldjitter=jitter; + jitter=expect_time-pts; + + TimeWrapper::gettimeofday(&lastPTS_time); + lastPTS=pts; + + + unlockSyncClock(); + /* + cout << "(audio) pts stream:"<<pts + << " expect:"<<expect_time<<" jitter:"<<jitter<<endl; + */ + +} + + +int SyncClockMPEG::a_Minus_b_Is_C(timeval_t* a,timeval_t* b,timeval_t* c){ + c->tv_usec=a->tv_usec; + c->tv_sec=a->tv_sec; + + c->tv_usec-=b->tv_usec; + c->tv_sec-=b->tv_sec; + + if (c->tv_usec <= 0) { + c->tv_usec=c->tv_usec+1000000; + c->tv_sec--; + } + if (c->tv_usec >= 1000000) { + c->tv_usec=c->tv_usec-1000000; + c->tv_sec++; + } + return true; +} + + +double SyncClockMPEG::timeval2Double(timeval_t* a) { + return (double)a->tv_sec+(double)(a->tv_usec)/1000000.0; +} + + +void SyncClockMPEG::double2Timeval(double a,timeval_t* dest) { + dest->tv_sec=(int)a; + dest->tv_usec=(int)(1000000.0*(double)(a-(double)dest->tv_sec)); +} + + +int SyncClockMPEG::gowait(double ,double pts, + TimeStamp* earlyTime,TimeStamp* ) { + double window; + double currentPTS=getPTSTime(&window); + double diff_time; + + // in window we have the jitter + // diff_time is positive when we are in the future + diff_time=pts-(currentPTS+window); + + + + // tolerate one frame (for 25 frames/s) in the future + // but wait a bit + if (diff_time > 0.0) { + diff_time=diff_time/4.0; + + double2Timeval(diff_time,earlyTime->getTime()); + if (diff_time > 1) { + // cannot be, we assume stange clock error + earlyTime->set(1,0); + } + + return true; + } + + earlyTime->set(0,0); + // one frame late, display it, without waiting + // and hope we catch up + if (diff_time > -0.04) { + return true; + } + /* + cout << "(video) pts stream:"<<pts + << " pts expect:"<<currentPTS + << " window:"<<window<<endl; + */ + return false; +} + + +void SyncClockMPEG::printTime(timeval_t* a,char* text) { + cout << text + << "time(sec):"<<a->tv_sec + << "time(usec)"<<a->tv_usec<<endl; +} + +void SyncClockMPEG::print(char* text) { + cout << text + << " lastPTS:"<<lastPTS + << " lastSCR:"<<lastSCR + << " jitter:"<<jitter; + printTime(&lastPTS_time,(char*)"lastPTS_time"); + printTime(&lastSCR_time,(char*)"lastSCR_time"); +} diff --git a/mpeglib/lib/util/syncClockMPEG.h b/mpeglib/lib/util/syncClockMPEG.h new file mode 100644 index 00000000..1a812c45 --- /dev/null +++ b/mpeglib/lib/util/syncClockMPEG.h @@ -0,0 +1,77 @@ +/* + synchronisation of audio/video (PTS) against system clock stamps (SCR) + 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 __SYNCCLOCKMPEG_H +#define __SYNCCLOCKMPEG_H + + +#include "syncClock.h" + +/** + The idea is similar to this: + We start a clock and selext a synchronisation mode. + (AUDIO,VIDEO,BOTH,NONE) + Assume we select AUDIO. When the audio thread delivers an SCR + and an PTS, we set the SCR from this set, as the new + time reference fo rthis clock. + If a video thread enters the class, with an SCR,PTS we wait, + or directly return if the PTS is in time or out of time, + but we never set the SCR. +*/ + +class SyncClockMPEG : public SyncClock { + + int syncMode; + double lastSCR; + double lastPTS; + double jitter; + double oldjitter; + timeval_t lastSCR_time; + timeval_t lastPTS_time; + timeval_t drift_time; + + public: + SyncClockMPEG(); + ~SyncClockMPEG(); + + int getSyncMode(); + void setSyncMode(int syncMode); + + + int syncAudio(double pts,double scr); + int syncVideo(double pts,double scr, + class TimeStamp* earlyTime,class TimeStamp* waitTime); + + void print(char* text); + + double getPTSTime(double* window); + private: + + void printTime(timeval_t* a,char* text); + void markLastPTSTime(double scr,double pts); + int gowait(double scr,double pts, + class TimeStamp* earlyTime,class TimeStamp* waitTime); + int a_Minus_b_Is_C(timeval_t* a,timeval_t* b,timeval_t* c); + double timeval2Double(timeval_t* a); + void double2Timeval(double a,timeval_t* dest); + + void lockSyncClock(); + void unlockSyncClock(); + + abs_thread_mutex_t scrMut; + abs_thread_mutex_t changeMut; + + +}; +#endif + diff --git a/mpeglib/lib/util/timeStamp.cpp b/mpeglib/lib/util/timeStamp.cpp new file mode 100644 index 00000000..2804cc5b --- /dev/null +++ b/mpeglib/lib/util/timeStamp.cpp @@ -0,0 +1,273 @@ +/* + class for managing byte positions and associated time positions + 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 "timeStamp.h" + +#include <iostream> + +using namespace std; + + +TimeStamp::TimeStamp() { + key=0; + keylen=0; + time.tv_sec=0; + time.tv_usec=0; + + ptsTimeStamp=0.0; + scrTimeStamp=0.0; + videoFrameCounter=0; + dtsTimeStamp=0.0; + lPTSFlag=false; + +} + + +TimeStamp::~TimeStamp() { +} + + +void TimeStamp::copyTo(TimeStamp* dest) { + dest->setKey(key,keylen); + dest->setTime(&time); + dest->setPTSTimeStamp(ptsTimeStamp); + dest->setVideoFrameCounter(videoFrameCounter); + + dest->setSCRTimeStamp(scrTimeStamp); + dest->setDTSTimeStamp(dtsTimeStamp); + dest->setSyncClock(syncClock); + dest->setPTSFlag(lPTSFlag); +} + + +long TimeStamp::getKey() { + return key; +} + +int TimeStamp::getKeyLen() { + return keylen; +} + +void TimeStamp::setKey(long key,int len) { + this->key=key; + this->keylen=len; +} + + +void TimeStamp::setTime(timeval_t* newTime) { + time.tv_sec=newTime->tv_sec; + time.tv_usec=newTime->tv_usec; +} + + +void TimeStamp::gettimeofday() { + TimeWrapper::gettimeofday(&time); +} + + +timeval_t* TimeStamp::getTime() { + return &time; +} + + +void TimeStamp::waitForIt() { + timeval_t waitTime; + + waitTime.tv_sec=time.tv_sec; + waitTime.tv_usec=time.tv_usec; + + if (isPositive()) { + //cout << "wait:"<<waitTime.tv_sec<<" usec:"<<waitTime.tv_usec<<endl; + TimeWrapper::usleep(&waitTime); + } + +} + +void TimeStamp::addOffset(TimeStamp* stamp) { + addOffset(stamp->time.tv_sec,stamp->time.tv_usec); +} + +void TimeStamp::addOffset(int sec,long usec) { + time.tv_sec=time.tv_sec+sec; + time.tv_usec=time.tv_usec+usec; + if (time.tv_usec >= 1000000) { + time.tv_usec-=1000000; + time.tv_sec++; + } + if (time.tv_usec < 0) { + time.tv_usec+=1000000; + time.tv_sec--; + } +} + +void TimeStamp::minus(int sec,long usec) { + + time.tv_usec-=usec; + time.tv_sec-=sec; + if (time.tv_usec <= 0) { + time.tv_usec=time.tv_usec+1000000; + time.tv_sec--; + } + if (time.tv_usec >= 1000000) { + time.tv_usec=time.tv_usec-1000000; + time.tv_sec++; + } + +} + +void TimeStamp::minus(TimeStamp* stamp,TimeStamp* dest) { + + long sec=time.tv_sec; + long usec=time.tv_usec; + + minus(stamp->time.tv_sec,stamp->time.tv_usec); + + dest->set(time.tv_sec,time.tv_usec); + if (dest != this) { + time.tv_sec=sec; + time.tv_usec=usec; + } +} + + +int TimeStamp::lessThan(TimeStamp* stamp) { + return lessThan(stamp->time.tv_sec,stamp->time.tv_usec); +} + + +int TimeStamp::lessThan(int sec,long usec) { + int back=false; + if (time.tv_sec < sec) { + back=true; + } else { + if (time.tv_sec == sec) { + if (time.tv_usec < usec) { + back=true; + } + } + } + return back; +} + +void TimeStamp::set(long sec,long usec) { + time.tv_sec=sec; + time.tv_usec=usec; +} + + + +void TimeStamp::print(const char* name) { + cout << name + <<" lPTS:"<<lPTSFlag + <<" pts:"<<ptsTimeStamp + <<" dts:"<<dtsTimeStamp + <<" scr:"<<scrTimeStamp + <<" key:"<<key + <<" sec:"<<time.tv_sec + <<" usec:"<<time.tv_usec + <<" v-Minor:"<<videoFrameCounter<<endl; + + +} + + + + + +int TimeStamp::isPositive() { + if ((time.tv_sec == 0) && (time.tv_usec == 0)) { + return false; + } + return ((time.tv_sec >= 0) && (time.tv_usec >= 0)); +} + + +int TimeStamp::isNegative() { + if (time.tv_sec < 0) { + return true; + } + if (time.tv_usec < 0) { + return true; + } + return false; +} + + +int TimeStamp::getPTSFlag() { + return lPTSFlag; +} + +void TimeStamp::setPTSFlag(int lPTSFlag) { + this->lPTSFlag=lPTSFlag; +} + +double TimeStamp::getPTSTimeStamp() { + return ptsTimeStamp; +} + + +void TimeStamp::setPTSTimeStamp(double ptsTimeStamp) { + this->ptsTimeStamp=ptsTimeStamp; +} + + +double TimeStamp::getSCRTimeStamp() { + return scrTimeStamp; +} + + +void TimeStamp::setSCRTimeStamp(double scrTimeStamp) { + this->scrTimeStamp=scrTimeStamp; +} + + +double TimeStamp::getDTSTimeStamp() { + return dtsTimeStamp; +} + + +void TimeStamp::setDTSTimeStamp(double dtsTimeStamp) { + this->dtsTimeStamp=dtsTimeStamp; +} + +int TimeStamp::getVideoFrameCounter() { + return videoFrameCounter; +} + + +void TimeStamp::setVideoFrameCounter(int nr) { + this->videoFrameCounter=nr; +} + + + +double TimeStamp::getAsSeconds() { + return (double)time.tv_sec+(double)time.tv_usec/(double)1000000; +} + + + +SyncClock* TimeStamp::getSyncClock() { + return syncClock; +} + +void TimeStamp::setSyncClock(SyncClock* syncClock) { + this->syncClock=syncClock; +} + + + + + + + diff --git a/mpeglib/lib/util/timeStamp.h b/mpeglib/lib/util/timeStamp.h new file mode 100644 index 00000000..a45bb582 --- /dev/null +++ b/mpeglib/lib/util/timeStamp.h @@ -0,0 +1,92 @@ +/* + class for managing byte positions and associated time positions + 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 __TIMESTAMP_H +#define __TIMESTAMP_H + + +#include "syncClock.h" + + +class TimeStamp { + + long key; + int keylen; + + int videoFrameCounter; + + timeval_t time; + + int lPTSFlag; + + double ptsTimeStamp; + double scrTimeStamp; + double dtsTimeStamp; + + class SyncClock* syncClock; + + public: + TimeStamp(); + ~TimeStamp(); + + void gettimeofday(); + void set(long sec,long usec); + + void addOffset(TimeStamp* stamp); + void addOffset(int sec,long usec); + void copyTo(TimeStamp* dest); + + long getKey(); + int getKeyLen(); + void setKey(long key,int keylen); + + int getPTSFlag(); + void setPTSFlag(int lPTSFlag); + + + double getPTSTimeStamp(); + void setPTSTimeStamp(double ptsTimeStamp); + + double getDTSTimeStamp(); + void setDTSTimeStamp(double dtsTimeStamp); + + double getSCRTimeStamp(); + void setSCRTimeStamp(double scrTimeStamp); + + int getVideoFrameCounter(); + void setVideoFrameCounter(int nr); + + SyncClock* getSyncClock(); + void setSyncClock(class SyncClock* syncClock); + + + void print(const char* name); + void minus(TimeStamp* stamp,TimeStamp* dest); + void minus(int sec,long usec); + int lessThan(TimeStamp* stamp); + int lessThan(int sec,long usec); + double getAsSeconds(); + + void waitForIt(); + timeval_t* getTime(); + + int isPositive(); + int isNegative(); + + private: + void setTime(timeval_t* newTime); + void normalize(); + + +}; +#endif diff --git a/mpeglib/lib/util/timeStampArray.cpp b/mpeglib/lib/util/timeStampArray.cpp new file mode 100644 index 00000000..730dc280 --- /dev/null +++ b/mpeglib/lib/util/timeStampArray.cpp @@ -0,0 +1,178 @@ +/* + class for managing byte positions and associated time positions + 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 <iostream> + +#include "timeStampArray.h" + +using namespace std; + + +TimeStampArray::TimeStampArray(char* aName,int entries) { + + writePos=0; + readPos=0; + fillgrade=0; + lastWritePos=0; + this->entries=entries; + if (entries < 1) { + cout << "TimeStampArray entries must be >= 1"; + exit(0); + } + + + abs_thread_mutex_init(&writeInMut); + abs_thread_mutex_init(&changeMut); + + + + name=strdup(aName); + int i; + tStampArray=new TimeStamp*[entries]; + + for(i=0;i<entries;i++) { + tStampArray[i]=new TimeStamp(); + } + +} + + +TimeStampArray::~TimeStampArray() { + + int i; + for(i=0;i<entries;i++) { + delete tStampArray[i]; + } + delete [] tStampArray; + if (name != NULL) { + free(name); // allocated with strdup + } + abs_thread_mutex_destroy(&writeInMut); + abs_thread_mutex_destroy(&changeMut); +} + +TimeStamp* TimeStampArray::getReadTimeStamp() { + return tStampArray[readPos]; +} + + +int TimeStampArray::getFillgrade() { + return fillgrade; +} + +int TimeStampArray::insertTimeStamp(TimeStamp* src,long key,int len) { + if (src == NULL) { + return true; + } + lockStampArray(); + int back=true; + src->copyTo(tStampArray[writePos]); + tStampArray[writePos]->setKey(key,len); + /* + if (fillgrade > 0) { + if (tStampArray[lastWritePos]->getKey() == key) { + unlockStampArray(); + return; + } + } + */ + + lastWritePos=writePos; + writePos++; + fillgrade++; + if (writePos == entries) { + writePos=0; + } + if (fillgrade == entries) { + cout << name<<" TimeStampArray::array overfull forward"<<endl; + internalForward(); + back=false; + } + unlockStampArray(); + return back; +} + + +int TimeStampArray::bytesUntilNext(long key) { + lockStampArray(); + TimeStamp* current=tStampArray[readPos]; + int back=current->getKey()-key; + unlockStampArray(); + return back; +} + +TimeStamp* TimeStampArray::getTimeStamp(long key) { + lockStampArray(); + TimeStamp* back=tStampArray[readPos]; + if (key > back->getKey()+back->getKeyLen()) { + if (fillgrade > 1) { + internalForward(); + unlockStampArray(); + return getTimeStamp(key); + } + } + + /* + if (back->getKey() > key) { + cout << "key "<<key<<" too big"<<back->getKey()-key<<endl; + back->print("key access"); + } + */ + unlockStampArray(); + /* maybe we should return NULL here to indicate + that there is no valid timestamp */ + /* This would need a check for every getTimeStamp call + I think returning the last available stamp is ok + */ + return back; +} + + +void TimeStampArray::forward() { + lockStampArray(); + internalForward(); + unlockStampArray(); +} + + + +void TimeStampArray::clear() { + lockStampArray(); + writePos=0; + readPos=0; + fillgrade=0; + unlockStampArray(); +} + + +void TimeStampArray::lockStampArray() { + + abs_thread_mutex_lock(&changeMut); + abs_thread_mutex_lock(&writeInMut); + abs_thread_mutex_unlock(&changeMut); + +} + + +void TimeStampArray::unlockStampArray() { + abs_thread_mutex_unlock(&writeInMut); +} + + +void TimeStampArray::internalForward() { + readPos++; + fillgrade--; + if (readPos == entries) { + readPos=0; + } +} diff --git a/mpeglib/lib/util/timeStampArray.h b/mpeglib/lib/util/timeStampArray.h new file mode 100644 index 00000000..8b117652 --- /dev/null +++ b/mpeglib/lib/util/timeStampArray.h @@ -0,0 +1,85 @@ +/* + class for managing byte positions and associated time positions + 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 __TIMESTAMPARRAY_H +#define __TIMESTAMPARRAY_H + +#include "abstract/abs_thread.h" +#include "timeStamp.h" + + +/** + This class deals with the problem to sync audio and video. + Both streams are decoded in different threads, sometimes + the video is decoded faster than the audio and sometimes + not. + <p> + You need a general mechanism to decide, which is faster. + It works like this: + <p> + When the mpeg stream is split in video/audio part the split thread + writes the video/audio data to the inputInterface. + Additionally it writes a timestamp to the interface. + The interface counts the bytes and forward the bytes/timeStamp + pait to this class. + Later when the threads write to the outputInterface the ask + this class (with the bytePostions) which timestamp it + has and hass the data and the timestamp to the outputInterface. + There we can decide what to do with the data. + <p> + 1) audio faster than video = drop video picture + <p> + 2) video faster than audio - wait for audio. +*/ + + + +class TimeStampArray { + + TimeStamp** tStampArray; + + int lastWritePos; + int writePos; + int readPos; + int fillgrade; + char* name; + int entries; + + abs_thread_mutex_t writeInMut; + abs_thread_mutex_t changeMut; + + + public: + TimeStampArray(char* name,int entries); + ~TimeStampArray(); + + + int insertTimeStamp(TimeStamp* src,long key,int len); + TimeStamp* getReadTimeStamp(); + TimeStamp* getTimeStamp(long key); + int getFillgrade(); + void forward(); + void clear(); + + int bytesUntilNext(long key); + + private: + void lockStampArray(); + void unlockStampArray(); + void internalForward(); + + + +}; +#endif + diff --git a/mpeglib/lib/util/timeWrapper.cpp b/mpeglib/lib/util/timeWrapper.cpp new file mode 100644 index 00000000..adf87681 --- /dev/null +++ b/mpeglib/lib/util/timeWrapper.cpp @@ -0,0 +1,77 @@ +/* + wrapps calls to usleep, gettimeofday,... + 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 "timeWrapper.h" + +#if defined WIN32 +// usec goes from 0 -> 1000000 (one Million) under Unix +int gettimeofday(struct timeval *tv, struct timezone *tz) { + if(tv) { + struct _timeb tb; + _ftime(&tb); + tv->tv_sec=tb.time; + tv->tv_usec=1000*tb.millitm; + } + return(0); +} + +void abs_usleep(const timeval* tm) { + _sleep((tm->tv_usec / 1000) + (tm->tv_sec * 1000)); +} +#endif + +#ifndef WIN32 + +void abs_usleep(struct timeval* tm) { + select(0,NULL,NULL,NULL,tm); +} + +#endif + +TimeWrapper::TimeWrapper() { +} + + +TimeWrapper::~TimeWrapper() { +} + +void TimeWrapper::sleep(int sec) { + timeval_t time; + time.tv_sec=sec; + time.tv_usec=0; + TimeWrapper::usleep(&time); +} + +void TimeWrapper::usleep(unsigned long usec) { + timeval_t time; + time.tv_sec=0; + time.tv_usec=usec; + TimeWrapper::usleep(&time); +} + +void TimeWrapper::usleep(timeval_t* time) { + struct timeval waitTime; + waitTime.tv_sec=time->tv_sec; + waitTime.tv_usec=time->tv_usec; + /*Threads and usleep does not work, select is very portable*/ + ::abs_usleep(&waitTime); +} + + +void TimeWrapper::gettimeofday(timeval_t* time) { + struct timeval waitTime; + ::gettimeofday(&waitTime,NULL); + time->tv_sec=waitTime.tv_sec; + time->tv_usec=waitTime.tv_usec; +} diff --git a/mpeglib/lib/util/timeWrapper.h b/mpeglib/lib/util/timeWrapper.h new file mode 100644 index 00000000..608d5bd0 --- /dev/null +++ b/mpeglib/lib/util/timeWrapper.h @@ -0,0 +1,44 @@ +/* + wrapps calls to usleep, gettimeofday,... + 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 __TIMEWRAPPER_H +#define __TIMEWRAPPER_H + +#if defined WIN32 +#include <winsock.h> +#include <sys/timeb.h> +#else +#include <unistd.h> +#include <sys/time.h> +#include <strings.h> +#endif + +#include <kdemacros.h> + +typedef struct timeval_s { + long tv_sec; /* seconds */ + long tv_usec; /* microseconds */ +} timeval_t; + +class KDE_EXPORT TimeWrapper { + + public: + TimeWrapper(); + ~TimeWrapper(); + static void sleep(int sec); + static void usleep(unsigned long usec); + static void usleep(timeval_t* time); + static void gettimeofday(timeval_t* time); + +}; +#endif diff --git a/mpeglib/lib/yuv/Makefile.am b/mpeglib/lib/yuv/Makefile.am new file mode 100644 index 00000000..b8d7155d --- /dev/null +++ b/mpeglib/lib/yuv/Makefile.am @@ -0,0 +1,28 @@ +# libplayerplugin - Makefile.am + +INCLUDES = $(all_includes) + +noinst_LTLIBRARIES = libyuvPlugin.la + + +noinst_HEADERS = + +kmpgincludedir = $(includedir)/$(THIS_LIB_NAME)/decoder + +kmpginclude_HEADERS = yuvPlugin.h + +libyuvPlugin_la_SOURCES = yuvPlugin.cpp + + + + + + + + + + + + + + diff --git a/mpeglib/lib/yuv/yuvPlugin.cpp b/mpeglib/lib/yuv/yuvPlugin.cpp new file mode 100644 index 00000000..94697aa8 --- /dev/null +++ b/mpeglib/lib/yuv/yuvPlugin.cpp @@ -0,0 +1,158 @@ +/* + raw yuv stream player + 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 "yuvPlugin.h" + +#include <iostream> + +using namespace std; + + +YUVPlugin::YUVPlugin() { + init(); +} + + +YUVPlugin::~YUVPlugin() { +} + + +void YUVPlugin::init() { + lCalcLength=false; + nWidth=0; + nHeight=0; + imageType=PICTURE_YUVMODE_CR_CB; + picPerSec=1.0; +} + + +void YUVPlugin::decoder_loop() { + + + + cout << "YUVPlugin::decoder_loop() 1"<<endl; + if (input == NULL) { + cout << "YUVPlugin::decoder_loop input is NULL"<<endl; + exit(0); + } + if (output == NULL) { + cout << "YUVPlugin::decoder_loop output is NULL"<<endl; + exit(0); + } + + + PictureArray* pictureArray; + + + int bytes=nWidth*nHeight; + + if ( (imageType == PICTURE_YUVMODE_CR_CB) || + (imageType == PICTURE_YUVMODE_CB_CR) ) { + bytes=bytes+bytes/2; + } + if ( (imageType == PICTURE_RGB) || + (imageType == PICTURE_RGB_FLIPPED) ) { + bytes=bytes*4; + } + + + + + // decode loop + while(runCheck()) { + switch(streamState) { + case _STREAM_STATE_FIRST_INIT : + output->openWindow(nWidth,nHeight,(char*)"yuv Viewer"); + pictureArray=output->lockPictureArray(); + cout << "pictureArray->setImageType"<<endl; + pictureArray->setImageType(imageType); + + setStreamState(_STREAM_STATE_INIT); + break; + case _STREAM_STATE_INIT : + setStreamState(_STREAM_STATE_PLAY); + break; + case _STREAM_STATE_PLAY : { + // we read from input raw yuv bytes + // and display them. + pictureArray=output->lockPictureArray(); + // now we have the color info + YUVPicture* pic=pictureArray->getPast(); + unsigned char* dest=pic->getImagePtr(); + input->read((char*)dest,bytes); + pic->setPicturePerSecond(picPerSec); + // now inform subsystem about the frame to display + pictureArray->setYUVPictureCallback(pic); + // display it + output->unlockPictureArray(pictureArray); + + pictureArray->setYUVPictureCallback(NULL); + break; + } + case _STREAM_STATE_WAIT_FOR_END: + // exit while loop + lDecoderLoop=false; + cout << "mpegplugin _STREAM_STATE_WAIT_FOR_END"<<endl; + break; + default: + cout << "unknown stream state:"<<streamState<<endl; + } + } + + cout << "*********mpegPLugin exit"<<endl; + + output->flushWindow(); + // copy sequence back if needed + + cout << "delete mpegVideoStream"<<endl; + +} + + + + + +// here we can config our decoder with special flags +void YUVPlugin::config(const char* key,const char* value,void* user_data) { + if (strcmp(key,"-c")==0) { + lCalcLength=false; + } + + if (strcmp(key,"height")==0) { + nHeight=atoi(value); + } + if (strcmp(key,"width")==0) { + nWidth=atoi(value); + } + if (strcmp(key,"imageType")==0) { + imageType=atoi(value); + cout << "imageType:"<<imageType<<endl; + } + if (strcmp(key,"picPerSec")==0) { + picPerSec=atoi(value); + } + DecoderPlugin::config(key,value,user_data); +} + + + +int YUVPlugin::getSongLength() { + int back=0; + return back; +} + + + + + + diff --git a/mpeglib/lib/yuv/yuvPlugin.h b/mpeglib/lib/yuv/yuvPlugin.h new file mode 100644 index 00000000..4a5dc72b --- /dev/null +++ b/mpeglib/lib/yuv/yuvPlugin.h @@ -0,0 +1,47 @@ +/* + raw yuv stream player + 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 __YUVPLUGIN_H +#define __YUVPLUGIN_H + +#include "../decoder/decoderPlugin.h" +#include <kdemacros.h> + +class KDE_EXPORT YUVPlugin : public DecoderPlugin { + + int lCalcLength; + int nWidth; + int nHeight; + int imageType; + float picPerSec; + + public: + YUVPlugin(); + ~YUVPlugin(); + + void decoder_loop(); + void config(const char* key,const char* value,void* user_data); + + + private: + void init(); + + int getSongLength(); + + +}; + +#endif |