diff options
Diffstat (limited to 'mpeglib/lib/util')
98 files changed, 14401 insertions, 0 deletions
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 |