aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoraugust black <augmentus@users.sourceforge.net>2010-07-28 09:14:17 +0000
committerIOhannes m zmölnig <zmoelnig@iem.at>2015-10-14 15:05:31 +0200
commit6dec07e785db93ea9d2702b660b885d678dc87e4 (patch)
tree266817a13947e0b712e6d36dbf03339acd7e7b7c
parent0f5d5d1a8a13c2bf08030e9569337ce2bc5cb789 (diff)
adding the readanysf~ again
svn path=/trunk/externals/august/readanysf~/; revision=13732
-rw-r--r--Makefile79
-rw-r--r--README13
-rw-r--r--READMEmacpkg.txt11
-rwxr-xr-xembed-MacOSX-dependencies.sh2
-rw-r--r--readanysf~-help.pd6
-rw-r--r--screengrab0.40.pngbin0 -> 31276 bytes
-rw-r--r--src/FifoAudioFrames.cpp140
-rw-r--r--src/FifoAudioFrames.h41
-rw-r--r--src/FifoVideoFrames.cpp120
-rw-r--r--src/FifoVideoFrames.h43
-rw-r--r--src/ReadMedia.cpp1132
-rw-r--r--src/ReadMedia.h220
-rw-r--r--src/readanysf~.cpp507
-rw-r--r--stress.pd53
14 files changed, 2342 insertions, 25 deletions
diff --git a/Makefile b/Makefile
index d306b87..416b6f9 100644
--- a/Makefile
+++ b/Makefile
@@ -4,6 +4,19 @@
GAVLPATH=/usr/local/include
PDPATH=/usr/local/include
+
+VERSION=0.40
+UNAME := $(shell uname)
+
+ifeq ($(UNAME), Linux)
+TARGET=pd_linux
+else
+# assume darwin here
+GAVLPATH=/sw/include
+PDPATH=/Applications/Pd-extended.app/Contents/Resources/include/
+TARGET=pd_darwin
+endif
+
##############################################
LBITS := $(shell getconf LONG_BIT)
ifeq ($(LBITS),64)
@@ -14,27 +27,67 @@ else
CFLAGS = -I./ -I$(GAVLPATH) -I$(GAVLPATH)/gavl -I$(GAVLPATH)/gmerlin -I$(PDPATH) -Wall
endif
+
+ifeq ($(UNAME), Linux)
+STRIP=strip --strip-unneeded
+# optimizations?
+#CFLAGS += -O1 -funroll-loops -fomit-frame-pointer \
+# -Wall -W -Wshadow \
+# -Wno-unused -Wno-parentheses -Wno-switch
LDFLAGS = -L/usr/local/lib -lpthread -lgavl -lgmerlin_avdec
+else
+# assume darwin here
+STRIP=strip -x
+CFLAGS += -I/sw/include -I$(externals_src)/pdp/include -DMACOSX -DUNIX -Dunix
+#LDFLAGS += -bundle -bundle_loader $(pd_src)/bin/pd -undefined dynamic_lookup \
+# -L/sw/lib -weak_framework Carbon -lc -L/sw/lib -lgavl -lgmerlin_avdec
+LDFLAGS = -dynamiclib -undefined dynamic_lookup -read_only_relocs warning -L/sw/lib -lgavl -lgmerlin_avdec
+# os 10.4
+#CFLAGS += -mmacosx-version-min=10.4 -arch i386 -isysroot /Developer/SDKs/MacOSX10.4u.sdk
+#LDFLAGS = -L/sw/lib -lgavl -lgmerlin_avdec \
+# -dynamiclib -undefined dynamic_lookup -lsupc++ -mmacosx-version-min=10.4 \
+# -lSystem.B -arch i386 -isysroot /Developer/SDKs/MacOSX10.4u.sdk
+endif
+
-LINUXCFLAGS = -O1 -funroll-loops -fomit-frame-pointer \
- -Wall -W -Wshadow -Wstrict-prototypes \
- -Wno-unused -Wno-parentheses -Wno-switch
-all: pd_linux
+all: $(TARGET)
-pd_linux: readanysf~.cpp Readsf.cpp Readsf.h objs/FifoAudioFrames.o objs/Readsf.o FifoAudioFrames.h FifoAudioFrames.cpp
+pd_linux: src/readanysf~.cpp objs/FifoVideoFrames.o objs/FifoAudioFrames.o objs/ReadMedia.o
g++ -shared -o readanysf~.pd_linux $(CFLAGS) $(LDFLAGS) \
- readanysf~.cpp \
+ src/readanysf~.cpp \
objs/FifoAudioFrames.o \
- objs/Readsf.o
- strip --strip-unneeded readanysf~.pd_linux
+ objs/FifoVideoFrames.o \
+ objs/ReadMedia.o
+ $(STRIP) readanysf~.pd_linux
+
+pd_darwin: src/readanysf~.cpp objs/FifoVideoFrames.o objs/FifoAudioFrames.o objs/ReadMedia.o
+ g++ $(LDFLAGS) -o readanysf~.pd_darwin $(CFLAGS) \
+ src/readanysf~.cpp \
+ objs/FifoAudioFrames.o \
+ objs/FifoVideoFrames.o \
+ objs/ReadMedia.o
+ $(STRIP) readanysf~.pd_darwin
+ mkdir -p readanysf~$(VERSION)_MacOSX-Intel
+ mkdir -p readanysf~$(VERSION)_MacOSX-Intel/readanysf~
+ cp readanysf~.pd_darwin readanysf~-help.pd readanysf~$(VERSION)_MacOSX-Intel/readanysf~
+ cp READMEmacpkg.txt anysndfiler.pd readanysf~$(VERSION)_MacOSX-Intel/
+ mv readanysf~$(VERSION)_MacOSX-Intel/READMEmacpkg.txt readanysf~$(VERSION)_MacOSX-Intel/README.txt
+ ./embed-MacOSX-dependencies.sh readanysf~$(VERSION)_MacOSX-Intel/readanysf~
+ tar -cvf readanysf~$(VERSION)_MacOSX-Intel.tar readanysf~$(VERSION)_MacOSX-Intel/
+ gzip readanysf~$(VERSION)_MacOSX-Intel.tar
+
+objs/ReadMedia.o: src/ReadMedia.cpp src/ReadMedia.h objs/FifoAudioFrames.o objs/FifoVideoFrames.o
+ g++ -c -o objs/ReadMedia.o src/ReadMedia.cpp $(CFLAGS)
-objs/Readsf.o: Readsf.cpp Readsf.h FifoAudioFrames.h
- g++ -c -o objs/Readsf.o Readsf.cpp $(CFLAGS)
+objs/FifoAudioFrames.o: src/FifoAudioFrames.cpp src/FifoAudioFrames.h
+ g++ -c -o objs/FifoAudioFrames.o src/FifoAudioFrames.cpp $(CFLAGS)
-objs/FifoAudioFrames.o: FifoAudioFrames.cpp FifoAudioFrames.h
- g++ -c -o objs/FifoAudioFrames.o FifoAudioFrames.cpp $(CFLAGS)
+objs/FifoVideoFrames.o: src/FifoVideoFrames.cpp src/FifoVideoFrames.h
+ g++ -c -o objs/FifoVideoFrames.o src/FifoVideoFrames.cpp $(CFLAGS)
clean:
- rm objs/*.o readanysf~.pd_linux readanysf~.pd_darwin
+ if [ -d readanysf~$(VERSION)_MacOSX-Intel ]; then rm -rf readanysf~$(VERSION)_MacOSX-Intel; fi;
+ if [ -f readanysf~$(VERSION)_MacOSX-Intel.tar.gz ]; then rm -rf readanysf~$(VERSION)_MacOSX-Intel.tar.gz; fi;
+ rm -f objs/*.o readanysf~.pd_*
diff --git a/README b/README
index 7af1c8d..3d7118b 100644
--- a/README
+++ b/README
@@ -1,6 +1,6 @@
readanysf~, a puredata external for reading multiple file formats.
-----------------------------------------------------------------
-© august black 2003 - 2009
+© august black 2003 - 2010
licensed under the GNU GPL v2
@@ -31,8 +31,7 @@ you will need:
sudo make install
-If you didn't change anything in the ./configure of gavl or gmerlin, AND your PD header files are in /usr/local/include you can just type make. Otherwise, open the Makefile with your favorite text editor and change the first two variables to suit your system.
-
+After installing gavl and gmerlin_avdecode, you should just be able to type make.
----------------------------------------------------------------------------------------
@@ -40,15 +39,9 @@ Mac users:
you can install gavl/gmerlin-avdecoder either by source as above with linux or through fink.
- then, first try "make -f Makefile.darwin"
-
+ then, do "make" and let me know if it doesn't work
- If that doesn't work ...then, if you have a i386 machine with Mac OS.X 10.4 or greater, do:
-
- export LIBRARY_PATH=/sw/lib:$LIBRARY_PATH; make -f Makefile.darwin_i386_10.4
-
- I don't have a mac...so I can't tell what is going on there.
diff --git a/READMEmacpkg.txt b/READMEmacpkg.txt
new file mode 100644
index 0000000..2e43e2a
--- /dev/null
+++ b/READMEmacpkg.txt
@@ -0,0 +1,11 @@
+
+http://aug.ment.org/readanysf/
+
+by August Black
+
+--
+To install, drag the readanysf~ folder and anysndfiler.pd to /Library/Pd. Then you can create [readanysf~] anywhere you need it.
+
+If /Library/Pd does not exist, just create it.
+
+This build put together by Hans-Christoph Steiner, post to the pd-list with questions.
diff --git a/embed-MacOSX-dependencies.sh b/embed-MacOSX-dependencies.sh
index f8275a4..0612b0c 100755
--- a/embed-MacOSX-dependencies.sh
+++ b/embed-MacOSX-dependencies.sh
@@ -5,7 +5,7 @@
# <hans@at.or.at>
LIB_DIR=/Library/Pd/readanysf~
-PD_APP_LIB=.
+PD_APP_LIB=$1
echo " "
diff --git a/readanysf~-help.pd b/readanysf~-help.pd
index 1920cd0..506d1b1 100644
--- a/readanysf~-help.pd
+++ b/readanysf~-help.pd
@@ -3,7 +3,7 @@
#X obj 28 321 *~ 0;
#X obj 69 321 *~ 0;
#X obj 579 94 vsl 15 50 0.01 1.3 1 0 empty empty empty 0 -8 0 8 -241291
--1 -1 4411 0;
+-1 -1 4300 0;
#X msg 112 104 play;
#X msg 193 103 pause;
#X msg 276 109 speed \$1;
@@ -68,6 +68,8 @@ blocksize.;
#X text 332 219 send cache \, length output every X ticks;
#X text 330 232 "tick 1" sends out every single dsp cycle;
#X text 648 202 loop on/off;
+#X floatatom 75 502 0 0 0 0 - - -;
+#X obj 75 439 env~ 16384 8192;
#X connect 1 0 0 0;
#X connect 2 0 0 1;
#X connect 3 0 11 0;
@@ -111,3 +113,5 @@ blocksize.;
#X connect 53 0 52 0;
#X connect 54 0 44 0;
#X connect 55 0 44 0;
+#X connect 60 0 59 0;
+#X connect 60 0 59 0;
diff --git a/screengrab0.40.png b/screengrab0.40.png
new file mode 100644
index 0000000..a83017b
--- /dev/null
+++ b/screengrab0.40.png
Binary files differ
diff --git a/src/FifoAudioFrames.cpp b/src/FifoAudioFrames.cpp
new file mode 100644
index 0000000..a3bc682
--- /dev/null
+++ b/src/FifoAudioFrames.cpp
@@ -0,0 +1,140 @@
+#include "FifoAudioFrames.h"
+
+/*
+#define RESET 0
+#define BRIGHT 1
+#define DIM 2
+#define UNDERLINE 3
+#define BLINK 4
+#define REVERSE 7
+#define HIDDEN 8
+
+#define BLACK 0
+#define RED 1
+#define GREEN 2
+#define YELLOW 3
+#define BLUE 4
+#define MAGENTA 5
+#define CYAN 6
+#define WHITE 7
+void textcolor(int attr, int fg, int bg) {
+ char command[13];
+ // Command is the control command to the terminal
+ sprintf(command, "%c[%d;%d;%dm", 0x1B, attr, fg + 30, bg + 40);
+ printf("%s", command);
+}
+*/
+
+
+FifoAudioFrames::FifoAudioFrames(int s, gavl_audio_format_t * f) {
+ size = s ;
+ start = 0 ;
+ end = 0 ;
+ count = 0;
+ format = new gavl_audio_format_t;
+ gavl_audio_format_copy(format, f);
+ fifoPtr = new gavl_audio_frame_t * [size] ;
+ for(int i=0; i < size; i++) {
+ fifoPtr[i] = gavl_audio_frame_create( format );
+ }
+ pthread_mutex_init (&mut, 0);
+ //printf("FifoAudioFrames::size=%d\n", size);
+}
+
+FifoAudioFrames::~FifoAudioFrames() {
+ //printf("deleting fifo \n");
+ for(int i=0; i < size; i++) {
+ gavl_audio_frame_destroy( fifoPtr[i] );
+ }
+ delete format;
+ delete[] fifoPtr;
+
+ pthread_mutex_destroy (&mut);
+ //printf("deleted fifo \n");
+}
+
+// empty the fifo of any content
+void FifoAudioFrames::Flush() {
+ pthread_mutex_lock (&mut);
+ start = 0 ;
+ end = 0 ;
+ count = 0;
+ //printf("FifoAudioFrames::flushed size=%d\n", count);
+ pthread_mutex_unlock (&mut);
+}
+
+// push an element onto the FifoAudioFrames
+bool FifoAudioFrames::Append( gavl_audio_frame_t * source) {
+ bool ret = false;
+ //Dump("Appending a frame ");
+ pthread_mutex_lock (&mut);
+ if ( count < size ) { // if there is room for one more
+ int vs = gavl_audio_frame_copy(format, fifoPtr[end], source, 0,0, format->samples_per_frame, format->samples_per_frame) ;
+ fifoPtr[end]->timestamp = source->timestamp;
+ fifoPtr[end]->valid_samples =vs;
+ if (++end >= size)
+ end = 0;
+ count++;
+ ret = true;
+ } // no room in fifo, return false
+ pthread_mutex_unlock (&mut);
+ //Dump("Appended a frame ");
+ return ret;
+}
+
+// get an element off the FifoAudioFrames
+bool FifoAudioFrames::Get( gavl_audio_frame_t * dest) {
+ bool ret = false;
+ //Dump("Getting a frame ");
+ pthread_mutex_lock (&mut);
+ if ( count > 0 ) { // if there any items in the fifo
+ int vs = gavl_audio_frame_copy(format, dest, fifoPtr[start], 0, 0, format->samples_per_frame, format->samples_per_frame) ;
+ dest->timestamp = fifoPtr[start]->timestamp;
+ dest->valid_samples = vs;
+ if ( ++start >= size )
+ start = 0;
+ count--;
+ ret = true;
+ }
+ pthread_mutex_unlock (&mut);
+ //Dump("Got a frame ");
+ return ret;
+}
+/*
+void FifoAudioFrames::Dump( char * c) {
+ int i,j = 0;
+ pthread_mutex_lock (&mut);
+ printf("%s -----------------------\n", c);
+ for( i=0;i<size;i++) {
+ //j=start+i;
+ //if (j >= size)
+ // j = j -size;
+ j=i;
+ if ( j == start)
+ textcolor(BRIGHT, GREEN, BLACK);
+ if (j == end)
+ textcolor(BRIGHT, RED, BLACK);
+ if (j == end && j == start)
+ textcolor(BRIGHT, YELLOW, BLACK);
+ printf("[%d]=%ld ", j, fifoPtr[j]->timestamp);
+ textcolor(RESET, BLACK, WHITE);
+ }
+ printf("\n");
+ printf("start=%02d, end=%02d, count=%02d\n", start,end,count);
+ printf("-----------------------\n");
+ pthread_mutex_unlock (&mut);
+}
+*/
+bool FifoAudioFrames::FreeSpace() {
+ bool ret = false;
+ //printf("asking for free space on audio fifo\n");
+ pthread_mutex_lock(&mut);
+ ret = (count < size);
+ pthread_mutex_unlock (&mut);
+ return ret;
+}
+bool FifoAudioFrames::isEmpty() { bool c; pthread_mutex_lock(&mut); c = (count == 0) ; pthread_mutex_unlock (&mut); return c; }
+bool FifoAudioFrames::isFull() { bool c; pthread_mutex_lock(&mut); c = (count == size ); pthread_mutex_unlock (&mut); return c; }
+gavl_audio_format_t * FifoAudioFrames::getFormat() { return format; };
+float FifoAudioFrames::getSizePercentage() { float ret; pthread_mutex_lock(&mut);ret = count / (float) size; pthread_mutex_unlock (&mut); return ret;};
+
diff --git a/src/FifoAudioFrames.h b/src/FifoAudioFrames.h
new file mode 100644
index 0000000..eea7a66
--- /dev/null
+++ b/src/FifoAudioFrames.h
@@ -0,0 +1,41 @@
+#ifndef _FIFOAUDIOFRAMES_H_
+#define _FIFOAUDIOFRAMES_H_
+
+#include <string.h> // memcpy
+#include <stdio.h>
+#include <pthread.h>
+
+#ifndef _AVDEC_H_
+#define _AVDEC_H_
+extern "C" {
+#include <gmerlin/avdec.h>
+}
+#endif
+
+class FifoAudioFrames {
+ public:
+ FifoAudioFrames(int s, gavl_audio_format_t * format) ;
+ ~FifoAudioFrames();// { delete [] fifoPtr; }
+ bool Append( gavl_audio_frame_t * af);
+ bool Get( gavl_audio_frame_t * af) ; // pop an element off the fifo
+ void Flush();
+ //void Dump(char *c);
+ bool FreeSpace();
+ bool isEmpty();
+ bool isFull();
+ void setDebug( bool b);
+ gavl_audio_format_t * getFormat();
+ float getSizePercentage();
+ private:
+ int size ; // Number of elements on FifoAudioFrames
+ int start ;
+ int end ;
+ int count;
+ gavl_audio_frame_t ** fifoPtr ;
+ gavl_audio_format_t * format;
+ pthread_mutex_t mut;
+} ;
+
+
+#endif
+
diff --git a/src/FifoVideoFrames.cpp b/src/FifoVideoFrames.cpp
new file mode 100644
index 0000000..29975dc
--- /dev/null
+++ b/src/FifoVideoFrames.cpp
@@ -0,0 +1,120 @@
+#include "FifoVideoFrames.h"
+
+FifoVideoFrames::FifoVideoFrames(int s, gavl_video_format_t * f) {
+ size = s ;
+ start = 0 ;
+ end = 0 ;
+ count = 0;
+ format = new gavl_video_format_t;
+ gavl_video_format_copy(format, f);
+ fifoPtr = new gavl_video_frame_t * [size] ;
+ for(int i=0; i < size; i++) {
+ fifoPtr[i] = gavl_video_frame_create( format );
+ }
+ pthread_mutex_init (&mut, 0);
+}
+
+FifoVideoFrames::~FifoVideoFrames() {
+ //printf("deleting fifo \n");
+ for(int i=0; i < size; i++) {
+ gavl_video_frame_destroy( fifoPtr[i] );
+ }
+ delete format;
+ delete[] fifoPtr;
+ pthread_mutex_destroy (&mut);
+ //printf("deleted fifo \n");
+}
+
+// empty the fifo of any content
+void FifoVideoFrames::Flush() {
+ pthread_mutex_lock (&mut);
+ start = 0 ;
+ end = 0 ;
+ count = 0;
+ //printf("FifoVideoFrames::flushed size=%d\n", count);
+ pthread_mutex_unlock (&mut);
+}
+
+// push an element onto the FifoVideoFrames
+bool FifoVideoFrames::Append( gavl_video_frame_t * source) {
+ bool ret = false;
+ //Dump("Appending a frame ");
+ pthread_mutex_lock (&mut);
+ if ( count < size ) { // if there is room for one more
+ gavl_video_frame_copy(format, fifoPtr[end], source) ;
+ fifoPtr[end]->timestamp = source->timestamp;
+ fifoPtr[end]->duration = source->duration;
+ if (++end >= size)
+ end = 0;
+ count++;
+ ret = true;
+ } // no room in fifo, return false
+ pthread_mutex_unlock (&mut);
+ //Dump("Appended a frame ");
+ return ret;
+}
+// remove an element off the front FifoVideoFrames
+bool FifoVideoFrames::Get( ) {
+ bool ret = false;
+ pthread_mutex_lock (&mut);
+ if ( count > 0 ) { // if there any items in the fifo
+ if ( ++start >= size )
+ start = 0;
+ count--;
+ ret = true;
+ }
+ pthread_mutex_unlock (&mut);
+ //Dump("Got a frame ");
+ return ret;
+}
+
+// get an element off the FifoVideoFrames
+bool FifoVideoFrames::Get( gavl_video_frame_t * dest) {
+ bool ret = false;
+ //Dump("Getting a frame ");
+ pthread_mutex_lock (&mut);
+ if ( count > 0 ) { // if there any items in the fifo
+ gavl_video_frame_copy(format, dest, fifoPtr[start]) ;
+ dest->timestamp = fifoPtr[start]->timestamp;
+ dest->duration = fifoPtr[start]->duration;
+ if ( ++start >= size )
+ start = 0;
+ count--;
+ ret = true;
+ }
+ pthread_mutex_unlock (&mut);
+ //Dump("Got a frame ");
+ return ret;
+}
+/*
+void FifoVideoFrames::Dump( char * c) {
+ int i,j = 0;
+ pthread_mutex_lock (&mut);
+ printf("%s -----------------------\n", c);
+ for( i=0;i<size;i++) {
+ //j=start+i;
+ //if (j >= size)
+ // j = j -size;
+ j=i;
+ if ( j == start)
+ textcolor(BRIGHT, GREEN, BLACK);
+ if (j == end)
+ textcolor(BRIGHT, RED, BLACK);
+ if (j == end && j == start)
+ textcolor(BRIGHT, YELLOW, BLACK);
+ printf("[%d]=%ld ", j, fifoPtr[j]->timestamp);
+ textcolor(RESET, BLACK, WHITE);
+ }
+ printf("\n");
+ printf("start=%02d, end=%02d, count=%02d\n", start,end,count);
+ printf("-----------------------\n");
+ pthread_mutex_unlock (&mut);
+}
+*/
+bool FifoVideoFrames::FreeSpace() { bool ret; pthread_mutex_lock(&mut); ret = (count < size);pthread_mutex_unlock (&mut); return ret;}
+bool FifoVideoFrames::isEmpty() { bool c; pthread_mutex_lock(&mut); c = (count == 0) ; pthread_mutex_unlock (&mut); return c; }
+bool FifoVideoFrames::isFull() { bool c; pthread_mutex_lock(&mut); c = (count == size ); pthread_mutex_unlock (&mut); return c; }
+gavl_video_format_t * FifoVideoFrames::getFormat() { return format; };
+float FifoVideoFrames::getSizePercentage() { float ret; pthread_mutex_lock(&mut);ret = count / (float) size; pthread_mutex_unlock (&mut); return ret;};
+int FifoVideoFrames::getSize() { int ret; pthread_mutex_lock(&mut);ret = count; pthread_mutex_unlock (&mut); return ret;};
+
diff --git a/src/FifoVideoFrames.h b/src/FifoVideoFrames.h
new file mode 100644
index 0000000..ee5beba
--- /dev/null
+++ b/src/FifoVideoFrames.h
@@ -0,0 +1,43 @@
+#ifndef _FIFOVIDEOFRAMES_H_
+#define _FIFOVIDEOFRAMES_H_
+
+#include <string.h> // memcpy
+#include <stdio.h>
+#include <pthread.h>
+
+#ifndef _AVDEC_H_
+#define _AVDEC_H_
+extern "C" {
+#include <gmerlin/avdec.h>
+}
+#endif
+
+class FifoVideoFrames {
+ public:
+ FifoVideoFrames(int s, gavl_video_format_t * format) ;
+ ~FifoVideoFrames();// { delete [] fifoPtr; }
+ bool Append( gavl_video_frame_t * af);
+ bool Get( gavl_video_frame_t * af) ; // pop an element off the fifo
+ bool Get( ) ; // discard an element off the fifo
+ void Flush();
+ //void Dump(char *c);
+ bool FreeSpace();
+ bool isEmpty();
+ bool isFull();
+ void setDebug( bool b);
+ gavl_video_format_t * getFormat();
+ int getSize();
+ float getSizePercentage();
+ private:
+ int size ; // Number of elements on FifoVideoFrames
+ int start ;
+ int end ;
+ int count;
+ gavl_video_frame_t ** fifoPtr ;
+ gavl_video_format_t * format;
+ pthread_mutex_t mut;
+} ;
+
+
+#endif
+
diff --git a/src/ReadMedia.cpp b/src/ReadMedia.cpp
new file mode 100644
index 0000000..f109da7
--- /dev/null
+++ b/src/ReadMedia.cpp
@@ -0,0 +1,1132 @@
+#include "ReadMedia.h"
+#include <pthread.h>
+#include <unistd.h> //usleep
+
+
+static void *the_thread_dispatcher(void * xp);
+static void *the_thread_opener(void * xp);
+static void *the_audiofifo_filler(void * xp);
+static void *the_videofifo_filler(void * xp);
+
+
+ReadMedia::ReadMedia( ) {
+
+ m_state = STATE_EMPTY;
+
+ m_audio_frame = NULL;
+ m_video_frame = NULL;
+ m_aeof = false;
+ m_veof = false;
+ m_atime = 0.0;
+ m_vtime = 0.0;
+ m_video_stream_count =0;
+ m_audio_stream_count =0;
+
+ m_pcm_seek = -1;
+ m_frame_seek = -1;
+ m_length_in_seconds=0.0;
+ m_num_frames=0;
+ m_num_samples=0;
+
+ m_video_format.frame_width=0;
+ m_video_format.frame_height=0;
+ m_video_format.image_width=0;
+ m_video_format.image_height=0;
+ m_video_format.pixel_width=0;
+ m_video_format.pixel_height=0;
+ m_video_format.pixelformat = GAVL_PIXELFORMAT_NONE ;
+ m_video_format.frame_duration=0;
+ m_video_format.timescale=0;
+ m_video_format.framerate_mode=GAVL_FRAMERATE_CONSTANT;
+ m_video_format.chroma_placement=GAVL_CHROMA_PLACEMENT_DEFAULT;
+ //m_video_format.interlace_mode=GAVL_INTERLACE_UNKNOWN;
+ m_video_format.timecode_format.int_framerate =0;
+ m_video_format.timecode_format.flags =0;
+
+ m_audio_format.samples_per_frame = 0;
+ m_audio_format.samplerate = 0;
+ m_audio_format.num_channels = 0;
+ m_audio_format.sample_format = GAVL_SAMPLE_NONE ;
+ m_audio_format.interleave_mode = GAVL_INTERLEAVE_NONE;
+ m_audio_format.center_level = 1.0;
+ m_audio_format.rear_level = 1.0;
+ m_audio_format.channel_locations[0] = GAVL_CHID_NONE; // Reset
+
+
+ m_fifoaudio= NULL; // new FifoAudioFrames( frames_in_fifo , &tmp_audio_lormat);
+ m_fifovideo= NULL; // new FifoVideoFrames( 12 , &output_video_format);
+ m_audio_thread_ret = -1;
+ m_video_thread_ret = -1;
+
+ m_open_callback = NULL;
+ m_open_callback_data = NULL;
+ m_buffer_callback = NULL;
+ m_buffer_callback_data = NULL;
+
+ quit_av_threads = false;
+ m_loop = false;
+
+ sprintf(m_filename, "seinettbitte!");
+
+ //bgav stuff
+ m_file = NULL;
+ m_opt = bgav_options_create();
+
+ bgav_options_set_connect_timeout(m_opt, 5000);
+ bgav_options_set_read_timeout(m_opt, 5000);
+ bgav_options_set_network_bandwidth(m_opt, 524300);
+ bgav_options_set_network_buffer_size(m_opt, 1024*12);
+ bgav_options_set_http_shoutcast_metadata (m_opt, 1);
+ // set up the reading so that we can seek sample accurately
+ bgav_options_set_sample_accurate (m_opt, 1 );
+
+
+ pthread_cond_init(&m_cond_dispatch, 0);
+ pthread_mutex_init(&m_condmut_dispatch, 0);
+
+ pthread_cond_init(&m_cond_a, 0);
+ pthread_cond_init(&m_cond_v, 0);
+ pthread_mutex_init(&m_condmut_a, 0);
+ pthread_mutex_init(&m_condmut_v, 0);
+
+ pthread_mutex_init(&m_av_mut, 0);
+ pthread_mutex_init(&m_state_mut, 0);
+
+ // start the dispatcher thread
+ m_cmd = CMD_START;
+ m_dispatcher_thread_ret = pthread_create(&m_thread_dispatch, NULL, the_thread_dispatcher, (void *)this) ;
+ if (m_dispatcher_thread_ret != 0 )
+ printf("error starting the readmedia dispatcher thread.\n");
+
+ while( getCommand() != CMD_NULL)
+ signalDispatcher();
+ //printf("dispatcher ready ...\n");
+}
+
+ReadMedia::~ReadMedia() {
+ printf("killing the media..\n");
+ setCommand( CMD_QUIT );
+ signalDispatcher();
+
+
+ // signal dispatcher joins the opener and AV threads
+ pthread_join( m_thread_dispatch, NULL);
+
+ //printf("joined dispatcher\n");
+ if (m_audio_frame != NULL) {
+ gavl_audio_frame_destroy(m_audio_frame);
+ }
+ if (m_video_frame != NULL) {
+ gavl_video_frame_destroy(m_video_frame);
+ }
+ if (m_file != NULL) {
+ bgav_close(m_file);
+ }
+
+ //printf("now, on to deleting fifo...\n");
+ if( m_fifoaudio != NULL) delete m_fifoaudio;
+ if( m_fifovideo != NULL) delete m_fifovideo;
+
+ // these are created only once
+ bgav_options_destroy(m_opt);
+
+ pthread_cond_destroy(&m_cond_dispatch);
+ pthread_mutex_destroy(&m_condmut_dispatch);
+
+ pthread_cond_destroy(&m_cond_a);
+ pthread_cond_destroy(&m_cond_v);
+ pthread_mutex_destroy(&m_condmut_a);
+ pthread_mutex_destroy(&m_condmut_v);
+
+ pthread_mutex_destroy(&m_av_mut);
+ pthread_mutex_destroy(&m_state_mut);
+
+ printf("killed the media..\n");
+}
+
+int ReadMedia::decodeVideo( gavl_video_frame_t * vf ) {
+
+ // check state first, if state is ready, we can check the other vars without locking
+ lockState();
+ if (m_state != STATE_READY || m_video_stream_count < 1 || m_fifovideo == NULL ) {
+ unlockState();
+ return -1;
+ }
+
+ if (!m_fifovideo->Get( vf ) ) {
+ if ( m_veof ) {
+ unlockState();
+ signalV();
+ return 0;
+ } else {
+ //printf("Couldn't get a video frame, videofifo is %f full\n", m_fifovideo->getSizePercentage()); // this can only happen if the fifo is empty
+ unlockState();
+ signalV();
+ return -1; // return with error
+ }
+ }
+
+ m_vtime = vf->timestamp / (double)m_video_format.timescale;
+ unlockState();
+ signalV();
+ return 1 ;
+}
+
+int ReadMedia::decodeAudio( gavl_audio_frame_t * af ) {
+ lockState();
+ if (m_state != STATE_READY || m_audio_stream_count < 1 || m_fifoaudio == NULL ) {
+ unlockState();
+ return -1;
+ }
+
+ if ( !m_fifoaudio->Get( af ) ) {
+ if ( m_aeof ) {
+ m_pcm_seek = -1;
+ unlockState();
+ signalA();
+ return 0;
+ } else {
+ //printf("Couldn't get an audio frame, audiofifo is %f full.\n", m_fifoaudio->getSizePercentage()); // this can only happen if the fifo is empty
+ unlockState();
+ signalA();
+ return -1;
+ }
+ }
+
+ m_atime = af->timestamp / (double)m_audio_format.samplerate;
+ unlockState();
+ signalA();
+ return 1 ;
+}
+
+bool ReadMedia::rewind() {
+ lockState();
+ if ( m_state == STATE_READY && m_file != NULL) {
+ if (m_audio_stream_count){
+ //m_audio_frame->valid_samples = 0;
+ m_pcm_seek = 0;
+ m_frame_seek = -1;
+ m_aeof = false;
+ m_atime = 0;
+ // need to signal after setting eof to false;
+ unlockState();
+ signalAV();
+ lockState();
+ }
+ if ( m_video_stream_count ) {
+ if (m_audio_stream_count == 0) {
+ m_frame_seek=0;
+ m_pcm_seek = -1;
+ }
+ m_veof = false;
+ m_vtime=0;
+ unlockState();
+ signalAV();
+ lockState();
+ }
+ unlockState();
+ // fifo flush happens when we seek
+ return true;
+ }
+ unlockState();
+ return false;
+}
+
+double ReadMedia::getLengthInSeconds() {
+ double secs = 0.0;
+ lockState();
+ secs = m_length_in_seconds;
+ unlockState();
+ return secs;
+}
+
+int64_t ReadMedia::getLengthInAudioSamples() {
+ int64_t samples = 0;
+ lockState();
+ samples = m_num_samples;
+ unlockState();
+ return samples;
+}
+
+int64_t ReadMedia::getLengthInVideoFrames() {
+ int64_t frames = 0;
+ lockState();
+ frames = m_num_frames;
+ unlockState();
+ return frames;
+}
+
+bool ReadMedia::frameSeek( int64_t frames ) {
+ lockState();
+ if (m_state == STATE_READY && m_file && bgav_can_seek( m_file ) && frames >= 0 && frames < m_num_frames ) {
+ m_frame_seek = frames;
+ unlockState();
+ signalAV();
+ return true;
+ } else {
+ m_frame_seek = -1;
+ unlockState();
+ return false;
+ }
+}
+
+// NOT PUBLIC
+int64_t ReadMedia::frameSeek() {
+ int64_t tmp=-1;
+ lockState();
+ tmp = m_frame_seek;
+ m_frame_seek = -1;
+ unlockState();
+ return tmp;
+}
+
+bool ReadMedia::pcmSeek( int64_t samples ) {
+ lockState();
+ if (m_state == STATE_READY && m_file && bgav_can_seek( m_file) && samples >= 0 && samples < m_num_samples ) {
+ m_pcm_seek = samples;
+ unlockState();
+ signalAV();
+ return true;
+ } else {
+ m_pcm_seek = -1;
+ unlockState();
+ return false;
+ }
+}
+
+// NOT PUBLIC
+int64_t ReadMedia::pcmSeek() {
+ int64_t tmp=-1;
+ lockState();
+ tmp = m_pcm_seek;
+ m_pcm_seek = -1;
+ unlockState();
+ return tmp;
+}
+
+bool ReadMedia::timeSeek(double seconds) {
+ gavl_time_t gt = gavl_seconds_to_time( seconds ) ;
+
+ lockState();
+ if (m_state == STATE_READY && m_file && bgav_can_seek( m_file) && seconds >= 0.0 && seconds < m_length_in_seconds ) {
+ if (m_audio_stream_count) {
+ m_pcm_seek = gavl_time_to_samples(m_audio_format.samplerate, gt );
+ if (m_pcm_seek >= m_num_samples || m_pcm_seek < 0)
+ m_pcm_seek = -1;
+ unlockState();
+ signalAV();
+ return true;
+ } else if ( m_video_stream_count ) {
+ m_frame_seek = gavl_time_to_frames( m_video_format.timescale, m_video_format.frame_duration, gt );
+ if (m_frame_seek >= m_num_frames || m_frame_seek < 0 )
+ m_frame_seek = -1;
+ unlockState();
+ signalAV();
+ return true;
+ }
+ }
+ unlockState();
+ return false;
+}
+
+bool ReadMedia::quitAVThreads() {
+ bool b =false;
+ lockState();
+ b = quit_av_threads;
+ unlockState();
+ return b;
+}
+
+void ReadMedia::openFile( char * fn, int vsize, int asize, int spf) {
+ lockState();
+ /*
+ if ( strcmp(m_filename, fn) == 0 && m_state == STATE_READY) {
+ printf("%s is already open for action. \n", m_filename);
+ unlockState();
+ return;
+ }
+ */
+ // signal the dispatcher that we want an new file
+ m_audio_format.samples_per_frame = spf ;
+ m_afifosize = asize;
+ m_vfifosize = vsize;
+ sprintf(m_filename, "%s", fn);
+
+ m_cmd = CMD_OPEN ;
+
+ unlockState();
+ signalDispatcher();
+}
+
+void ReadMedia::copyAudioFormat(gavl_audio_format_t * dst ){
+ lockState();
+ //if (m_state == STATE_READY)
+ gavl_audio_format_copy(dst, &m_audio_format);
+ unlockState();
+}
+
+void ReadMedia::copyVideoFormat(gavl_video_format_t * dst ){
+ lockState();
+ //if (m_state == STATE_READY)
+ gavl_video_format_copy( dst, &m_video_format);
+ unlockState();
+}
+
+int ReadMedia::getAudioSamplerate() {
+ int sr=0;
+ lockState();
+ //if (m_state == STATE_READY )
+ sr = m_audio_format.samplerate;
+ unlockState();
+ return sr;
+}
+
+int ReadMedia::getAudioChannelCount() {
+ int ch=0;
+ lockState();
+ //if (m_state == STATE_READY )
+ ch = m_audio_format.num_channels;
+ unlockState();
+ return ch;
+}
+
+int ReadMedia::getVideoTimescale() {
+ int t=0;
+ lockState();
+ t = m_video_format.timescale;
+ unlockState();
+ return t;
+}
+
+int ReadMedia::getVideoFrameDuration() {
+ int t=0;
+ lockState();
+ t = m_video_format.frame_duration;
+ unlockState();
+ return t;
+}
+
+char * ReadMedia::getFilename() {
+ return m_filename;
+}
+
+bgav_t * ReadMedia::getFile() {return m_file;}
+FifoAudioFrames * ReadMedia::getAudioFifo() { return m_fifoaudio; }
+FifoVideoFrames * ReadMedia::getVideoFifo() { return m_fifovideo; }
+gavl_audio_frame_t * ReadMedia::getAudioFrame() { return m_audio_frame;}
+gavl_video_frame_t * ReadMedia::getVideoFrame() { return m_video_frame;}
+
+
+void ReadMedia::setState(int b) {
+ lockState();
+ m_state = b;
+ unlockState();
+}
+
+int ReadMedia::getState() {
+ int s=STATE_EMPTY;
+ lockState();
+ s = m_state;
+ unlockState();
+ return s;
+}
+
+bool ReadMedia::isReady() { if ( getState() == STATE_READY) return true; else return false;}
+// no need to lock on these
+double ReadMedia::getATimeInSeconds() { return m_atime;};
+double ReadMedia::getVTimeInSeconds() { return m_vtime;};
+
+float ReadMedia::getTimeInSeconds() {
+ lockState();
+ if (m_audio_stream_count > 0 ) {
+ unlockState();
+ return m_atime;
+ } else {
+ // FIXME : see if the following is really true
+ unlockState();
+ return m_vtime;
+ }
+};
+
+float ReadMedia::getAudioFifoSizePercentage() {
+ float f=0.0;
+ lockState();
+ if (m_fifoaudio)
+ f = m_fifoaudio->getSizePercentage();
+ unlockState();
+ return f;
+}
+
+void ReadMedia::pealOffVideoFrames( int howmany) {
+ lockAV();
+ if (m_fifovideo == NULL) {
+ unlockAV();
+ return;
+ }
+ int max = howmany > m_fifovideo->getSize() ? m_fifovideo->getSize() : howmany;
+ for (int i=0;i< max; i++) {
+ m_fifovideo->Get();
+ //printf("pealing of a video frame size = %d\n", m_fifovideo->getSize());
+ }
+ unlockAV();
+}
+
+void ReadMedia::setAEOF(bool b) {
+ lockState();
+ m_aeof = b;
+ unlockState();
+}
+void ReadMedia::setVEOF(bool b) {
+ lockState();
+ m_veof = b;
+ unlockState();
+}
+
+
+bool ReadMedia::getEOF() {
+ bool tmp = true;
+ lockState();
+ if (m_state == STATE_READY)
+ tmp = (m_aeof && m_veof);
+ unlockState();
+ return tmp;
+}
+
+void ReadMedia::setLoop( bool b) {
+ lockState();
+ m_loop = b;
+ unlockState();
+}
+bool ReadMedia::getLoop() {
+ bool tmp = true;
+ lockState();
+ tmp = m_loop;
+ unlockState();
+ return tmp;
+}
+
+// NOT PUBILC
+// only used in fifo filler
+bool ReadMedia::getAEOF() {
+ bool tmp = false;
+ lockState();
+ tmp = m_aeof;
+ unlockState();
+ return tmp;
+}
+
+// NOT PUBLIC
+bool ReadMedia::getVEOF() {
+ bool tmp = false;
+ lockState();
+ tmp = m_veof;
+ unlockState();
+ return tmp;
+}
+
+int ReadMedia::getSamplesPerFrame() {
+ int spf=0;
+ lockState();
+ spf = m_audio_format.samples_per_frame;
+ unlockState();
+ return spf;
+}
+
+int ReadMedia::lockAV() {
+ //printf("locking AV\n");
+ return pthread_mutex_lock(&m_av_mut);
+}
+int ReadMedia::unlockAV() {
+ //printf("unlocking AV\n");
+ return pthread_mutex_unlock(&m_av_mut);
+}
+
+int ReadMedia::lockState() {
+ // printf("locking state.\n");
+ return pthread_mutex_lock(&m_state_mut);
+}
+int ReadMedia::unlockState() {
+ //printf("unlocking state.\n");
+ return pthread_mutex_unlock(&m_state_mut);
+}
+
+
+void ReadMedia::waitA() { pthread_cond_wait( &m_cond_a, &m_condmut_a); }
+void ReadMedia::waitV() { pthread_cond_wait( &m_cond_v, &m_condmut_v); }
+void ReadMedia::signalAV() { signalA(); signalV(); }
+void ReadMedia::signalA() { pthread_cond_signal( &m_cond_a); }
+void ReadMedia::signalV() { pthread_cond_signal( &m_cond_v); }
+
+void ReadMedia::signalDispatcher() { pthread_cond_signal( &m_cond_dispatch); }
+void ReadMedia::waitDispatch() { pthread_cond_wait( &m_cond_dispatch, &m_condmut_dispatch); }
+
+void ReadMedia::setOpenCallback(void (*oc)(void *), void *v ) {
+ lockState();// do we need this?
+ m_open_callback = oc;
+ m_open_callback_data = v;
+ unlockState();
+}
+void ReadMedia::callOpenCallback() {
+ // do NOT lock on the callback, user must do call public functions
+ // that also lock
+ if(m_open_callback != NULL)
+ m_open_callback( m_open_callback_data);
+ };
+
+void ReadMedia::setBufferCallback(bgav_buffer_callback bc, void *v ) {
+ lockState();
+ m_buffer_callback = bc;
+ m_buffer_callback_data = v;
+ // set up callbacks.
+ if (m_buffer_callback) {
+ bgav_options_set_buffer_callback( m_opt, m_buffer_callback, m_buffer_callback_data);
+ }
+ unlockState();
+};
+
+
+
+
+int ReadMedia::getAudioStreamCount() {
+ int asc=0;
+ lockState();
+ asc = m_audio_stream_count;
+ unlockState();
+ return asc;
+}
+int ReadMedia::getVideoStreamCount() {
+ int vsc=0;
+ lockState();
+ vsc = m_video_stream_count;
+ unlockState();
+ return vsc;
+}
+
+
+// NOT PUBLIC
+void ReadMedia::setAudioStreamCount(int s){
+ lockState();
+ m_audio_stream_count=s;
+ if (s == 0) // no audio streams, we are already at audio eof
+ m_aeof = true;
+ unlockState();
+}
+// NOT PUBLIC
+void ReadMedia::setVideoStreamCount(int s){
+ lockState();
+ m_video_stream_count=s;
+ if (s==0) // if there are no video streams, video is at eof
+ m_veof = true;
+ unlockState();
+}
+
+// NOT PUBLIC
+void ReadMedia::setCommand(int s){
+ lockState();
+ m_cmd = s;
+ unlockState();
+}
+
+// NOT PUBLIC
+int ReadMedia::getCommand() {
+ int cmd= CMD_NULL;
+ lockState();
+ cmd = m_cmd;
+ unlockState();
+ return cmd;
+}
+
+
+// NOT PUBLIC
+// Clears the bgav_t struct, destroying and then creating it
+// NO NEED TO DO AV LOCK, only called in the opener thread
+void ReadMedia::clearFile() {
+ if (m_file != NULL)
+ bgav_close( m_file );
+
+ m_file = bgav_create();
+ bgav_options_copy( bgav_get_options( m_file ) , m_opt);
+ m_aeof = false;
+ m_veof = false;
+ m_pcm_seek = -1;
+ m_frame_seek = -1;
+}
+
+// NOT PUBLIC
+// Closes the bgav_t struct, destroying it and setting to NULL
+// NO NEED TO DO AV LOCK, only called in the opener thread
+void ReadMedia::closeFile() {
+ if (m_file != NULL)
+ bgav_close( m_file );
+ m_file = NULL;
+ m_aeof = false;
+ m_veof = false;
+ m_pcm_seek = -1;
+ m_frame_seek = -1;
+
+ sprintf(m_filename, "seinettbitte!");
+}
+
+
+// NOT PUBLIC
+// killAVThreads is only called from the opener thread
+// and from the destructor
+// THIS IS NOT REALLY A PUBLIC function
+void ReadMedia::killAVThreads() {
+
+ lockState();
+ m_state = STATE_EMPTY;
+ quit_av_threads = true;
+ unlockState();
+
+ signalAV();
+ signalAV();
+
+ // FIRST need to join the threads that exist and are running
+ if (m_audio_thread_ret == 0) {
+ pthread_join( m_thread_fillaudiofifo, NULL);
+ //pthread_detach( m_thread_fillaudiofifo);
+ }
+ if (m_video_thread_ret == 0){
+ pthread_join( m_thread_fillvideofifo, NULL);
+ //pthread_detach( m_thread_fillvideofifo);
+ }
+ m_audio_thread_ret = -1;
+ m_video_thread_ret = -1;
+
+ // no need to lock here
+ quit_av_threads = false;
+
+}
+
+// NOT PUBLIC
+// Only called from the opener thread
+bool ReadMedia::startAVThreads() {
+
+ if (m_audio_thread_ret == 0 || m_video_thread_ret == 0 ) {
+ // ouch!, we have running AV threads, this is not good
+ return false;
+ }
+
+ if (m_audio_stream_count > 0) {
+ m_audio_thread_ret = pthread_create(&m_thread_fillaudiofifo, NULL, the_audiofifo_filler, (void *)this);
+ if (m_audio_thread_ret != 0 ) {
+ printf("ReadMedia:: problem starting the audio thread\n");
+ return false;
+ }
+ }
+
+ if (m_video_stream_count > 0) {
+ m_video_thread_ret = pthread_create(&m_thread_fillvideofifo, NULL, the_videofifo_filler, (void *)this);
+ if (m_video_thread_ret != 0 ) {
+ printf("ReadMedia:: problem starting the video thread\n");
+ return false;
+ }
+ }
+ return true;
+}
+
+bool ReadMedia::initFormat() {
+
+ const gavl_audio_format_t * open_audio_format;
+ const gavl_video_format_t * open_video_format;
+
+ // we use the m_vfifosize to see if the user app wants video or not
+ // then, we set m_video_stream_count to 0 if he doesn't want video
+ if (m_video_stream_count > 0 && m_vfifosize > 0) {
+ open_video_format = bgav_get_video_format(m_file, 0);
+
+ if (open_video_format->pixelformat == GAVL_PIXELFORMAT_NONE) {
+ printf("!!!sorry, pixelformat is not recognized.\n");
+ return false;
+ }
+
+ // let's check to see if the formats are the same, if they are the same
+ // there is no reason to recreate the fifo or frames
+ if ( gavl_video_formats_equal( &m_video_format, open_video_format) == 0 ) {
+ // the formats are different
+ gavl_video_format_copy (&m_video_format, open_video_format);
+ if (m_video_frame != NULL)
+ gavl_video_frame_destroy(m_video_frame);
+ m_video_frame = gavl_video_frame_create(&m_video_format);
+ gavl_video_frame_clear( m_video_frame, &m_video_format);
+ if (m_fifovideo != NULL)
+ delete m_fifovideo;
+ m_fifovideo= new FifoVideoFrames( m_vfifosize , &m_video_format);
+ }
+ } else {
+ m_video_stream_count = 0;
+ }
+
+ // we use the m_afifosize to see if the user app wants audio or not
+ // then, we set m_audio_stream_count to 0 if he doesn't want audio
+ if (m_audio_stream_count > 0 && m_afifosize > 0) {
+ open_audio_format = bgav_get_audio_format(m_file, 0);
+
+ // we can get audio formats that are unkown
+ if ( open_audio_format->sample_format == GAVL_SAMPLE_NONE) {
+ printf("sorry, this file has unsupported audio.\n");
+ return false;
+ }
+
+ if ( gavl_audio_formats_equal(&m_audio_format, open_audio_format) == 0 ) {
+ // audio formats are different
+ // save the old spf
+ int spf = m_audio_format.samples_per_frame;
+ gavl_audio_format_copy(&m_audio_format, open_audio_format);
+
+ if (m_audio_frame != NULL)
+ gavl_audio_frame_destroy(m_audio_frame);
+
+ // set it back to original
+ m_audio_format.samples_per_frame = spf ;
+
+ m_audio_frame = gavl_audio_frame_create(&m_audio_format);
+ gavl_audio_frame_mute( m_audio_frame, &m_audio_format);
+ if( m_fifoaudio != NULL )
+ delete m_fifoaudio;
+ m_fifoaudio = new FifoAudioFrames( m_afifosize , &m_audio_format);
+ }
+ } else {
+ // user doesn't want audio
+ m_audio_stream_count = 0;
+ }
+
+ if (bgav_can_seek(m_file)) {
+ // set seconds
+ m_length_in_seconds = gavl_time_to_seconds( bgav_get_duration ( m_file, 0) );
+
+ // set samples
+ if (m_audio_stream_count)
+ if ( bgav_can_seek_sample(m_file) == 1 )
+ m_num_samples= bgav_audio_duration ( m_file, 0) ;
+ else
+ m_num_samples= gavl_time_to_samples( m_audio_format.samplerate , bgav_get_duration ( m_file, 0) );
+ else
+ m_num_samples=0;
+
+ // set frames
+ if(m_video_stream_count)
+ if ( bgav_can_seek_sample(m_file) == 1 )
+ m_num_frames = bgav_video_duration ( m_file, 0);
+ else
+ m_num_frames = gavl_time_to_frames( m_video_format.timescale, m_video_format.frame_duration , bgav_get_duration ( m_file, 0) );
+ else
+ m_num_frames=0;
+
+ } else { // no can seek;
+
+ m_length_in_seconds = 0.0;
+ m_num_samples = 0;
+ m_num_frames = 0;
+ }
+
+ m_pcm_seek = -1;
+ m_frame_seek = -1;
+
+ return true;
+}
+
+
+void *the_thread_dispatcher(void *xp) {
+
+ ReadMedia *rm = (ReadMedia *)xp;
+ int cmd = CMD_NULL;
+ pthread_t thread_open;
+ int start_thread_ret = -1;
+ cmd = rm->getCommand();
+
+ while ( cmd != CMD_QUIT ) {
+ if (cmd == CMD_OPEN) {
+ // We already check in the openFile function if the user is trying to open
+ // a file that is already open.
+
+ // join the opener thread, this will protect again any other calls to open
+ if (start_thread_ret == 0 )
+ pthread_join( thread_open, NULL );
+
+ // we join the AV threads
+ // the opener thread will start the AV threads anew upon success
+ rm->killAVThreads();
+
+ start_thread_ret = pthread_create(&thread_open, NULL, the_thread_opener, (void *)rm) ;
+ if (start_thread_ret != 0 )
+ printf( "Failed to create m_thread_open thread.\n");
+
+ }
+ if (rm->getCommand() == CMD_QUIT)
+ break;
+ rm->setCommand( CMD_NULL);
+ rm->waitDispatch();
+ cmd = rm->getCommand();
+ }
+
+ //printf("dispatcher: joining thread open\n");
+ if( start_thread_ret == 0 )
+ pthread_join( thread_open , NULL);
+ //printf("dispatcher: joined thread open, joining AV's\n");
+ rm->killAVThreads();
+ //printf("dispatcher: joined AV's\n");
+ pthread_exit(NULL);
+};
+
+void *the_thread_opener(void *xp) {
+ ReadMedia *rm = NULL;
+ int num_urls=0, num_tracks=0, audio_stream_count=0, video_stream_count =0;
+
+ rm = (ReadMedia *)xp;
+ rm->setState(STATE_OPENING);
+
+ // AFTER WE KILL THE THREADS, THERE IS NO NEED TO LOCK AV mutex
+ // ALL functions that want to get info on the file, seek,
+ // or decode a frame, MUST first check the state. If the
+ // state is STATE_READY, then it can perform it's function,
+ // locking on the necessary variables that might conflict with
+ // the AV.
+
+ // clearFile deletes old file and creates new File
+ rm->clearFile();
+
+ if(!bgav_open(rm->getFile(), rm->getFilename())) {
+ printf( "Could not open file %s\n", rm->getFilename());
+ rm->setState( STATE_EMPTY );
+ rm->closeFile();
+ rm->callOpenCallback();
+ pthread_exit(NULL);
+ //return NULL;
+ } else {
+ printf("opened %s\n", rm->getFilename());
+ }
+
+ // check to see if it is a redirector
+ if(bgav_is_redirector( rm->getFile() )) {
+ num_urls = bgav_redirector_get_num_urls( rm->getFile() );
+ printf( "Found redirector with %d urls inside, we will try to use the first one.\n", num_urls);
+ printf( "Name %d: %s\n", 1, bgav_redirector_get_name(rm->getFile() , 0));
+ printf("URL %d: %s\n", 1, bgav_redirector_get_url(rm->getFile(), 0));
+ sprintf(rm->getFilename(), "%s", bgav_redirector_get_url(rm->getFile(), 0) );
+ rm->clearFile();
+ if (!bgav_open( rm->getFile(), rm->getFilename() )) {
+ printf("Could not open redirector\n");
+ rm->setState( STATE_EMPTY );
+ rm->closeFile();
+ rm->callOpenCallback();
+ pthread_exit(NULL);
+ //return NULL;
+ } else {
+ printf("opened redirector %s\n", rm->getFilename());
+ }
+ }
+
+ num_tracks = bgav_num_tracks(rm->getFile());
+ if ( num_tracks ) {
+ bgav_select_track(rm->getFile(), 0);
+ } else {
+ printf("No tracks associated with file:%s\n", rm->getFilename() );
+ rm->setState( STATE_EMPTY );
+ rm->closeFile();
+ rm->callOpenCallback();
+ pthread_exit(NULL);
+ }
+
+ audio_stream_count = bgav_num_audio_streams(rm->getFile(), 0);
+ if( audio_stream_count )
+ bgav_set_audio_stream(rm->getFile(), 0, BGAV_STREAM_DECODE);
+
+ video_stream_count = bgav_num_video_streams(rm->getFile(), 0);
+ if( video_stream_count )
+ bgav_set_video_stream(rm->getFile(), 0, BGAV_STREAM_DECODE);
+
+ rm->setVideoStreamCount(video_stream_count);
+ rm->setAudioStreamCount(audio_stream_count);
+
+ if(!bgav_start(rm->getFile())) {
+ printf( "failed to start file\n");
+ rm->setState( STATE_EMPTY );
+ rm->closeFile();
+ rm->callOpenCallback();
+ pthread_exit(NULL) ;
+ //return NULL;
+ }
+
+ if( !rm->initFormat() ){
+ rm->setState( STATE_EMPTY );
+ rm->closeFile();
+ rm->callOpenCallback();
+ pthread_exit(NULL) ;
+ }
+
+ if( !rm->startAVThreads() ){
+ rm->setState( STATE_EMPTY );
+ rm->closeFile();
+ rm->callOpenCallback();
+ pthread_exit(NULL) ;
+ }
+
+ // AV threads are now running, blocking will be necessary
+ // STATE_READY and callOpenCallback is set/called in the
+ // fifo fill callbacks
+ rm->signalAV();
+ rm->signalAV(); //extra signal for second thread
+ pthread_exit(NULL);
+ //return NULL;
+}
+
+void *the_audiofifo_filler( void * xp) {
+ int samples_returned=0;
+ ReadMedia *rm = (ReadMedia *)xp;
+ int first = true;
+ int dovideo = rm->getVideoStreamCount();
+ int spf = rm->getSamplesPerFrame();
+ int samplerate = rm->getAudioSamplerate();
+ int64_t seekto =-1;
+ int can_seek = bgav_can_seek ( rm->getFile() );
+ int can_seek_sample = bgav_can_seek_sample ( rm->getFile() );
+
+ while (!rm->quitAVThreads() ) {
+
+ //while ( rm->getAudioFifo() != NULL && rm->getAudioFifo()->FreeSpace() && !rm->getAEOF() ) {
+ while ( rm->getAudioFifo()->FreeSpace() && !rm->getAEOF() ) {
+
+ if (rm->quitAVThreads() ) pthread_exit(NULL) ; //return NULL;
+
+ rm->lockAV();
+ // check to see if we need to seek
+ // if this is set, we already know we can seek on this file
+ // and don't need to check with bgav_can_seek
+ if ( can_seek && (seekto = rm->pcmSeek() ) >= 0 ) {
+ rm->getAudioFifo()->Flush();
+ if (dovideo && rm->getVideoFifo() ) rm->getVideoFifo()->Flush();
+ if ( can_seek_sample ) {
+ bgav_seek_audio(rm->getFile() , 0, seekto );
+ } else {
+ gavl_time_t gt = gavl_samples_to_time( samplerate, seekto ) ;
+ bgav_seek(rm->getFile(), &gt);
+ }
+ }
+
+ samples_returned = bgav_read_audio(rm->getFile(), rm->getAudioFrame(), 0, spf );
+ //rm->unlockAV();
+
+ if (samples_returned == 0 ) {
+ if( rm->getLoop() ) {
+ if ( can_seek ) {
+ // Now, rewind the file, don't flush the fifo's
+ if (can_seek_sample) {
+ bgav_seek_audio(rm->getFile() , 0, 0);
+ } else {
+ gavl_time_t gt = 0;
+ bgav_seek(rm->getFile(), &gt);
+ }
+ // SAVE THIS FOR ANOTHER TIME, OVERLAPPED SMOOTH LOOPING
+ //if ( rm->getLoop() > 1 && bgav_read_audio(rm->getFile(), rm->getAudioFrame(), 0, spf ) ) {
+ // add to the fifo, overlapping
+ // rm->getAudioFifo()->AppendOverlap( rm->getAudioFrame(), 5 );
+ // }
+
+
+ } else { // this file is not seekable, what do we do?
+ printf("cannot seek on file, but we want to loop. setting end of file.\n");
+ rm->setAEOF(true);
+ rm->pcmSeek();// clear the seek var just in case
+ }
+ } else {
+ rm->setAEOF(true);
+ rm->pcmSeek(); // clear the seek var just in case
+ }
+ rm->unlockAV();
+ break;
+ }
+ rm->unlockAV();
+ if( !rm->getAudioFifo()->Append( rm->getAudioFrame() ))
+ printf("problem with appending Audio Frame\n");
+ }
+ if (first && !dovideo) {
+ rm->setState( STATE_READY );
+ rm->callOpenCallback();
+ first = false;
+ }
+ if (rm->quitAVThreads() ) pthread_exit(NULL); //return NULL;
+ rm->waitA();
+ }
+ pthread_exit(NULL);//return NULL;
+}
+
+void *the_videofifo_filler( void * xp) {
+ ReadMedia *rm = (ReadMedia *)xp;
+ int ret = 0;
+ int first = true;
+ int doaudio = rm->getAudioStreamCount();
+ int64_t seekto =-1;
+ int can_seek = bgav_can_seek ( rm->getFile() );
+ int can_seek_sample = bgav_can_seek_sample ( rm->getFile() );
+ int timescale = rm->getVideoTimescale();
+ int frame_duration = rm->getVideoFrameDuration();
+
+ while (!rm->quitAVThreads() ) {
+
+ while ( rm->getVideoFifo() !=NULL && rm->getVideoFifo()->FreeSpace() && !rm->getVEOF() ) {
+
+ if (rm->quitAVThreads() ) pthread_exit(NULL);//return NULL;
+
+ rm->lockAV();
+ // check to see if we need to seek
+ // if this is set, we already know we can seek on this file
+ // and don't need to check with bgav_can_seek
+ if ( (seekto = rm->frameSeek() ) >= 0 ) {
+ if (doaudio && rm->getAudioFifo()) rm->getAudioFifo()->Flush();
+ rm->getVideoFifo()->Flush();
+ gavl_time_t gt = gavl_frames_to_time (timescale, frame_duration, seekto );
+ if ( can_seek_sample ) {
+ bgav_seek_video(rm->getFile() , 0, gt );
+ } else {
+ bgav_seek(rm->getFile(), &gt);
+ }
+ }
+
+ ret = bgav_read_video(rm->getFile(), rm->getVideoFrame(), 0 );
+
+ if ( !ret ) {
+ // only loop from video if there is no audio
+ // audio controls loop timing
+ if ( !doaudio && rm->getLoop() ) {
+
+ if ( can_seek ) {
+ // Now, rewind the file, don't flush fifos
+ if (can_seek_sample) {
+ bgav_seek_video(rm->getFile() , 0, 0);
+ } else {
+ gavl_time_t gt = 0;
+ bgav_seek(rm->getFile(), &gt);
+ }
+ } else { // this file is not seekable, what do we do?
+ printf("cannot seek on file, but we want to loop. setting end of file.\n");
+ rm->setVEOF(true);
+ //rm->frameSeek();// clear the seek var just in case
+ }
+
+ } else {
+ rm->setVEOF(true);
+ }
+ rm->unlockAV();
+ break;
+ }
+ rm->unlockAV();
+ if( !rm->getVideoFifo()->Append( rm->getVideoFrame() ))
+ printf("problem with appending VideoFrame\n");
+ }
+ // on the first time 'round we will call the open callback
+ // if there is no video in the file, the audio will handle it.
+ if (first) {
+ rm->setState( STATE_READY );
+ rm->callOpenCallback();
+ first = false;
+ }
+
+ if (rm->quitAVThreads() ) pthread_exit(NULL); //return NULL;
+ rm->waitV();
+ }
+ pthread_exit(NULL); //return NULL;
+}
+
+
diff --git a/src/ReadMedia.h b/src/ReadMedia.h
new file mode 100644
index 0000000..d0a7627
--- /dev/null
+++ b/src/ReadMedia.h
@@ -0,0 +1,220 @@
+#ifndef _READMEDIA_H_
+#define _READMEDIA_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include "FifoAudioFrames.h"
+#include "FifoVideoFrames.h"
+
+
+#ifndef _AVDEC_H_
+#define _AVDEC_H_
+extern "C" {
+#include <avdec.h>
+}
+#endif
+
+
+#define STATE_EMPTY 0
+#define STATE_OPENING 1
+#define STATE_READY 2
+
+#define SRC_MAX 256.0
+#define SRC_MIN 1/256.0
+
+#define CMD_START 3
+#define CMD_NULL 0
+#define CMD_OPEN 1
+#define CMD_QUIT 2
+
+class ReadMedia {
+
+ public:
+ ReadMedia();
+ ~ReadMedia();
+
+ void openFile( char * filename, int vfifosize, int afifosize, int samples_per_frame);
+
+ int decodeAudio( gavl_audio_frame_t *af);
+ int decodeVideo( gavl_video_frame_t *vf);
+
+ bool isReady(); // see if file is loaded or not
+ bool getEOF();
+
+ bool rewind();
+ bool rewindNoFlush();
+ bool frameSeek(int64_t frames);
+ bool pcmSeek(int64_t samples);
+ bool timeSeek(double seconds);
+
+ int getAudioSamplerate();
+ int getAudioChannelCount();
+ int getVideoTimescale();
+ int getVideoFrameDuration();
+
+ double getLengthInSeconds();
+ int64_t getLengthInAudioSamples();
+ int64_t getLengthInVideoFrames();
+
+ int getAudioStreamCount();
+ int getVideoStreamCount();
+
+ // this is used to sync AV frames
+ void pealOffVideoFrames(int howmany);
+
+ void dump() { lockState(); if (m_file != NULL) bgav_dump(m_file); unlockState(); };
+
+ double getATimeInSeconds();
+ double getVTimeInSeconds();
+ float getTimeInSeconds();
+ float getAudioFifoSizePercentage();
+
+ void copyAudioFormat(gavl_audio_format_t * dst );
+ void copyVideoFormat(gavl_video_format_t * dst );
+ void setLoop( bool b);
+ bool getLoop();
+
+
+ //|||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+ // NON-PUBLIC public functions
+ //|||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+
+ int64_t pcmSeek();
+ int64_t frameSeek();
+ //bool seek(gavl_time_t gt);
+
+ void killAVThreads();
+ bool startAVThreads();
+ void setAudioStreamCount(int s);
+ void setVideoStreamCount(int s);
+
+ FifoAudioFrames * getAudioFifo();
+ FifoVideoFrames * getVideoFifo();
+
+ bgav_t * getFile();
+ char * getFilename();
+
+ gavl_audio_frame_t * getAudioFrame();
+ gavl_video_frame_t * getVideoFrame();
+
+ void closeFile();
+ void clearFile();
+
+ void setState(int b);
+ int getState();
+ gavl_audio_format_t * getAudioFormat() { return &m_audio_format;};
+ gavl_video_format_t * getVideoFormat() { return &m_video_format;};
+
+ void setCommand( int c);
+ int getCommand();
+
+ void setAEOF(bool b);
+ void setVEOF(bool b);
+ bool getAEOF();
+ bool getVEOF();
+
+ int getSamplesPerFrame();
+
+ int lockAV();
+ int unlockAV();
+ //int lockAV(const char *s);
+ //int unlockAV(const char *s);
+ int lockState();
+ int unlockState();
+ //int lockState(const char *s);
+ //int unlockState(const char *s);
+
+
+ void waitA();
+ void waitV();
+ void signalAV();
+ void signalA();
+ void signalV();
+ void waitDispatch();
+ void signalDispatcher();
+
+ bool initFormat();
+
+ void setOpenCallback(void (*oc)(void *), void *v );
+ void callOpenCallback();
+
+ void setBufferCallback( bgav_buffer_callback bc, void *v );
+
+ bool quitAVThreads();
+
+ private:
+ bool quit_av_threads;
+ // callbacks for open, input buffer etc.
+ void * m_open_callback_data;
+ void (* m_open_callback)(void * v);
+ bgav_buffer_callback m_buffer_callback;
+ void * m_buffer_callback_data;
+
+ // end of file for audio and video
+ bool m_aeof;
+ bool m_veof;
+
+ // seek vars
+ int64_t m_pcm_seek;
+ int64_t m_frame_seek;
+
+ double m_length_in_seconds;
+ int64_t m_num_samples;
+ int64_t m_num_frames;
+
+ // command for dispatcher thread
+ int m_cmd;
+
+ // internal state of media reader and
+ // current filename
+ int m_state;
+ char m_filename[1024];
+ bool m_loop;
+
+
+ // current time of audio in seconds
+ double m_atime;
+ double m_vtime;
+
+ int m_afifosize;
+ int m_vfifosize;
+ int m_audio_stream_count;
+ int m_video_stream_count;
+
+ bgav_t * m_file;
+ bgav_options_t * m_opt;
+
+ // audio stuff
+ gavl_audio_frame_t * m_audio_frame;
+ gavl_audio_format_t m_audio_format;
+
+ //video stuff
+ gavl_video_frame_t * m_video_frame;
+ gavl_video_format_t m_video_format;
+
+ FifoAudioFrames *m_fifoaudio;
+ FifoVideoFrames *m_fifovideo;
+
+ int m_audio_thread_ret;
+ int m_video_thread_ret;
+ int m_dispatcher_thread_ret;
+
+ pthread_t m_thread_fillaudiofifo;
+ pthread_t m_thread_fillvideofifo;
+ pthread_t m_thread_dispatch;
+
+ pthread_mutex_t m_condmut_a;
+ pthread_mutex_t m_condmut_v;
+ pthread_mutex_t m_condmut_dispatch;
+
+ pthread_mutex_t m_state_mut;
+ pthread_mutex_t m_av_mut;
+
+ pthread_cond_t m_cond_a;
+ pthread_cond_t m_cond_v;
+ pthread_cond_t m_cond_dispatch;
+
+};
+
+#endif
diff --git a/src/readanysf~.cpp b/src/readanysf~.cpp
new file mode 100644
index 0000000..811ddef
--- /dev/null
+++ b/src/readanysf~.cpp
@@ -0,0 +1,507 @@
+/*
+ * Readanysf PD object for reading and playing multiple soundfile types
+ * from disk and from the web using gmerlin_avdecode
+ *
+ * Copyright (C) 2003-2010 August Black
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU 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
+ *
+ * readanysf.cpp
+ */
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdbool.h> //IMPORTANT bool
+#include <stdlib.h> // for malloc
+#include <stdio.h> //sprintf
+#include <string.h> //strcmp
+#include <math.h> // ceil
+
+#include "m_pd.h"
+#include "ReadMedia.h"
+
+#define MAXSFCHANS 64 // got this from d_soundfile.c in pd/src
+
+
+static t_class *readanysf_class;
+
+typedef struct readanysf {
+ t_object x_obj;
+ t_sample *(x_outvec[MAXSFCHANS]);
+ t_outlet *outinfo;
+
+ int blocksize; // size of the pd block for this object
+ int num_channels;
+ int num_frames_in_fifo;
+ int num_samples_per_frame;
+ unsigned int tick; // how often to send outlet info
+ bool play;
+ bool is_opening;
+ unsigned int count;
+ float src_factor;
+
+ bool do_t2o_audio_convert;
+ bool do_i2t_audio_convert;
+
+ int samplesleft; // how many audio samples left in our curren read buf
+
+
+ ReadMedia *rm;
+ gavl_audio_frame_t * out_audio_frame;
+ gavl_audio_frame_t * tmp_audio_frame;
+ gavl_audio_frame_t * in_audio_frame;
+
+ gavl_audio_format_t out_audio_format;
+ gavl_audio_format_t tmp_audio_format;
+ gavl_audio_format_t in_audio_format;
+
+ gavl_audio_converter_t * i2t_audio_converter;
+ gavl_audio_converter_t * t2o_audio_converter;
+
+ pthread_mutex_t mut;
+
+} t_readanysf;
+
+
+void m_play(t_readanysf *x) {
+
+ pthread_mutex_lock(&x->mut);
+ if (x->rm->isReady() && !x->is_opening ) {
+ // is_opening protects the play variable, which in turn protects
+ // the memory accessed in m_decode_block inside of the perform function
+ // as long as play is false, no memory is accessed
+ // as long as is_opening is true, play is false and no memory is accessed
+ // to be safe, we will protect the is_opening var so that when the open callback
+ // is called, and the memory is de-allocated and re-allocated, that memory is not
+ // access by the perform function
+ x->play = true; // this is the only place where play is true
+ } else {
+ if (x->is_opening ) {
+ post("Current file is still starting.");
+ post("This probably means that it is a stream and it needs to buffer in from the network.");
+ } else {
+ post("Current file is either invalid or an unsupported codec.");
+ }
+ }
+ pthread_mutex_unlock(&x->mut);
+}
+
+void readanysf_bang(t_readanysf *x) {
+ m_play(x);
+}
+
+
+void m_pause(t_readanysf *x) {
+ x->play = false;
+}
+
+void m_pcm_seek(t_readanysf *x, float f) {
+ if (! x->rm->pcmSeek( (long)f) )
+ post("can't seek on this file.");
+}
+
+void m_time_seek(t_readanysf *x, float f) {
+ if (! x->rm->timeSeek( (double)f) )
+ post("can't seek on this file.");
+}
+
+void m_tick(t_readanysf *x, float f) {
+ if (f >= 0.0) {
+ x->tick = (unsigned int) f ;
+ }
+}
+
+void m_stop(t_readanysf *x) {
+ x->play = false;
+ x->rm->rewind();
+}
+
+void m_init_audio( t_readanysf *x) {
+ // Now,. do Audio stuff
+ x->rm->copyAudioFormat( &x->in_audio_format);
+ x->in_audio_format.samples_per_frame = x->num_samples_per_frame;
+
+ x->tmp_audio_format.samplerate = x->in_audio_format.samplerate;
+ x->tmp_audio_format.samples_per_frame = x->in_audio_format.samples_per_frame;
+ x->tmp_audio_format.num_channels = x->out_audio_format.num_channels;
+ x->tmp_audio_format.channel_locations[0] = GAVL_CHID_NONE; // Reset
+ gavl_set_channel_setup (&x->tmp_audio_format); // Set channel locations
+
+ if (x->in_audio_frame != NULL)
+ gavl_audio_frame_destroy(x->in_audio_frame);
+ x->in_audio_frame = gavl_audio_frame_create(&x->in_audio_format);
+
+ if (x->tmp_audio_frame != NULL)
+ gavl_audio_frame_destroy(x->tmp_audio_frame);
+ x->tmp_audio_frame = gavl_audio_frame_create(&x->tmp_audio_format);
+
+ /* m_out_audio_format.samples_per_frame = (m_out_audio_format.samplerate / (double)m_get_audio_format.samplerate) *
+ m_get_audio_format.samples_per_frame + 10;
+ */
+
+ if (x->i2t_audio_converter == NULL)
+ x->i2t_audio_converter = gavl_audio_converter_create( );
+ x->do_i2t_audio_convert = gavl_audio_converter_init( x->i2t_audio_converter, &x->in_audio_format, &x->tmp_audio_format);
+
+ if (x->t2o_audio_converter == NULL)
+ x->t2o_audio_converter = gavl_audio_converter_create( );
+ x->do_t2o_audio_convert = gavl_audio_converter_init_resample( x->t2o_audio_converter, &x->out_audio_format);
+
+ // FIXME: this should be protected
+ x->src_factor = x->out_audio_format.samplerate / (float) x->in_audio_format.samplerate;
+ /*
+ printf("in audio format: \n");
+ gavl_audio_format_dump( &x->in_audio_format);
+ printf("tmp audio format, converting from input=%d \n", x->do_i2t_audio_convert);
+ gavl_audio_format_dump( &x->tmp_audio_format);
+ printf("output audio format, converting from tmp=%d \n", x->do_t2o_audio_convert);
+ gavl_audio_format_dump( &x->out_audio_format);
+ */
+};
+
+
+void m_open_callback( void * data) {
+ t_atom lst;
+ t_readanysf * x = (t_readanysf *)data;
+
+ pthread_mutex_lock(&x->mut);
+ x->is_opening = true; // set it here again just to be safe
+
+ if (x->rm->isReady() && x->rm->getAudioStreamCount() ) {
+
+ m_init_audio(x);
+
+ // FIXME: is it safe to call these here?
+ SETFLOAT(&lst, (float)x->rm->getAudioSamplerate() );
+ outlet_anything(x->outinfo, gensym("samplerate"), 1, &lst);
+
+ SETFLOAT(&lst, x->rm->getLengthInSeconds() );
+ outlet_anything(x->outinfo, gensym("length"), 1, &lst);
+
+ outlet_float(x->outinfo, 0.0);
+
+ // ready should be last
+ SETFLOAT(&lst, 1.0 );
+ outlet_anything(x->outinfo, gensym("ready"), 1, &lst);
+ // set time to 0 again here just to be sure
+ } else {
+ SETFLOAT(&lst, 0.0 );
+ outlet_anything(x->outinfo, gensym("samplerate"), 1, &lst);
+ SETFLOAT(&lst, 0.0 );
+ outlet_anything(x->outinfo, gensym("length"), 1, &lst);
+ SETFLOAT(&lst, 0.0 );
+ outlet_anything(x->outinfo, gensym("ready"), 1, &lst);
+ outlet_float(x->outinfo, 0.0);
+ post("Invalid file or unsupported codec.");
+ }
+ x->is_opening=false;
+ pthread_mutex_unlock(&x->mut);
+
+}
+
+void m_open(t_readanysf *x, t_symbol *s) {
+
+ t_atom lst;
+ SETFLOAT(&lst, 0.0 );
+ outlet_anything(x->outinfo, gensym("ready"), 1, &lst);
+
+ SETFLOAT(&lst, 0.0 );
+ outlet_anything(x->outinfo, gensym("length"), 1, &lst);
+
+ outlet_float(x->outinfo, 0.0);
+
+ x->play = false;
+ pthread_mutex_lock(&x->mut);
+ x->is_opening = true;
+ pthread_mutex_unlock(&x->mut);
+ x->rm->openFile( s->s_name, 0, x->num_frames_in_fifo, x->num_samples_per_frame );
+}
+
+void m_speed(t_readanysf *x, float f) {
+ // x->rm->setSpeed( f );
+ if (f > SRC_MAX)
+ return;
+ if (f < SRC_MIN)
+ return;
+ // lock on src_factor because it is set called during open callback
+ // we can be sure then it won't conflict
+ pthread_mutex_lock(&x->mut);
+ x->src_factor = 1.0/f;
+ pthread_mutex_unlock(&x->mut);
+}
+
+void m_loop(t_readanysf *x, float f) {
+ if ( f == 0)
+ x->rm->setLoop( false );
+ else
+ x->rm->setLoop( true );
+ post("looping = %d", x->rm->getLoop());
+}
+
+
+static void *readanysf_new(t_float f, t_float f2, t_float f3 ) {
+
+ int nchannels = (int)f;
+ int nframes = (int)f2;
+ int nsamples = (int)f3;
+ int i;
+ t_atom lst;
+
+ // if the external is created without any options
+ if (nchannels <=0)
+ nchannels = 2;
+
+ if (nframes <=0)
+ nframes = 24;
+
+ if (nsamples <=0)
+ nsamples = sys_getblksize();
+
+ t_readanysf *x = (t_readanysf *)pd_new(readanysf_class);
+ x->blocksize=0;
+ x->num_channels = nchannels;
+ x->num_frames_in_fifo = nframes;
+ x->num_samples_per_frame = nsamples;
+ x->tick = 1000;
+ x->play =false;
+ x->is_opening=false;
+ x->count = 0;
+ x->src_factor = 1.0;
+ x->do_t2o_audio_convert = false;
+ x->do_i2t_audio_convert = false;
+ x->samplesleft = 0;
+
+ x->rm = NULL;
+
+ x->out_audio_frame=NULL;
+ x->tmp_audio_frame=NULL;
+ x->in_audio_frame=NULL;
+
+ // set up the audio formats in dsp call
+
+ x->i2t_audio_converter=NULL;
+ x->t2o_audio_converter=NULL;
+
+ pthread_mutex_init(&x->mut, 0);
+
+ for (i=0; i < nchannels; i++) {
+ outlet_new(&x->x_obj, gensym("signal"));
+ }
+ x->outinfo = outlet_new(&x->x_obj, &s_anything);
+ SETFLOAT(&lst, 0.0 );
+ outlet_anything(x->outinfo, gensym("ready"), 1, &lst);
+
+ // set time to 0.0
+ outlet_float(x->outinfo, 0.0);
+ if (x->rm == NULL) {
+ x->rm = new ReadMedia ( ); // (int)sys_getsr(), x->num_channels, x->num_frames_in_fifo, x->num_samples_per_frame);
+ post("Created new readanysf~ with %d channels and internal buffer of %d * %d = %d", x->num_channels,
+ x->num_frames_in_fifo, x->num_samples_per_frame, x->num_frames_in_fifo * x->num_samples_per_frame);
+ }
+ x->rm->setOpenCallback( m_open_callback, (void *)x);
+
+ return (void *)x;
+}
+
+int m_get_frame( t_readanysf *x ) {
+ int ret =0;
+ ret = x->rm->decodeAudio(x->in_audio_frame);
+ if (ret != 1) // EOF
+ return ret;
+
+ if (x->do_i2t_audio_convert) {
+ gavl_audio_convert( x->i2t_audio_converter, x->in_audio_frame, x->tmp_audio_frame) ;
+ } else {
+ gavl_audio_frame_copy(&x->in_audio_format, x->tmp_audio_frame, x->in_audio_frame,
+ 0,0, x->in_audio_frame->valid_samples, x->in_audio_frame->valid_samples) ;
+ x->tmp_audio_frame->valid_samples = x->in_audio_frame->valid_samples;
+ }
+
+ if ( x->do_t2o_audio_convert ) { // should be true all of the time
+ //gavl_audio_convert( t2o_audio_converter, taf, oaf );
+ gavl_audio_converter_resample( x->t2o_audio_converter, x->tmp_audio_frame, x->out_audio_frame, x->src_factor );
+ // Don't know why, but on the first conversion, I get one extra sample
+ // THIS SHOULD NOT HAPPEN...this is a fix for now..check it out later.
+ //if (x->src_factor == 1.0 && x->out_audio_frame->valid_samples > x->num_samples_per_frame) {
+ // printf("Got wierd return value for audio frames, taf->vs %d, oaf->vs %d, src_factor=%f\n",
+ // x->tmp_audio_frame->valid_samples, x->out_audio_frame->valid_samples, x->src_factor);
+ //x->samplesleft = x->out_audio_frame->valid_samples = x->num_samples_per_frame;
+ //} else {
+ x->samplesleft = x->out_audio_frame->valid_samples;
+ //}
+ } else {
+ // copy the samples to the output
+ gavl_audio_frame_copy(&x->tmp_audio_format, x->out_audio_frame, x->tmp_audio_frame,
+ 0,0, x->tmp_audio_frame->valid_samples, x->tmp_audio_frame->valid_samples) ;
+ //printf("copying taf to oaf, taf->vs %d, oaf->vs %d\n", taf->valid_samples, oaf->valid_samples);
+ x->samplesleft = x->tmp_audio_frame->valid_samples;
+ x->out_audio_frame->valid_samples = x->tmp_audio_frame->valid_samples;
+ }
+ return ret;
+}
+
+int m_decode_block( t_readanysf * x ) {
+ int i=0,j=0, samps_done=0;
+ int samps_to_do = x->blocksize;
+
+ while( samps_to_do > 0) {
+ if ( samps_to_do <= x->samplesleft) {
+ //if (x->out_audio_frame->valid_samples < x->samplesleft)
+ // printf("error\n");
+ // copy our samples out to the pd audio buffer
+ for (i = 0; i < x->num_channels; i++) {
+ for (j = 0; j < samps_to_do ; j++) {
+ x->x_outvec[i][samps_done + j] = x->out_audio_frame->channels.f[i][ x->out_audio_frame->valid_samples - x->samplesleft +j ];
+ }
+ }
+ x->samplesleft -= samps_to_do;
+ samps_done += samps_to_do;
+ samps_to_do = 0;
+ break;
+ } else if ( x->samplesleft > 0 ) {
+ //if( x->out_audio_frame->valid_samples < x->samplesleft)
+ // printf("valid_samples < samplesleft, shouldn't happen\n");
+ for (i = 0; i < x->num_channels; i++) {
+ for (j = 0; j < x->samplesleft; j++) {
+ x->x_outvec[i][samps_done + j] = x->out_audio_frame->channels.f[i][ x->out_audio_frame->valid_samples - x->samplesleft +j ];
+ }
+ }
+ samps_to_do = samps_to_do - x->samplesleft;
+ samps_done += x->samplesleft;
+ x->samplesleft = 0;
+ } else { // samplesleft is zero
+ int ret = m_get_frame(x);
+ if (ret == 0) {
+ return samps_done;
+ } else if (ret == -1) {
+ //printf("error getting frame...must be seeking\n");
+ return ret;
+ }
+ }
+ }
+ return samps_done;
+}
+
+static t_int *readanysf_perform(t_int *w) {
+ t_readanysf *x = (t_readanysf *) (w[1]);
+ int i=0,j=0;
+ int samples_returned = 0;
+ t_atom lst;
+
+ if (x->play ) { // play protects the memory accessed in m_decode_block
+ samples_returned = m_decode_block( x );
+ if (samples_returned == 0 ) { // EOF
+ m_stop(x);
+ outlet_bang(x->outinfo);
+ } else if (samples_returned == -1) {
+ // error in getting audio, normally from seeking
+ samples_returned=0;
+ }
+ }
+
+ for (i = 0; i < x->num_channels; i++) {
+ for (j = samples_returned; j < x->blocksize; j++) {
+ x->x_outvec[i][j] = 0.0;
+ }
+ }
+
+ // just set some variables
+ if ( ++x->count > x->tick ) {
+ SETFLOAT (&lst, x->rm->getAudioFifoSizePercentage() );
+ outlet_anything(x->outinfo, gensym("cache"), 1, &lst);
+ if (x->play) {
+ outlet_float(x->outinfo, x->rm->getTimeInSeconds());
+ }
+ x->count = 0;
+ }
+
+ return (w+2);
+}
+
+void readanysf_dsp(t_readanysf *x, t_signal **sp) {
+ int i=0;
+
+ if (x->blocksize != sp[0]->s_n) {
+ x->blocksize = sp[0]->s_n;
+
+ x->tmp_audio_format.samplerate = sys_getsr();
+ x->tmp_audio_format.sample_format = GAVL_SAMPLE_FLOAT ;
+ x->tmp_audio_format.interleave_mode = GAVL_INTERLEAVE_NONE;
+ x->tmp_audio_format.num_channels = x->num_channels;
+ x->tmp_audio_format.channel_locations[0] = GAVL_CHID_NONE; // Reset
+ x->tmp_audio_format.samples_per_frame = x->num_samples_per_frame;
+
+ x->out_audio_format.samplerate = sys_getsr();
+ x->out_audio_format.sample_format = GAVL_SAMPLE_FLOAT ;
+ x->out_audio_format.interleave_mode = GAVL_INTERLEAVE_NONE;
+ x->out_audio_format.num_channels = x->num_channels;
+ x->out_audio_format.channel_locations[0] = GAVL_CHID_NONE; // Reset
+
+ // leave enough room in our out format and frame for resampling
+ x->out_audio_format.samples_per_frame = x->num_samples_per_frame * SRC_MAX +10;
+ gavl_set_channel_setup (&x->out_audio_format); // Set channel locations
+
+ if(x->out_audio_frame != NULL)
+ gavl_audio_frame_destroy( x->out_audio_frame);
+ x->out_audio_frame = gavl_audio_frame_create(&x->out_audio_format);
+ printf("created new out frame in readanysf_dsp\n");
+ post("pd blocksize=%d, spf=%d", x->blocksize, x->num_samples_per_frame);
+ }
+
+ for (i = 0; i < x->num_channels; i++)
+ x->x_outvec[i] = sp[i]->s_vec;
+
+ dsp_add(readanysf_perform, 1, x);
+}
+
+static void readanysf_free(t_readanysf *x) {
+ // delete the readany objs
+
+ if (x->in_audio_frame != NULL) gavl_audio_frame_destroy(x->in_audio_frame);
+ if (x->tmp_audio_frame != NULL) gavl_audio_frame_destroy(x->tmp_audio_frame);
+ if (x->out_audio_frame != NULL) gavl_audio_frame_destroy(x->out_audio_frame);
+
+ if (x->i2t_audio_converter != NULL)
+ gavl_audio_converter_destroy(x->i2t_audio_converter);
+
+ if (x->t2o_audio_converter != NULL)
+ gavl_audio_converter_destroy(x->t2o_audio_converter);
+
+ pthread_mutex_destroy(&x->mut);
+
+ delete x->rm;
+ x->rm = NULL;
+}
+
+extern "C" void readanysf_tilde_setup(void) {
+
+ readanysf_class = class_new(gensym("readanysf~"), (t_newmethod)readanysf_new,
+ (t_method)readanysf_free, sizeof(t_readanysf), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_NULL);
+
+ class_addmethod(readanysf_class, (t_method)readanysf_dsp, gensym("dsp"), A_NULL);
+ class_addmethod(readanysf_class, (t_method)m_open, gensym("open"), A_SYMBOL, A_NULL);
+ class_addmethod(readanysf_class, (t_method)m_play, gensym("play"), A_NULL);
+ class_addmethod(readanysf_class, (t_method)m_pause, gensym("pause"), A_NULL);
+ class_addmethod(readanysf_class, (t_method)m_stop, gensym("stop"), A_NULL);
+ class_addmethod(readanysf_class, (t_method)m_tick, gensym("tick"), A_FLOAT, A_NULL);
+ class_addmethod(readanysf_class, (t_method)m_speed, gensym("speed"), A_FLOAT, A_NULL);
+ class_addmethod(readanysf_class, (t_method)m_loop, gensym("loop"), A_FLOAT, A_NULL);
+ class_addmethod(readanysf_class, (t_method)m_pcm_seek, gensym("pcm_seek"), A_FLOAT, A_NULL);
+ class_addmethod(readanysf_class, (t_method)m_time_seek, gensym("time_seek"), A_FLOAT, A_NULL);
+ class_addbang(readanysf_class, readanysf_bang);
+
+}
diff --git a/stress.pd b/stress.pd
new file mode 100644
index 0000000..de529ed
--- /dev/null
+++ b/stress.pd
@@ -0,0 +1,53 @@
+#N canvas 525 43 611 566 10;
+#X obj 92 457 readanysf~;
+#X obj 89 167 * -1;
+#X obj 89 190 sel -1 1;
+#X obj 89 142 f 1;
+#X obj 89 54 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1
+-1;
+#X msg 176 53 0;
+#X obj 92 491 dac~;
+#X obj 184 265 del 50;
+#X obj 469 307 del 50;
+#X msg 184 285 play;
+#X msg 469 328 play;
+#X floatatom 161 192 7 0 0 0 - - -;
+#X obj 161 142 f;
+#X obj 187 142 + 1;
+#X obj 89 98 metro 100;
+#X obj 76 299 del 5;
+#X obj 380 306 del 5;
+#X msg 345 306 stop;
+#X msg 33 306 stop;
+#X msg 208 428 open /home/august/mp3/ygr_banhart/banhart_blackbabies_01.wma
+;
+#X msg 75 319 open /home/august/mp3/lauriealan0.mp3;
+#X connect 0 0 6 0;
+#X connect 0 1 6 1;
+#X connect 1 0 2 0;
+#X connect 1 0 3 1;
+#X connect 2 0 18 0;
+#X connect 2 0 7 0;
+#X connect 2 0 15 0;
+#X connect 2 1 17 0;
+#X connect 2 1 8 0;
+#X connect 2 1 16 0;
+#X connect 3 0 1 0;
+#X connect 4 0 14 0;
+#X connect 5 0 12 1;
+#X connect 5 0 14 0;
+#X connect 7 0 9 0;
+#X connect 8 0 10 0;
+#X connect 9 0 0 0;
+#X connect 10 0 0 0;
+#X connect 12 0 13 0;
+#X connect 12 0 11 0;
+#X connect 13 0 12 1;
+#X connect 14 0 3 0;
+#X connect 14 0 12 0;
+#X connect 15 0 20 0;
+#X connect 16 0 19 0;
+#X connect 17 0 0 0;
+#X connect 18 0 0 0;
+#X connect 19 0 0 0;
+#X connect 20 0 0 0;