diff options
author | Björn Stenberg <bjorn@haxx.se> | 2007-01-08 23:53:00 +0000 |
---|---|---|
committer | Björn Stenberg <bjorn@haxx.se> | 2007-01-08 23:53:00 +0000 |
commit | 7039a05147b8bbfc829babea1c65bd436450b505 (patch) | |
tree | 4ba555eb84ed97b72b0575034d5b0530a393713e /songdbj/de/jarnbjo/ogg | |
parent | 6d4c19707ef95942e323cbdc89fbbfdbe45e7cc5 (diff) | |
download | rockbox-7039a05147b8bbfc829babea1c65bd436450b505.tar.gz rockbox-7039a05147b8bbfc829babea1c65bd436450b505.zip |
Splitting out songdbj
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11953 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'songdbj/de/jarnbjo/ogg')
-rw-r--r-- | songdbj/de/jarnbjo/ogg/BasicStream.java | 121 | ||||
-rw-r--r-- | songdbj/de/jarnbjo/ogg/CachedUrlStream.java | 252 | ||||
-rw-r--r-- | songdbj/de/jarnbjo/ogg/EndOfOggStreamException.java | 45 | ||||
-rw-r--r-- | songdbj/de/jarnbjo/ogg/FileStream.java | 154 | ||||
-rw-r--r-- | songdbj/de/jarnbjo/ogg/LogicalOggStream.java | 151 | ||||
-rw-r--r-- | songdbj/de/jarnbjo/ogg/LogicalOggStreamImpl.java | 213 | ||||
-rw-r--r-- | songdbj/de/jarnbjo/ogg/OggFormatException.java | 50 | ||||
-rw-r--r-- | songdbj/de/jarnbjo/ogg/OggPage.java | 431 | ||||
-rw-r--r-- | songdbj/de/jarnbjo/ogg/OnDemandUrlStream.java | 127 | ||||
-rw-r--r-- | songdbj/de/jarnbjo/ogg/PhysicalOggStream.java | 124 | ||||
-rw-r--r-- | songdbj/de/jarnbjo/ogg/UncachedUrlStream.java | 207 |
11 files changed, 0 insertions, 1875 deletions
diff --git a/songdbj/de/jarnbjo/ogg/BasicStream.java b/songdbj/de/jarnbjo/ogg/BasicStream.java deleted file mode 100644 index 9939524d6c..0000000000 --- a/songdbj/de/jarnbjo/ogg/BasicStream.java +++ /dev/null | |||
@@ -1,121 +0,0 @@ | |||
1 | /* | ||
2 | * $ProjectName$ | ||
3 | * $ProjectRevision$ | ||
4 | * ----------------------------------------------------------- | ||
5 | * $Id$ | ||
6 | * ----------------------------------------------------------- | ||
7 | * | ||
8 | * $Author$ | ||
9 | * | ||
10 | * Description: | ||
11 | * | ||
12 | * Copyright 2002-2003 Tor-Einar Jarnbjo | ||
13 | * ----------------------------------------------------------- | ||
14 | * | ||
15 | * Change History | ||
16 | * ----------------------------------------------------------- | ||
17 | * $Log$ | ||
18 | * Revision 1.1 2005/07/11 15:42:36 hcl | ||
19 | * Songdb java version, source. only 1.5 compatible | ||
20 | * | ||
21 | * Revision 1.3 2004/09/21 12:09:45 shred | ||
22 | * *** empty log message *** | ||
23 | * | ||
24 | * Revision 1.2 2004/09/21 06:38:45 shred | ||
25 | * Importe reorganisiert, damit Eclipse Ruhe gibt. ;-) | ||
26 | * | ||
27 | * Revision 1.1.1.1 2004/04/04 22:09:12 shred | ||
28 | * First Import | ||
29 | * | ||
30 | * | ||
31 | */ | ||
32 | |||
33 | package de.jarnbjo.ogg; | ||
34 | |||
35 | import java.io.IOException; | ||
36 | import java.io.InputStream; | ||
37 | import java.util.Collection; | ||
38 | import java.util.HashMap; | ||
39 | import java.util.LinkedList; | ||
40 | |||
41 | /** | ||
42 | * Implementation of the <code>PhysicalOggStream</code> interface for reading | ||
43 | * an Ogg stream from a URL. This class performs | ||
44 | * no internal caching, and will not read data from the network before | ||
45 | * requested to do so. It is intended to be used in non-realtime applications | ||
46 | * like file download managers or similar. | ||
47 | */ | ||
48 | |||
49 | public class BasicStream implements PhysicalOggStream { | ||
50 | |||
51 | private boolean closed=false; | ||
52 | private InputStream sourceStream; | ||
53 | private Object drainLock=new Object(); | ||
54 | private LinkedList pageCache=new LinkedList(); | ||
55 | private long numberOfSamples=-1; | ||
56 | private int position=0; | ||
57 | |||
58 | private HashMap logicalStreams=new HashMap(); | ||
59 | private OggPage firstPage; | ||
60 | |||
61 | public BasicStream(InputStream sourceStream) throws OggFormatException, IOException { | ||
62 | firstPage=OggPage.create(sourceStream); | ||
63 | position+=firstPage.getTotalLength(); | ||
64 | LogicalOggStreamImpl los=new LogicalOggStreamImpl(this, firstPage.getStreamSerialNumber()); | ||
65 | logicalStreams.put(new Integer(firstPage.getStreamSerialNumber()), los); | ||
66 | los.checkFormat(firstPage); | ||
67 | } | ||
68 | |||
69 | public Collection getLogicalStreams() { | ||
70 | return logicalStreams.values(); | ||
71 | } | ||
72 | |||
73 | public boolean isOpen() { | ||
74 | return !closed; | ||
75 | } | ||
76 | |||
77 | public void close() throws IOException { | ||
78 | closed=true; | ||
79 | sourceStream.close(); | ||
80 | } | ||
81 | |||
82 | public int getContentLength() { | ||
83 | return -1; | ||
84 | } | ||
85 | |||
86 | public int getPosition() { | ||
87 | return position; | ||
88 | } | ||
89 | |||
90 | int pageNumber=2; | ||
91 | |||
92 | public OggPage getOggPage(int index) throws IOException { | ||
93 | if(firstPage!=null) { | ||
94 | OggPage tmp=firstPage; | ||
95 | firstPage=null; | ||
96 | return tmp; | ||
97 | } | ||
98 | else { | ||
99 | OggPage page=OggPage.create(sourceStream); | ||
100 | position+=page.getTotalLength(); | ||
101 | return page; | ||
102 | } | ||
103 | } | ||
104 | |||
105 | private LogicalOggStream getLogicalStream(int serialNumber) { | ||
106 | return (LogicalOggStream)logicalStreams.get(new Integer(serialNumber)); | ||
107 | } | ||
108 | |||
109 | public void setTime(long granulePosition) throws IOException { | ||
110 | throw new UnsupportedOperationException("Method not supported by this class"); | ||
111 | } | ||
112 | |||
113 | /** | ||
114 | * @return always <code>false</code> | ||
115 | */ | ||
116 | |||
117 | public boolean isSeekable() { | ||
118 | return false; | ||
119 | } | ||
120 | |||
121 | } \ No newline at end of file | ||
diff --git a/songdbj/de/jarnbjo/ogg/CachedUrlStream.java b/songdbj/de/jarnbjo/ogg/CachedUrlStream.java deleted file mode 100644 index 86f792e272..0000000000 --- a/songdbj/de/jarnbjo/ogg/CachedUrlStream.java +++ /dev/null | |||
@@ -1,252 +0,0 @@ | |||
1 | /* | ||
2 | * $ProjectName$ | ||
3 | * $ProjectRevision$ | ||
4 | * ----------------------------------------------------------- | ||
5 | * $Id$ | ||
6 | * ----------------------------------------------------------- | ||
7 | * | ||
8 | * $Author$ | ||
9 | * | ||
10 | * Description: | ||
11 | * | ||
12 | * Copyright 2002-2003 Tor-Einar Jarnbjo | ||
13 | * ----------------------------------------------------------- | ||
14 | * | ||
15 | * Change History | ||
16 | * ----------------------------------------------------------- | ||
17 | * $Log$ | ||
18 | * Revision 1.1 2005/07/11 15:42:36 hcl | ||
19 | * Songdb java version, source. only 1.5 compatible | ||
20 | * | ||
21 | * Revision 1.1.1.1 2004/04/04 22:09:12 shred | ||
22 | * First Import | ||
23 | * | ||
24 | * Revision 1.1 2003/04/10 19:48:22 jarnbjo | ||
25 | * no message | ||
26 | * | ||
27 | * | ||
28 | */ | ||
29 | |||
30 | package de.jarnbjo.ogg; | ||
31 | |||
32 | import java.io.*; | ||
33 | import java.net.*; | ||
34 | import java.util.*; | ||
35 | |||
36 | /** | ||
37 | * Implementation of the <code>PhysicalOggStream</code> interface for reading | ||
38 | * and caching an Ogg stream from a URL. This class reads the data as fast as | ||
39 | * possible from the URL, caches it locally either in memory or on disk, and | ||
40 | * supports seeking within the available data. | ||
41 | */ | ||
42 | |||
43 | public class CachedUrlStream implements PhysicalOggStream { | ||
44 | |||
45 | private boolean closed=false; | ||
46 | private URLConnection source; | ||
47 | private InputStream sourceStream; | ||
48 | private Object drainLock=new Object(); | ||
49 | private RandomAccessFile drain; | ||
50 | private byte[] memoryCache; | ||
51 | private ArrayList pageOffsets=new ArrayList(); | ||
52 | private ArrayList pageLengths=new ArrayList(); | ||
53 | private long numberOfSamples=-1; | ||
54 | private long cacheLength; | ||
55 | |||
56 | private HashMap logicalStreams=new HashMap(); | ||
57 | |||
58 | private LoaderThread loaderThread; | ||
59 | |||
60 | /** | ||
61 | * Creates an instance of this class, using a memory cache. | ||
62 | */ | ||
63 | |||
64 | public CachedUrlStream(URL source) throws OggFormatException, IOException { | ||
65 | this(source, null); | ||
66 | } | ||
67 | |||
68 | /** | ||
69 | * Creates an instance of this class, using the specified file as cache. The | ||
70 | * file is not automatically deleted when this class is disposed. | ||
71 | */ | ||
72 | |||
73 | public CachedUrlStream(URL source, RandomAccessFile drain) throws OggFormatException, IOException { | ||
74 | |||
75 | this.source=source.openConnection(); | ||
76 | |||
77 | if(drain==null) { | ||
78 | int contentLength=this.source.getContentLength(); | ||
79 | if(contentLength==-1) { | ||
80 | throw new IOException("The URLConncetion's content length must be set when operating with a in-memory cache."); | ||
81 | } | ||
82 | memoryCache=new byte[contentLength]; | ||
83 | } | ||
84 | |||
85 | this.drain=drain; | ||
86 | this.sourceStream=this.source.getInputStream(); | ||
87 | |||
88 | loaderThread=new LoaderThread(sourceStream, drain, memoryCache); | ||
89 | new Thread(loaderThread).start(); | ||
90 | |||
91 | while(!loaderThread.isBosDone() || pageOffsets.size()<20) { | ||
92 | System.out.print("pageOffsets.size(): "+pageOffsets.size()+"\r"); | ||
93 | try { | ||
94 | Thread.sleep(200); | ||
95 | } | ||
96 | catch (InterruptedException ex) { | ||
97 | } | ||
98 | } | ||
99 | System.out.println(); | ||
100 | System.out.println("caching "+pageOffsets.size()+"/20 pages\r"); | ||
101 | } | ||
102 | |||
103 | public Collection getLogicalStreams() { | ||
104 | return logicalStreams.values(); | ||
105 | } | ||
106 | |||
107 | public boolean isOpen() { | ||
108 | return !closed; | ||
109 | } | ||
110 | |||
111 | public void close() throws IOException { | ||
112 | closed=true; | ||
113 | sourceStream.close(); | ||
114 | } | ||
115 | |||
116 | public long getCacheLength() { | ||
117 | return cacheLength; | ||
118 | } | ||
119 | |||
120 | /* | ||
121 | private OggPage getNextPage() throws EndOfOggStreamException, IOException, OggFormatException { | ||
122 | return getNextPage(false); | ||
123 | } | ||
124 | |||
125 | private OggPage getNextPage(boolean skipData) throws EndOfOggStreamException, IOException, OggFormatException { | ||
126 | return OggPage.create(sourceStream, skipData); | ||
127 | } | ||
128 | */ | ||
129 | |||
130 | public OggPage getOggPage(int index) throws IOException { | ||
131 | synchronized(drainLock) { | ||
132 | Long offset=(Long)pageOffsets.get(index); | ||
133 | Long length=(Long)pageLengths.get(index); | ||
134 | if(offset!=null) { | ||
135 | if(drain!=null) { | ||
136 | drain.seek(offset.longValue()); | ||
137 | return OggPage.create(drain); | ||
138 | } | ||
139 | else { | ||
140 | byte[] tmpArray=new byte[length.intValue()]; | ||
141 | System.arraycopy(memoryCache, offset.intValue(), tmpArray, 0, length.intValue()); | ||
142 | return OggPage.create(tmpArray); | ||
143 | } | ||
144 | } | ||
145 | else { | ||
146 | return null; | ||
147 | } | ||
148 | } | ||
149 | } | ||
150 | |||
151 | private LogicalOggStream getLogicalStream(int serialNumber) { | ||
152 | return (LogicalOggStream)logicalStreams.get(new Integer(serialNumber)); | ||
153 | } | ||
154 | |||
155 | public void setTime(long granulePosition) throws IOException { | ||
156 | for(Iterator iter=logicalStreams.values().iterator(); iter.hasNext(); ) { | ||
157 | LogicalOggStream los=(LogicalOggStream)iter.next(); | ||
158 | los.setTime(granulePosition); | ||
159 | } | ||
160 | } | ||
161 | |||
162 | public class LoaderThread implements Runnable { | ||
163 | |||
164 | private InputStream source; | ||
165 | private RandomAccessFile drain; | ||
166 | private byte[] memoryCache; | ||
167 | |||
168 | private boolean bosDone=false; | ||
169 | |||
170 | private int pageNumber; | ||
171 | |||
172 | public LoaderThread(InputStream source, RandomAccessFile drain, byte[] memoryCache) { | ||
173 | this.source=source; | ||
174 | this.drain=drain; | ||
175 | this.memoryCache=memoryCache; | ||
176 | } | ||
177 | |||
178 | public void run() { | ||
179 | try { | ||
180 | boolean eos=false; | ||
181 | byte[] buffer=new byte[8192]; | ||
182 | while(!eos) { | ||
183 | OggPage op=OggPage.create(source); | ||
184 | synchronized (drainLock) { | ||
185 | int listSize=pageOffsets.size(); | ||
186 | |||
187 | long pos= | ||
188 | listSize>0? | ||
189 | ((Long)pageOffsets.get(listSize-1)).longValue()+ | ||
190 | ((Long)pageLengths.get(listSize-1)).longValue(): | ||
191 | 0; | ||
192 | |||
193 | byte[] arr1=op.getHeader(); | ||
194 | byte[] arr2=op.getSegmentTable(); | ||
195 | byte[] arr3=op.getData(); | ||
196 | |||
197 | if(drain!=null) { | ||
198 | drain.seek(pos); | ||
199 | drain.write(arr1); | ||
200 | drain.write(arr2); | ||
201 | drain.write(arr3); | ||
202 | } | ||
203 | else { | ||
204 | System.arraycopy(arr1, 0, memoryCache, (int)pos, arr1.length); | ||
205 | System.arraycopy(arr2, 0, memoryCache, (int)pos+arr1.length, arr2.length); | ||
206 | System.arraycopy(arr3, 0, memoryCache, (int)pos+arr1.length+arr2.length, arr3.length); | ||
207 | } | ||
208 | |||
209 | pageOffsets.add(new Long(pos)); | ||
210 | pageLengths.add(new Long(arr1.length+arr2.length+arr3.length)); | ||
211 | } | ||
212 | |||
213 | if(!op.isBos()) { | ||
214 | bosDone=true; | ||
215 | //System.out.println("bosDone=true;"); | ||
216 | } | ||
217 | if(op.isEos()) { | ||
218 | eos=true; | ||
219 | } | ||
220 | |||
221 | LogicalOggStreamImpl los=(LogicalOggStreamImpl)getLogicalStream(op.getStreamSerialNumber()); | ||
222 | if(los==null) { | ||
223 | los=new LogicalOggStreamImpl(CachedUrlStream.this, op.getStreamSerialNumber()); | ||
224 | logicalStreams.put(new Integer(op.getStreamSerialNumber()), los); | ||
225 | los.checkFormat(op); | ||
226 | } | ||
227 | |||
228 | los.addPageNumberMapping(pageNumber); | ||
229 | los.addGranulePosition(op.getAbsoluteGranulePosition()); | ||
230 | |||
231 | pageNumber++; | ||
232 | cacheLength=op.getAbsoluteGranulePosition(); | ||
233 | //System.out.println("read page: "+pageNumber); | ||
234 | } | ||
235 | } | ||
236 | catch(EndOfOggStreamException e) { | ||
237 | // ok | ||
238 | } | ||
239 | catch(IOException e) { | ||
240 | e.printStackTrace(); | ||
241 | } | ||
242 | } | ||
243 | |||
244 | public boolean isBosDone() { | ||
245 | return bosDone; | ||
246 | } | ||
247 | } | ||
248 | |||
249 | public boolean isSeekable() { | ||
250 | return true; | ||
251 | } | ||
252 | } \ No newline at end of file | ||
diff --git a/songdbj/de/jarnbjo/ogg/EndOfOggStreamException.java b/songdbj/de/jarnbjo/ogg/EndOfOggStreamException.java deleted file mode 100644 index 4a0c3200f4..0000000000 --- a/songdbj/de/jarnbjo/ogg/EndOfOggStreamException.java +++ /dev/null | |||
@@ -1,45 +0,0 @@ | |||
1 | /* | ||
2 | * $ProjectName$ | ||
3 | * $ProjectRevision$ | ||
4 | * ----------------------------------------------------------- | ||
5 | * $Id$ | ||
6 | * ----------------------------------------------------------- | ||
7 | * | ||
8 | * $Author$ | ||
9 | * | ||
10 | * Description: | ||
11 | * | ||
12 | * Copyright 2002-2003 Tor-Einar Jarnbjo | ||
13 | * ----------------------------------------------------------- | ||
14 | * | ||
15 | * Change History | ||
16 | * ----------------------------------------------------------- | ||
17 | * $Log$ | ||
18 | * Revision 1.1 2005/07/11 15:42:36 hcl | ||
19 | * Songdb java version, source. only 1.5 compatible | ||
20 | * | ||
21 | * Revision 1.2 2005/02/09 23:10:47 shred | ||
22 | * Serial UID für jarnbjo | ||
23 | * | ||
24 | * Revision 1.1.1.1 2004/04/04 22:09:12 shred | ||
25 | * First Import | ||
26 | * | ||
27 | * Revision 1.1 2003/03/03 21:02:20 jarnbjo | ||
28 | * no message | ||
29 | * | ||
30 | */ | ||
31 | |||
32 | package de.jarnbjo.ogg; | ||
33 | |||
34 | import java.io.IOException; | ||
35 | |||
36 | /** | ||
37 | * Exception thrown when reaching the end of an Ogg stream | ||
38 | */ | ||
39 | |||
40 | public class EndOfOggStreamException extends IOException { | ||
41 | private static final long serialVersionUID = 3907210438109444408L; | ||
42 | |||
43 | public EndOfOggStreamException() { | ||
44 | } | ||
45 | } \ No newline at end of file | ||
diff --git a/songdbj/de/jarnbjo/ogg/FileStream.java b/songdbj/de/jarnbjo/ogg/FileStream.java deleted file mode 100644 index 5a526300bf..0000000000 --- a/songdbj/de/jarnbjo/ogg/FileStream.java +++ /dev/null | |||
@@ -1,154 +0,0 @@ | |||
1 | /* | ||
2 | * $ProjectName$ | ||
3 | * $ProjectRevision$ | ||
4 | * ----------------------------------------------------------- | ||
5 | * $Id$ | ||
6 | * ----------------------------------------------------------- | ||
7 | * | ||
8 | * $Author$ | ||
9 | * | ||
10 | * Description: | ||
11 | * | ||
12 | * Copyright 2002-2003 Tor-Einar Jarnbjo | ||
13 | * ----------------------------------------------------------- | ||
14 | * | ||
15 | * Change History | ||
16 | * ----------------------------------------------------------- | ||
17 | * $Log$ | ||
18 | * Revision 1.1 2005/07/11 15:42:36 hcl | ||
19 | * Songdb java version, source. only 1.5 compatible | ||
20 | * | ||
21 | * Revision 1.1.1.1 2004/04/04 22:09:12 shred | ||
22 | * First Import | ||
23 | * | ||
24 | * Revision 1.1 2003/04/10 19:48:22 jarnbjo | ||
25 | * no message | ||
26 | * | ||
27 | * | ||
28 | */ | ||
29 | |||
30 | package de.jarnbjo.ogg; | ||
31 | |||
32 | import java.io.*; | ||
33 | import java.util.*; | ||
34 | |||
35 | /** | ||
36 | * Implementation of the <code>PhysicalOggStream</code> interface for accessing | ||
37 | * normal disk files. | ||
38 | */ | ||
39 | |||
40 | public class FileStream implements PhysicalOggStream { | ||
41 | |||
42 | private boolean closed=false; | ||
43 | private RandomAccessFile source; | ||
44 | private long[] pageOffsets; | ||
45 | private long numberOfSamples=-1; | ||
46 | |||
47 | private HashMap logicalStreams=new HashMap(); | ||
48 | |||
49 | /** | ||
50 | * Creates access to the specified file through the <code>PhysicalOggStream</code> interface. | ||
51 | * The specified source file must have been opened for reading. | ||
52 | * | ||
53 | * @param source the file to read from | ||
54 | * | ||
55 | * @throws OggFormatException if the stream format is incorrect | ||
56 | * @throws IOException if some other IO error occurs when reading the file | ||
57 | */ | ||
58 | |||
59 | public FileStream(RandomAccessFile source) throws OggFormatException, IOException { | ||
60 | this.source=source; | ||
61 | |||
62 | ArrayList po=new ArrayList(); | ||
63 | int pageNumber=0; | ||
64 | try { | ||
65 | while(true) { | ||
66 | po.add(new Long(this.source.getFilePointer())); | ||
67 | |||
68 | // skip data if pageNumber>0 | ||
69 | OggPage op=getNextPage(pageNumber>0); | ||
70 | if(op==null) { | ||
71 | break; | ||
72 | } | ||
73 | |||
74 | LogicalOggStreamImpl los=(LogicalOggStreamImpl)getLogicalStream(op.getStreamSerialNumber()); | ||
75 | if(los==null) { | ||
76 | los=new LogicalOggStreamImpl(this, op.getStreamSerialNumber()); | ||
77 | logicalStreams.put(new Integer(op.getStreamSerialNumber()), los); | ||
78 | } | ||
79 | |||
80 | if(pageNumber==0) { | ||
81 | los.checkFormat(op); | ||
82 | } | ||
83 | |||
84 | los.addPageNumberMapping(pageNumber); | ||
85 | los.addGranulePosition(op.getAbsoluteGranulePosition()); | ||
86 | |||
87 | if(pageNumber>0) { | ||
88 | this.source.seek(this.source.getFilePointer()+op.getTotalLength()); | ||
89 | } | ||
90 | |||
91 | pageNumber++; | ||
92 | } | ||
93 | } | ||
94 | catch(EndOfOggStreamException e) { | ||
95 | // ok | ||
96 | } | ||
97 | catch(IOException e) { | ||
98 | throw e; | ||
99 | } | ||
100 | //System.out.println("pageNumber: "+pageNumber); | ||
101 | this.source.seek(0L); | ||
102 | pageOffsets=new long[po.size()]; | ||
103 | int i=0; | ||
104 | Iterator iter=po.iterator(); | ||
105 | while(iter.hasNext()) { | ||
106 | pageOffsets[i++]=((Long)iter.next()).longValue(); | ||
107 | } | ||
108 | } | ||
109 | |||
110 | public Collection getLogicalStreams() { | ||
111 | return logicalStreams.values(); | ||
112 | } | ||
113 | |||
114 | public boolean isOpen() { | ||
115 | return !closed; | ||
116 | } | ||
117 | |||
118 | public void close() throws IOException { | ||
119 | closed=true; | ||
120 | source.close(); | ||
121 | } | ||
122 | |||
123 | private OggPage getNextPage() throws EndOfOggStreamException, IOException, OggFormatException { | ||
124 | return getNextPage(false); | ||
125 | } | ||
126 | |||
127 | private OggPage getNextPage(boolean skipData) throws EndOfOggStreamException, IOException, OggFormatException { | ||
128 | return OggPage.create(source, skipData); | ||
129 | } | ||
130 | |||
131 | public OggPage getOggPage(int index) throws IOException { | ||
132 | source.seek(pageOffsets[index]); | ||
133 | return OggPage.create(source); | ||
134 | } | ||
135 | |||
136 | private LogicalOggStream getLogicalStream(int serialNumber) { | ||
137 | return (LogicalOggStream)logicalStreams.get(new Integer(serialNumber)); | ||
138 | } | ||
139 | |||
140 | public void setTime(long granulePosition) throws IOException { | ||
141 | for(Iterator iter=logicalStreams.values().iterator(); iter.hasNext(); ) { | ||
142 | LogicalOggStream los=(LogicalOggStream)iter.next(); | ||
143 | los.setTime(granulePosition); | ||
144 | } | ||
145 | } | ||
146 | |||
147 | /** | ||
148 | * @return always <code>true</code> | ||
149 | */ | ||
150 | |||
151 | public boolean isSeekable() { | ||
152 | return true; | ||
153 | } | ||
154 | } \ No newline at end of file | ||
diff --git a/songdbj/de/jarnbjo/ogg/LogicalOggStream.java b/songdbj/de/jarnbjo/ogg/LogicalOggStream.java deleted file mode 100644 index 2f97b2a728..0000000000 --- a/songdbj/de/jarnbjo/ogg/LogicalOggStream.java +++ /dev/null | |||
@@ -1,151 +0,0 @@ | |||
1 | /* | ||
2 | * $ProjectName$ | ||
3 | * $ProjectRevision$ | ||
4 | * ----------------------------------------------------------- | ||
5 | * $Id$ | ||
6 | * ----------------------------------------------------------- | ||
7 | * | ||
8 | * $Author$ | ||
9 | * | ||
10 | * Description: | ||
11 | * | ||
12 | * Copyright 2002-2003 Tor-Einar Jarnbjo | ||
13 | * ----------------------------------------------------------- | ||
14 | * | ||
15 | * Change History | ||
16 | * ----------------------------------------------------------- | ||
17 | * $Log$ | ||
18 | * Revision 1.1 2005/07/11 15:42:36 hcl | ||
19 | * Songdb java version, source. only 1.5 compatible | ||
20 | * | ||
21 | * Revision 1.1.1.1 2004/04/04 22:09:12 shred | ||
22 | * First Import | ||
23 | * | ||
24 | * Revision 1.2 2003/04/10 19:48:22 jarnbjo | ||
25 | * no message | ||
26 | * | ||
27 | * Revision 1.1 2003/03/03 21:02:20 jarnbjo | ||
28 | * no message | ||
29 | * | ||
30 | */ | ||
31 | |||
32 | package de.jarnbjo.ogg; | ||
33 | |||
34 | import java.io.IOException; | ||
35 | |||
36 | /** | ||
37 | * Interface providing access to a logical Ogg stream as part of a | ||
38 | * physical Ogg stream. | ||
39 | */ | ||
40 | |||
41 | |||
42 | public interface LogicalOggStream { | ||
43 | |||
44 | public static final String FORMAT_UNKNOWN = "application/octet-stream"; | ||
45 | |||
46 | public static final String FORMAT_VORBIS = "audio/x-vorbis"; | ||
47 | public static final String FORMAT_FLAC = "audio/x-flac"; | ||
48 | public static final String FORMAT_THEORA = "video/x-theora"; | ||
49 | |||
50 | /** | ||
51 | * <i>Note:</i> To read from the stream, you must use either | ||
52 | * this method or the method <code>getNextOggPacket</code>. | ||
53 | * Mixing calls to the two methods will cause data corruption. | ||
54 | * | ||
55 | * @return the next Ogg page | ||
56 | * | ||
57 | * @see #getNextOggPacket() | ||
58 | * | ||
59 | * @throws OggFormatException if the ogg stream is corrupted | ||
60 | * @throws IOException if some other IO error occurs | ||
61 | */ | ||
62 | |||
63 | public OggPage getNextOggPage() throws OggFormatException, IOException; | ||
64 | |||
65 | /** | ||
66 | * <i>Note:</i> To read from the stream, you must use either | ||
67 | * this method or the method <code>getNextOggPage</code>. | ||
68 | * Mixing calls to the two methods will cause data corruption. | ||
69 | * | ||
70 | * @return the next packet as a byte array | ||
71 | * | ||
72 | * @see #getNextOggPage() | ||
73 | * | ||
74 | * @throws OggFormatException if the ogg stream is corrupted | ||
75 | * @throws IOException if some other IO error occurs | ||
76 | */ | ||
77 | |||
78 | public byte[] getNextOggPacket() throws OggFormatException, IOException; | ||
79 | |||
80 | /** | ||
81 | * Checks if this stream is open for reading. | ||
82 | * | ||
83 | * @return <code>true</code> if this stream is open for reading, | ||
84 | * <code>false</code> otherwise | ||
85 | */ | ||
86 | |||
87 | public boolean isOpen(); | ||
88 | |||
89 | /** | ||
90 | * Closes this stream. After invoking this method, no further access | ||
91 | * to the streams data is possible. | ||
92 | * | ||
93 | * @throws IOException if an IO error occurs | ||
94 | */ | ||
95 | |||
96 | public void close() throws IOException; | ||
97 | |||
98 | /** | ||
99 | * Sets the stream's position to the beginning of the stream. | ||
100 | * This method does not work if the physical Ogg stream is not | ||
101 | * seekable. | ||
102 | * | ||
103 | * @throws OggFormatException if the ogg stream is corrupted | ||
104 | * @throws IOException if some other IO error occurs | ||
105 | */ | ||
106 | |||
107 | public void reset() throws OggFormatException, IOException; | ||
108 | |||
109 | /** | ||
110 | * This method does not work if the physical Ogg stream is not | ||
111 | * seekable. | ||
112 | * | ||
113 | * @return the granule position of the last page within | ||
114 | * this stream | ||
115 | */ | ||
116 | |||
117 | public long getMaximumGranulePosition(); | ||
118 | |||
119 | /** | ||
120 | * This method is invoked on all logical streams when | ||
121 | * calling the same method on the physical stream. The | ||
122 | * same restrictions as mentioned there apply. | ||
123 | * This method does not work if the physical Ogg stream is not | ||
124 | * seekable. | ||
125 | * | ||
126 | * @param granulePosition | ||
127 | * | ||
128 | * @see PhysicalOggStream#setTime(long) | ||
129 | * | ||
130 | * @throws IOException if an IO error occurs | ||
131 | */ | ||
132 | |||
133 | public void setTime(long granulePosition) throws IOException; | ||
134 | |||
135 | /** | ||
136 | * @return the last parsed granule position of this stream | ||
137 | */ | ||
138 | |||
139 | public long getTime(); | ||
140 | |||
141 | /** | ||
142 | * @return the content type of this stream | ||
143 | * | ||
144 | * @see #FORMAT_UNKNOWN | ||
145 | * @see #FORMAT_VORBIS | ||
146 | * @see #FORMAT_FLAC | ||
147 | * @see #FORMAT_THEORA | ||
148 | */ | ||
149 | |||
150 | public String getFormat(); | ||
151 | } \ No newline at end of file | ||
diff --git a/songdbj/de/jarnbjo/ogg/LogicalOggStreamImpl.java b/songdbj/de/jarnbjo/ogg/LogicalOggStreamImpl.java deleted file mode 100644 index 1a503e91ca..0000000000 --- a/songdbj/de/jarnbjo/ogg/LogicalOggStreamImpl.java +++ /dev/null | |||
@@ -1,213 +0,0 @@ | |||
1 | /* | ||
2 | * $ProjectName$ | ||
3 | * $ProjectRevision$ | ||
4 | * ----------------------------------------------------------- | ||
5 | * $Id$ | ||
6 | * ----------------------------------------------------------- | ||
7 | * | ||
8 | * $Author$ | ||
9 | * | ||
10 | * Description: | ||
11 | * | ||
12 | * Copyright 2002-2003 Tor-Einar Jarnbjo | ||
13 | * ----------------------------------------------------------- | ||
14 | * | ||
15 | * Change History | ||
16 | * ----------------------------------------------------------- | ||
17 | * $Log$ | ||
18 | * Revision 1.1 2005/07/11 15:42:36 hcl | ||
19 | * Songdb java version, source. only 1.5 compatible | ||
20 | * | ||
21 | * Revision 1.1.1.1 2004/04/04 22:09:12 shred | ||
22 | * First Import | ||
23 | * | ||
24 | * Revision 1.3 2003/03/31 00:23:04 jarnbjo | ||
25 | * no message | ||
26 | * | ||
27 | * Revision 1.2 2003/03/16 01:11:26 jarnbjo | ||
28 | * no message | ||
29 | * | ||
30 | * Revision 1.1 2003/03/03 21:02:20 jarnbjo | ||
31 | * no message | ||
32 | * | ||
33 | */ | ||
34 | |||
35 | package de.jarnbjo.ogg; | ||
36 | |||
37 | import java.io.*; | ||
38 | import java.util.*; | ||
39 | |||
40 | public class LogicalOggStreamImpl implements LogicalOggStream { | ||
41 | |||
42 | private PhysicalOggStream source; | ||
43 | private int serialNumber; | ||
44 | |||
45 | private ArrayList pageNumberMapping=new ArrayList(); | ||
46 | private ArrayList granulePositions=new ArrayList(); | ||
47 | |||
48 | private int pageIndex=0; | ||
49 | private OggPage currentPage; | ||
50 | private int currentSegmentIndex; | ||
51 | |||
52 | private boolean open=true; | ||
53 | |||
54 | private String format=FORMAT_UNKNOWN; | ||
55 | |||
56 | public LogicalOggStreamImpl(PhysicalOggStream source, int serialNumber) { | ||
57 | this.source=source; | ||
58 | this.serialNumber=serialNumber; | ||
59 | } | ||
60 | |||
61 | public void addPageNumberMapping(int physicalPageNumber) { | ||
62 | pageNumberMapping.add(new Integer(physicalPageNumber)); | ||
63 | } | ||
64 | |||
65 | public void addGranulePosition(long granulePosition) { | ||
66 | granulePositions.add(new Long(granulePosition)); | ||
67 | } | ||
68 | |||
69 | public synchronized void reset() throws OggFormatException, IOException { | ||
70 | currentPage=null; | ||
71 | currentSegmentIndex=0; | ||
72 | pageIndex=0; | ||
73 | } | ||
74 | |||
75 | public synchronized OggPage getNextOggPage() throws EndOfOggStreamException, OggFormatException, IOException { | ||
76 | if(source.isSeekable()) { | ||
77 | currentPage=source.getOggPage(((Integer)pageNumberMapping.get(pageIndex++)).intValue()); | ||
78 | } | ||
79 | else { | ||
80 | currentPage=source.getOggPage(-1); | ||
81 | } | ||
82 | return currentPage; | ||
83 | } | ||
84 | |||
85 | public synchronized byte[] getNextOggPacket() throws EndOfOggStreamException, OggFormatException, IOException { | ||
86 | ByteArrayOutputStream res=new ByteArrayOutputStream(); | ||
87 | int segmentLength=0; | ||
88 | |||
89 | if(currentPage==null) { | ||
90 | currentPage=getNextOggPage(); | ||
91 | } | ||
92 | |||
93 | do { | ||
94 | if(currentSegmentIndex>=currentPage.getSegmentOffsets().length) { | ||
95 | currentSegmentIndex=0; | ||
96 | |||
97 | if(!currentPage.isEos()) { | ||
98 | if(source.isSeekable() && pageNumberMapping.size()<=pageIndex) { | ||
99 | while(pageNumberMapping.size()<=pageIndex+10) { | ||
100 | try { | ||
101 | Thread.sleep(1000); | ||
102 | } | ||
103 | catch (InterruptedException ex) { | ||
104 | } | ||
105 | } | ||
106 | } | ||
107 | currentPage=getNextOggPage(); | ||
108 | |||
109 | if(res.size()==0 && currentPage.isContinued()) { | ||
110 | boolean done=false; | ||
111 | while(!done) { | ||
112 | if(currentPage.getSegmentLengths()[currentSegmentIndex++]!=255) { | ||
113 | done=true; | ||
114 | } | ||
115 | if(currentSegmentIndex>currentPage.getSegmentTable().length) { | ||
116 | currentPage=source.getOggPage(((Integer)pageNumberMapping.get(pageIndex++)).intValue()); | ||
117 | } | ||
118 | } | ||
119 | } | ||
120 | } | ||
121 | else { | ||
122 | throw new EndOfOggStreamException(); | ||
123 | } | ||
124 | } | ||
125 | segmentLength=currentPage.getSegmentLengths()[currentSegmentIndex]; | ||
126 | res.write(currentPage.getData(), currentPage.getSegmentOffsets()[currentSegmentIndex], segmentLength); | ||
127 | currentSegmentIndex++; | ||
128 | } while(segmentLength==255); | ||
129 | |||
130 | return res.toByteArray(); | ||
131 | } | ||
132 | |||
133 | public boolean isOpen() { | ||
134 | return open; | ||
135 | } | ||
136 | |||
137 | public void close() throws IOException { | ||
138 | open=false; | ||
139 | } | ||
140 | |||
141 | public long getMaximumGranulePosition() { | ||
142 | Long mgp=(Long)granulePositions.get(granulePositions.size()-1); | ||
143 | return mgp.longValue(); | ||
144 | } | ||
145 | |||
146 | public synchronized long getTime() { | ||
147 | return currentPage!=null?currentPage.getAbsoluteGranulePosition():-1; | ||
148 | } | ||
149 | |||
150 | public synchronized void setTime(long granulePosition) throws IOException { | ||
151 | |||
152 | int page=0; | ||
153 | for(page=0; page<granulePositions.size(); page++) { | ||
154 | Long gp=(Long)granulePositions.get(page); | ||
155 | if(gp.longValue()>granulePosition) { | ||
156 | break; | ||
157 | } | ||
158 | } | ||
159 | |||
160 | pageIndex=page; | ||
161 | currentPage=source.getOggPage(((Integer)pageNumberMapping.get(pageIndex++)).intValue()); | ||
162 | currentSegmentIndex=0; | ||
163 | int segmentLength=0; | ||
164 | do { | ||
165 | if(currentSegmentIndex>=currentPage.getSegmentOffsets().length) { | ||
166 | currentSegmentIndex=0; | ||
167 | if(pageIndex>=pageNumberMapping.size()) { | ||
168 | throw new EndOfOggStreamException(); | ||
169 | } | ||
170 | currentPage=source.getOggPage(((Integer)pageNumberMapping.get(pageIndex++)).intValue()); | ||
171 | } | ||
172 | segmentLength=currentPage.getSegmentLengths()[currentSegmentIndex]; | ||
173 | currentSegmentIndex++; | ||
174 | } while(segmentLength==255); | ||
175 | } | ||
176 | |||
177 | public void checkFormat(OggPage page) { | ||
178 | byte[] data=page.getData(); | ||
179 | |||
180 | if(data.length>=7 && | ||
181 | data[1]==0x76 && | ||
182 | data[2]==0x6f && | ||
183 | data[3]==0x72 && | ||
184 | data[4]==0x62 && | ||
185 | data[5]==0x69 && | ||
186 | data[6]==0x73) { | ||
187 | |||
188 | format=FORMAT_VORBIS; | ||
189 | } | ||
190 | else if(data.length>=7 && | ||
191 | data[1]==0x74 && | ||
192 | data[2]==0x68 && | ||
193 | data[3]==0x65 && | ||
194 | data[4]==0x6f && | ||
195 | data[5]==0x72 && | ||
196 | data[6]==0x61) { | ||
197 | |||
198 | format=FORMAT_THEORA; | ||
199 | } | ||
200 | else if (data.length==4 && | ||
201 | data[0]==0x66 && | ||
202 | data[1]==0x4c && | ||
203 | data[2]==0x61 && | ||
204 | data[3]==0x43) { | ||
205 | |||
206 | format=FORMAT_FLAC; | ||
207 | } | ||
208 | } | ||
209 | |||
210 | public String getFormat() { | ||
211 | return format; | ||
212 | } | ||
213 | } \ No newline at end of file | ||
diff --git a/songdbj/de/jarnbjo/ogg/OggFormatException.java b/songdbj/de/jarnbjo/ogg/OggFormatException.java deleted file mode 100644 index a6b2466b92..0000000000 --- a/songdbj/de/jarnbjo/ogg/OggFormatException.java +++ /dev/null | |||
@@ -1,50 +0,0 @@ | |||
1 | /* | ||
2 | * $ProjectName$ | ||
3 | * $ProjectRevision$ | ||
4 | * ----------------------------------------------------------- | ||
5 | * $Id$ | ||
6 | * ----------------------------------------------------------- | ||
7 | * | ||
8 | * $Author$ | ||
9 | * | ||
10 | * Description: | ||
11 | * | ||
12 | * Copyright 2002-2003 Tor-Einar Jarnbjo | ||
13 | * ----------------------------------------------------------- | ||
14 | * | ||
15 | * Change History | ||
16 | * ----------------------------------------------------------- | ||
17 | * $Log$ | ||
18 | * Revision 1.1 2005/07/11 15:42:36 hcl | ||
19 | * Songdb java version, source. only 1.5 compatible | ||
20 | * | ||
21 | * Revision 1.2 2005/02/09 23:10:47 shred | ||
22 | * Serial UID für jarnbjo | ||
23 | * | ||
24 | * Revision 1.1.1.1 2004/04/04 22:09:12 shred | ||
25 | * First Import | ||
26 | * | ||
27 | * Revision 1.1 2003/03/03 21:02:20 jarnbjo | ||
28 | * no message | ||
29 | * | ||
30 | */ | ||
31 | |||
32 | package de.jarnbjo.ogg; | ||
33 | |||
34 | import java.io.IOException; | ||
35 | |||
36 | /** | ||
37 | * Exception thrown when trying to read a corrupted Ogg stream. | ||
38 | */ | ||
39 | |||
40 | public class OggFormatException extends IOException { | ||
41 | private static final long serialVersionUID = 3544953238333175349L; | ||
42 | |||
43 | public OggFormatException() { | ||
44 | super(); | ||
45 | } | ||
46 | |||
47 | public OggFormatException(String message) { | ||
48 | super(message); | ||
49 | } | ||
50 | } \ No newline at end of file | ||
diff --git a/songdbj/de/jarnbjo/ogg/OggPage.java b/songdbj/de/jarnbjo/ogg/OggPage.java deleted file mode 100644 index cc965cc7a9..0000000000 --- a/songdbj/de/jarnbjo/ogg/OggPage.java +++ /dev/null | |||
@@ -1,431 +0,0 @@ | |||
1 | /* | ||
2 | * $ProjectName$ | ||
3 | * $ProjectRevision$ | ||
4 | * ----------------------------------------------------------- | ||
5 | * $Id$ | ||
6 | * ----------------------------------------------------------- | ||
7 | * | ||
8 | * $Author$ | ||
9 | * | ||
10 | * Description: | ||
11 | * | ||
12 | * Copyright 2002-2003 Tor-Einar Jarnbjo | ||
13 | * ----------------------------------------------------------- | ||
14 | * | ||
15 | * Change History | ||
16 | * ----------------------------------------------------------- | ||
17 | * $Log$ | ||
18 | * Revision 1.1 2005/07/11 15:42:36 hcl | ||
19 | * Songdb java version, source. only 1.5 compatible | ||
20 | * | ||
21 | * Revision 1.1.1.1 2004/04/04 22:09:12 shred | ||
22 | * First Import | ||
23 | * | ||
24 | * Revision 1.3 2003/04/10 19:48:22 jarnbjo | ||
25 | * no message | ||
26 | * | ||
27 | * Revision 1.2 2003/03/31 00:23:04 jarnbjo | ||
28 | * no message | ||
29 | * | ||
30 | * Revision 1.1 2003/03/03 21:02:20 jarnbjo | ||
31 | * no message | ||
32 | * | ||
33 | */ | ||
34 | |||
35 | package de.jarnbjo.ogg; | ||
36 | |||
37 | import java.io.*; | ||
38 | |||
39 | import de.jarnbjo.util.io.*; | ||
40 | |||
41 | /** | ||
42 | * <p>An instance of this class represents an ogg page read from an ogg file | ||
43 | * or network stream. It has no public constructor, but instances can be | ||
44 | * created by the <code>create</code> methods, supplying a JMF stream or | ||
45 | * a <code>RandomAccessFile</code> | ||
46 | * which is positioned at the beginning of an Ogg page.</p> | ||
47 | * | ||
48 | * <p>Furtheron, the class provides methods for accessing the raw page data, | ||
49 | * as well as data attributes like segmenting information, sequence number, | ||
50 | * stream serial number, chechsum and wether this page is the beginning or | ||
51 | * end of a logical bitstream (BOS, EOS) and if the page data starts with a | ||
52 | * continued packet or a fresh data packet.</p> | ||
53 | */ | ||
54 | |||
55 | public class OggPage { | ||
56 | |||
57 | private int version; | ||
58 | private boolean continued, bos, eos; | ||
59 | private long absoluteGranulePosition; | ||
60 | private int streamSerialNumber, pageSequenceNumber, pageCheckSum; | ||
61 | private int[] segmentOffsets; | ||
62 | private int[] segmentLengths; | ||
63 | private int totalLength; | ||
64 | private byte[] header, segmentTable, data; | ||
65 | |||
66 | protected OggPage() { | ||
67 | } | ||
68 | |||
69 | private OggPage( | ||
70 | int version, | ||
71 | boolean continued, | ||
72 | boolean bos, | ||
73 | boolean eos, | ||
74 | long absoluteGranulePosition, | ||
75 | int streamSerialNumber, | ||
76 | int pageSequenceNumber, | ||
77 | int pageCheckSum, | ||
78 | int[] segmentOffsets, | ||
79 | int[] segmentLengths, | ||
80 | int totalLength, | ||
81 | byte[] header, | ||
82 | byte[] segmentTable, | ||
83 | byte[] data) { | ||
84 | |||
85 | this.version=version; | ||
86 | this.continued=continued; | ||
87 | this.bos=bos; | ||
88 | this.eos=eos; | ||
89 | this.absoluteGranulePosition=absoluteGranulePosition; | ||
90 | this.streamSerialNumber=streamSerialNumber; | ||
91 | this.pageSequenceNumber=pageSequenceNumber; | ||
92 | this.pageCheckSum=pageCheckSum; | ||
93 | this.segmentOffsets=segmentOffsets; | ||
94 | this.segmentLengths=segmentLengths; | ||
95 | this.totalLength=totalLength; | ||
96 | this.header=header; | ||
97 | this.segmentTable=segmentTable; | ||
98 | this.data=data; | ||
99 | } | ||
100 | |||
101 | /** | ||
102 | * this method equals to create(RandomAccessFile source, false) | ||
103 | * | ||
104 | * @see #create(RandomAccessFile, boolean) | ||
105 | */ | ||
106 | |||
107 | public static OggPage create(RandomAccessFile source) throws IOException, EndOfOggStreamException, OggFormatException { | ||
108 | return create(source, false); | ||
109 | } | ||
110 | |||
111 | /** | ||
112 | * This method is called to read data from the current position in the | ||
113 | * specified RandomAccessFile and create a new OggPage instance based on the data | ||
114 | * read. If the parameter <code>skipData</code> is set to <code>true</code>, | ||
115 | * the actual page segments (page data) is skipped and not read into | ||
116 | * memory. This mode is useful when scanning through an ogg file to build | ||
117 | * a seek table. | ||
118 | * | ||
119 | * @param source the source from which the ogg page is generated | ||
120 | * @param skipData if set to <code>true</code>, the actual page data is not read into memory | ||
121 | * @return an ogg page created by reading data from the specified source, starting at the current position | ||
122 | * @throws FormatException if the data read from the specified source is not matching the specification for an ogg page | ||
123 | * @throws EndOfStreamException if it is not possible to read an entire ogg page from the specified source | ||
124 | * @throws IOException if some other I/O error is detected when reading from the source | ||
125 | * | ||
126 | * @see #create(RandomAccessFile) | ||
127 | */ | ||
128 | |||
129 | public static OggPage create(RandomAccessFile source, boolean skipData) throws IOException, EndOfOggStreamException, OggFormatException { | ||
130 | return create((Object)source, skipData); | ||
131 | } | ||
132 | |||
133 | /** | ||
134 | * this method equals to create(InputStream source, false) | ||
135 | * | ||
136 | * @see #create(InputStream, boolean) | ||
137 | */ | ||
138 | |||
139 | public static OggPage create(InputStream source) throws IOException, EndOfOggStreamException, OggFormatException { | ||
140 | return create(source, false); | ||
141 | } | ||
142 | |||
143 | /** | ||
144 | * This method is called to read data from the current position in the | ||
145 | * specified InpuStream and create a new OggPage instance based on the data | ||
146 | * read. If the parameter <code>skipData</code> is set to <code>true</code>, | ||
147 | * the actual page segments (page data) is skipped and not read into | ||
148 | * memory. This mode is useful when scanning through an ogg file to build | ||
149 | * a seek table. | ||
150 | * | ||
151 | * @param source the source from which the ogg page is generated | ||
152 | * @param skipData if set to <code>true</code>, the actual page data is not read into memory | ||
153 | * @return an ogg page created by reading data from the specified source, starting at the current position | ||
154 | * @throws FormatException if the data read from the specified source is not matching the specification for an ogg page | ||
155 | * @throws EndOfStreamException if it is not possible to read an entire ogg page from the specified source | ||
156 | * @throws IOException if some other I/O error is detected when reading from the source | ||
157 | * | ||
158 | * @see #create(InputStream) | ||
159 | */ | ||
160 | |||
161 | public static OggPage create(InputStream source, boolean skipData) throws IOException, EndOfOggStreamException, OggFormatException { | ||
162 | return create((Object)source, skipData); | ||
163 | } | ||
164 | |||
165 | /** | ||
166 | * this method equals to create(byte[] source, false) | ||
167 | * | ||
168 | * @see #create(byte[], boolean) | ||
169 | */ | ||
170 | |||
171 | public static OggPage create(byte[] source) throws IOException, EndOfOggStreamException, OggFormatException { | ||
172 | return create(source, false); | ||
173 | } | ||
174 | |||
175 | /** | ||
176 | * This method is called to | ||
177 | * create a new OggPage instance based on the specified byte array. | ||
178 | * | ||
179 | * @param source the source from which the ogg page is generated | ||
180 | * @param skipData if set to <code>true</code>, the actual page data is not read into memory | ||
181 | * @return an ogg page created by reading data from the specified source, starting at the current position | ||
182 | * @throws FormatException if the data read from the specified source is not matching the specification for an ogg page | ||
183 | * @throws EndOfStreamException if it is not possible to read an entire ogg page from the specified source | ||
184 | * @throws IOException if some other I/O error is detected when reading from the source | ||
185 | * | ||
186 | * @see #create(byte[]) | ||
187 | */ | ||
188 | |||
189 | public static OggPage create(byte[] source, boolean skipData) throws IOException, EndOfOggStreamException, OggFormatException { | ||
190 | return create((Object)source, skipData); | ||
191 | } | ||
192 | |||
193 | private static OggPage create(Object source, boolean skipData) throws IOException, EndOfOggStreamException, OggFormatException { | ||
194 | |||
195 | try { | ||
196 | int sourceOffset=27; | ||
197 | |||
198 | byte[] header=new byte[27]; | ||
199 | if(source instanceof RandomAccessFile) { | ||
200 | RandomAccessFile raf=(RandomAccessFile)source; | ||
201 | if(raf.getFilePointer()==raf.length()) { | ||
202 | return null; | ||
203 | } | ||
204 | raf.readFully(header); | ||
205 | } | ||
206 | else if(source instanceof InputStream) { | ||
207 | readFully((InputStream)source, header); | ||
208 | } | ||
209 | else if(source instanceof byte[]) { | ||
210 | System.arraycopy((byte[])source, 0, header, 0, 27); | ||
211 | } | ||
212 | |||
213 | BitInputStream bdSource=new ByteArrayBitInputStream(header); | ||
214 | |||
215 | int capture=bdSource.getInt(32); | ||
216 | |||
217 | if(capture!=0x5367674f) { | ||
218 | //throw new FormatException("Ogg page does not start with 'OggS' (0x4f676753)"); | ||
219 | |||
220 | /* | ||
221 | ** This condition is IMHO an error, but older Ogg files often contain | ||
222 | ** pages with a different capture than OggS. I am not sure how to | ||
223 | ** manage these pages, but the decoder seems to work properly, if | ||
224 | ** the incorrect capture is simply ignored. | ||
225 | */ | ||
226 | |||
227 | String cs=Integer.toHexString(capture); | ||
228 | while(cs.length()<8) { | ||
229 | cs="0"+cs; | ||
230 | } | ||
231 | cs=cs.substring(6, 8)+cs.substring(4, 6)+cs.substring(2, 4)+cs.substring(0, 2); | ||
232 | char c1=(char)(Integer.valueOf(cs.substring(0, 2), 16).intValue()); | ||
233 | char c2=(char)(Integer.valueOf(cs.substring(2, 4), 16).intValue()); | ||
234 | char c3=(char)(Integer.valueOf(cs.substring(4, 6), 16).intValue()); | ||
235 | char c4=(char)(Integer.valueOf(cs.substring(6, 8), 16).intValue()); | ||
236 | System.out.println("Ogg packet header is 0x"+cs+" ("+c1+c2+c3+c4+"), should be 0x4f676753 (OggS)"); | ||
237 | } | ||
238 | |||
239 | int version=bdSource.getInt(8); | ||
240 | byte tmp=(byte)bdSource.getInt(8); | ||
241 | boolean bf1=(tmp&1)!=0; | ||
242 | boolean bos=(tmp&2)!=0; | ||
243 | boolean eos=(tmp&4)!=0; | ||
244 | long absoluteGranulePosition=bdSource.getLong(64); | ||
245 | int streamSerialNumber=bdSource.getInt(32); | ||
246 | int pageSequenceNumber=bdSource.getInt(32); | ||
247 | int pageCheckSum=bdSource.getInt(32); | ||
248 | int pageSegments=bdSource.getInt(8); | ||
249 | |||
250 | //System.out.println("OggPage: "+streamSerialNumber+" / "+absoluteGranulePosition+" / "+pageSequenceNumber); | ||
251 | |||
252 | int[] segmentOffsets=new int[pageSegments]; | ||
253 | int[] segmentLengths=new int[pageSegments]; | ||
254 | int totalLength=0; | ||
255 | |||
256 | byte[] segmentTable=new byte[pageSegments]; | ||
257 | byte[] tmpBuf=new byte[1]; | ||
258 | |||
259 | for(int i=0; i<pageSegments; i++) { | ||
260 | int l=0; | ||
261 | if(source instanceof RandomAccessFile) { | ||
262 | l=((int)((RandomAccessFile)source).readByte()&0xff); | ||
263 | } | ||
264 | else if(source instanceof InputStream) { | ||
265 | l=(int)((InputStream)source).read(); | ||
266 | } | ||
267 | else if(source instanceof byte[]) { | ||
268 | l=(int)((byte[])source)[sourceOffset++]; | ||
269 | l&=255; | ||
270 | } | ||
271 | segmentTable[i]=(byte)l; | ||
272 | segmentLengths[i]=l; | ||
273 | segmentOffsets[i]=totalLength; | ||
274 | totalLength+=l; | ||
275 | } | ||
276 | |||
277 | byte[] data=null; | ||
278 | |||
279 | if(!skipData) { | ||
280 | |||
281 | //System.out.println("createPage: "+absoluteGranulePosition*1000/44100); | ||
282 | |||
283 | data=new byte[totalLength]; | ||
284 | //source.read(data, 0, totalLength); | ||
285 | if(source instanceof RandomAccessFile) { | ||
286 | ((RandomAccessFile)source).readFully(data); | ||
287 | } | ||
288 | else if(source instanceof InputStream) { | ||
289 | readFully((InputStream)source, data); | ||
290 | } | ||
291 | else if(source instanceof byte[]) { | ||
292 | System.arraycopy(source, sourceOffset, data, 0, totalLength); | ||
293 | } | ||
294 | } | ||
295 | |||
296 | return new OggPage(version, bf1, bos, eos, absoluteGranulePosition, streamSerialNumber, pageSequenceNumber, pageCheckSum, segmentOffsets, segmentLengths, totalLength, header, segmentTable, data); | ||
297 | } | ||
298 | catch(EOFException e) { | ||
299 | throw new EndOfOggStreamException(); | ||
300 | } | ||
301 | } | ||
302 | |||
303 | private static void readFully(InputStream source, byte[] buffer) throws IOException { | ||
304 | int total=0; | ||
305 | while(total<buffer.length) { | ||
306 | int read=source.read(buffer, total, buffer.length-total); | ||
307 | if(read==-1) { | ||
308 | throw new EndOfOggStreamException(); | ||
309 | } | ||
310 | total+=read; | ||
311 | } | ||
312 | } | ||
313 | |||
314 | /** | ||
315 | * Returns the absolute granule position of the last complete | ||
316 | * packet contained in this Ogg page, or -1 if the page contains a single | ||
317 | * packet, which is not completed on this page. For pages containing Vorbis | ||
318 | * data, this value is the sample index within the Vorbis stream. The Vorbis | ||
319 | * stream does not necessarily start with sample index 0. | ||
320 | * | ||
321 | * @return the absolute granule position of the last packet completed on | ||
322 | * this page | ||
323 | */ | ||
324 | |||
325 | |||
326 | public long getAbsoluteGranulePosition() { | ||
327 | return absoluteGranulePosition; | ||
328 | } | ||
329 | |||
330 | /** | ||
331 | * Returns the stream serial number of this ogg page. | ||
332 | * | ||
333 | * @return this page's serial number | ||
334 | */ | ||
335 | |||
336 | public int getStreamSerialNumber() { | ||
337 | return streamSerialNumber; | ||
338 | } | ||
339 | |||
340 | /** | ||
341 | * Return the sequnce number of this ogg page. | ||
342 | * | ||
343 | * @return this page's sequence number | ||
344 | */ | ||
345 | |||
346 | public int getPageSequenceNumber() { | ||
347 | return pageSequenceNumber; | ||
348 | } | ||
349 | |||
350 | /** | ||
351 | * Return the check sum of this ogg page. | ||
352 | * | ||
353 | * @return this page's check sum | ||
354 | */ | ||
355 | |||
356 | public int getPageCheckSum() { | ||
357 | return pageCheckSum; | ||
358 | } | ||
359 | |||
360 | /** | ||
361 | * @return the total number of bytes in the page data | ||
362 | */ | ||
363 | |||
364 | |||
365 | public int getTotalLength() { | ||
366 | if(data!=null) { | ||
367 | return 27+segmentTable.length+data.length; | ||
368 | } | ||
369 | else { | ||
370 | return totalLength; | ||
371 | } | ||
372 | } | ||
373 | |||
374 | /** | ||
375 | * @return a ByteBuffer containing the page data | ||
376 | */ | ||
377 | |||
378 | |||
379 | public byte[] getData() { | ||
380 | return data; | ||
381 | } | ||
382 | |||
383 | public byte[] getHeader() { | ||
384 | return header; | ||
385 | } | ||
386 | |||
387 | public byte[] getSegmentTable() { | ||
388 | return segmentTable; | ||
389 | } | ||
390 | |||
391 | public int[] getSegmentOffsets() { | ||
392 | return segmentOffsets; | ||
393 | } | ||
394 | |||
395 | public int[] getSegmentLengths() { | ||
396 | return segmentLengths; | ||
397 | } | ||
398 | |||
399 | /** | ||
400 | * @return <code>true</code> if this page begins with a continued packet | ||
401 | */ | ||
402 | |||
403 | public boolean isContinued() { | ||
404 | return continued; | ||
405 | } | ||
406 | |||
407 | /** | ||
408 | * @return <code>true</code> if this page begins with a fresh packet | ||
409 | */ | ||
410 | |||
411 | public boolean isFresh() { | ||
412 | return !continued; | ||
413 | } | ||
414 | |||
415 | /** | ||
416 | * @return <code>true</code> if this page is the beginning of a logical stream | ||
417 | */ | ||
418 | |||
419 | public boolean isBos() { | ||
420 | return bos; | ||
421 | } | ||
422 | |||
423 | /** | ||
424 | * @return <code>true</code> if this page is the end of a logical stream | ||
425 | */ | ||
426 | |||
427 | public boolean isEos() { | ||
428 | return eos; | ||
429 | } | ||
430 | |||
431 | } \ No newline at end of file | ||
diff --git a/songdbj/de/jarnbjo/ogg/OnDemandUrlStream.java b/songdbj/de/jarnbjo/ogg/OnDemandUrlStream.java deleted file mode 100644 index 98159c4e7c..0000000000 --- a/songdbj/de/jarnbjo/ogg/OnDemandUrlStream.java +++ /dev/null | |||
@@ -1,127 +0,0 @@ | |||
1 | /* | ||
2 | * $ProjectName$ | ||
3 | * $ProjectRevision$ | ||
4 | * ----------------------------------------------------------- | ||
5 | * $Id$ | ||
6 | * ----------------------------------------------------------- | ||
7 | * | ||
8 | * $Author$ | ||
9 | * | ||
10 | * Description: | ||
11 | * | ||
12 | * Copyright 2002-2003 Tor-Einar Jarnbjo | ||
13 | * ----------------------------------------------------------- | ||
14 | * | ||
15 | * Change History | ||
16 | * ----------------------------------------------------------- | ||
17 | * $Log$ | ||
18 | * Revision 1.1 2005/07/11 15:42:36 hcl | ||
19 | * Songdb java version, source. only 1.5 compatible | ||
20 | * | ||
21 | * Revision 1.1.1.1 2004/04/04 22:09:12 shred | ||
22 | * First Import | ||
23 | * | ||
24 | * Revision 1.1 2003/04/10 19:48:22 jarnbjo | ||
25 | * no message | ||
26 | * | ||
27 | * Revision 1.1 2003/03/31 00:23:04 jarnbjo | ||
28 | * no message | ||
29 | * | ||
30 | */ | ||
31 | |||
32 | package de.jarnbjo.ogg; | ||
33 | |||
34 | import java.io.*; | ||
35 | import java.net.*; | ||
36 | import java.util.*; | ||
37 | |||
38 | /** | ||
39 | * Implementation of the <code>PhysicalOggStream</code> interface for reading | ||
40 | * an Ogg stream from a URL. This class performs | ||
41 | * no internal caching, and will not read data from the network before | ||
42 | * requested to do so. It is intended to be used in non-realtime applications | ||
43 | * like file download managers or similar. | ||
44 | */ | ||
45 | |||
46 | public class OnDemandUrlStream implements PhysicalOggStream { | ||
47 | |||
48 | private boolean closed=false; | ||
49 | private URLConnection source; | ||
50 | private InputStream sourceStream; | ||
51 | private Object drainLock=new Object(); | ||
52 | private LinkedList pageCache=new LinkedList(); | ||
53 | private long numberOfSamples=-1; | ||
54 | private int contentLength=0; | ||
55 | private int position=0; | ||
56 | |||
57 | private HashMap logicalStreams=new HashMap(); | ||
58 | private OggPage firstPage; | ||
59 | |||
60 | private static final int PAGECACHE_SIZE = 20; | ||
61 | |||
62 | public OnDemandUrlStream(URL source) throws OggFormatException, IOException { | ||
63 | this.source=source.openConnection(); | ||
64 | this.sourceStream=this.source.getInputStream(); | ||
65 | |||
66 | contentLength=this.source.getContentLength(); | ||
67 | |||
68 | firstPage=OggPage.create(sourceStream); | ||
69 | position+=firstPage.getTotalLength(); | ||
70 | LogicalOggStreamImpl los=new LogicalOggStreamImpl(this, firstPage.getStreamSerialNumber()); | ||
71 | logicalStreams.put(new Integer(firstPage.getStreamSerialNumber()), los); | ||
72 | los.checkFormat(firstPage); | ||
73 | } | ||
74 | |||
75 | public Collection getLogicalStreams() { | ||
76 | return logicalStreams.values(); | ||
77 | } | ||
78 | |||
79 | public boolean isOpen() { | ||
80 | return !closed; | ||
81 | } | ||
82 | |||
83 | public void close() throws IOException { | ||
84 | closed=true; | ||
85 | sourceStream.close(); | ||
86 | } | ||
87 | |||
88 | public int getContentLength() { | ||
89 | return contentLength; | ||
90 | } | ||
91 | |||
92 | public int getPosition() { | ||
93 | return position; | ||
94 | } | ||
95 | |||
96 | int pageNumber=2; | ||
97 | |||
98 | public OggPage getOggPage(int index) throws IOException { | ||
99 | if(firstPage!=null) { | ||
100 | OggPage tmp=firstPage; | ||
101 | firstPage=null; | ||
102 | return tmp; | ||
103 | } | ||
104 | else { | ||
105 | OggPage page=OggPage.create(sourceStream); | ||
106 | position+=page.getTotalLength(); | ||
107 | return page; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | private LogicalOggStream getLogicalStream(int serialNumber) { | ||
112 | return (LogicalOggStream)logicalStreams.get(new Integer(serialNumber)); | ||
113 | } | ||
114 | |||
115 | public void setTime(long granulePosition) throws IOException { | ||
116 | throw new UnsupportedOperationException("Method not supported by this class"); | ||
117 | } | ||
118 | |||
119 | /** | ||
120 | * @return always <code>false</code> | ||
121 | */ | ||
122 | |||
123 | public boolean isSeekable() { | ||
124 | return false; | ||
125 | } | ||
126 | |||
127 | } \ No newline at end of file | ||
diff --git a/songdbj/de/jarnbjo/ogg/PhysicalOggStream.java b/songdbj/de/jarnbjo/ogg/PhysicalOggStream.java deleted file mode 100644 index 5f342a38b7..0000000000 --- a/songdbj/de/jarnbjo/ogg/PhysicalOggStream.java +++ /dev/null | |||
@@ -1,124 +0,0 @@ | |||
1 | /* | ||
2 | * $ProjectName$ | ||
3 | * $ProjectRevision$ | ||
4 | * ----------------------------------------------------------- | ||
5 | * $Id$ | ||
6 | * ----------------------------------------------------------- | ||
7 | * | ||
8 | * $Author$ | ||
9 | * | ||
10 | * Description: | ||
11 | * | ||
12 | * Copyright 2002-2003 Tor-Einar Jarnbjo | ||
13 | * ----------------------------------------------------------- | ||
14 | * | ||
15 | * Change History | ||
16 | * ----------------------------------------------------------- | ||
17 | * $Log$ | ||
18 | * Revision 1.1 2005/07/11 15:42:36 hcl | ||
19 | * Songdb java version, source. only 1.5 compatible | ||
20 | * | ||
21 | * Revision 1.1.1.1 2004/04/04 22:09:12 shred | ||
22 | * First Import | ||
23 | * | ||
24 | * Revision 1.3 2003/04/10 19:48:22 jarnbjo | ||
25 | * no message | ||
26 | * | ||
27 | * Revision 1.2 2003/03/31 00:23:04 jarnbjo | ||
28 | * no message | ||
29 | * | ||
30 | * Revision 1.1 2003/03/03 21:02:20 jarnbjo | ||
31 | * no message | ||
32 | * | ||
33 | */ | ||
34 | |||
35 | package de.jarnbjo.ogg; | ||
36 | |||
37 | import java.io.IOException; | ||
38 | import java.util.Collection; | ||
39 | |||
40 | /** | ||
41 | * Interface providing access to a physical Ogg stream. Typically this is | ||
42 | * a file. | ||
43 | */ | ||
44 | |||
45 | public interface PhysicalOggStream { | ||
46 | |||
47 | /** | ||
48 | * Returns a collection of objects implementing <code>LogicalOggStream</code> | ||
49 | * for accessing the separate logical streams within this physical Ogg stream. | ||
50 | * | ||
51 | * @return a collection of objects implementing <code>LogicalOggStream</code> | ||
52 | * which are representing the logical streams contained within this | ||
53 | * physical stream | ||
54 | * | ||
55 | * @see LogicalOggStream | ||
56 | */ | ||
57 | |||
58 | public Collection getLogicalStreams(); | ||
59 | |||
60 | /** | ||
61 | * Return the Ogg page with the absolute index <code>index</code>, | ||
62 | * independent from the logical structure of this stream or if the | ||
63 | * index parameter is -1, the next Ogg page is returned. | ||
64 | * This method should only be used by implementations of <code>LogicalOggStream</code> | ||
65 | * to access the raw pages. | ||
66 | * | ||
67 | * @param index the absolute index starting from 0 at the beginning of | ||
68 | * the file or stream or -1 to get the next page in a non-seekable | ||
69 | * stream | ||
70 | * | ||
71 | * @return the Ogg page with the physical absolute index <code>index</code> | ||
72 | * | ||
73 | * @throws OggFormatException if the ogg stream is corrupted | ||
74 | * @throws IOException if some other IO error occurs | ||
75 | */ | ||
76 | |||
77 | public OggPage getOggPage(int index) throws OggFormatException, IOException; | ||
78 | |||
79 | /** | ||
80 | * Checks if this stream is open for reading. | ||
81 | * | ||
82 | * @return <code>true</code> if this stream is open for reading, | ||
83 | * <code>false</code> otherwise | ||
84 | */ | ||
85 | |||
86 | public boolean isOpen(); | ||
87 | |||
88 | /** | ||
89 | * Closes this stream. After invoking this method, no further access | ||
90 | * to the streams data is possible. | ||
91 | * | ||
92 | * @throws IOException | ||
93 | */ | ||
94 | |||
95 | public void close() throws IOException; | ||
96 | |||
97 | /** | ||
98 | * Sets this stream's (and its logical stream's) position to the granule | ||
99 | * position. The next packet read from any logical stream will be the | ||
100 | * first packet beginning on the first page with a granule position higher | ||
101 | * than the argument.<br><br> | ||
102 | * | ||
103 | * At the moment, this method only works correctly for Ogg files with | ||
104 | * a single logical Vorbis stream, and due to the different interpretations | ||
105 | * of the granule position, depending on mixed content, this method will | ||
106 | * never be able to work for mixed streams. Chained and interleaved streams are | ||
107 | * also not yet supported. Actually, this method is only a hack to support | ||
108 | * seeking from JMF, but may of course be abused otherwise too :) | ||
109 | * | ||
110 | * @param granulePosition | ||
111 | * | ||
112 | * @throws OggFormatException if the ogg stream is corrupted | ||
113 | * @throws IOException if some other IO error occurs | ||
114 | */ | ||
115 | |||
116 | public void setTime(long granulePosition) throws OggFormatException, IOException; | ||
117 | |||
118 | /** | ||
119 | * @return <code>true</code> if the stream is seekable, <code>false</code> | ||
120 | * otherwise | ||
121 | */ | ||
122 | |||
123 | public boolean isSeekable(); | ||
124 | } \ No newline at end of file | ||
diff --git a/songdbj/de/jarnbjo/ogg/UncachedUrlStream.java b/songdbj/de/jarnbjo/ogg/UncachedUrlStream.java deleted file mode 100644 index a07f0ac00e..0000000000 --- a/songdbj/de/jarnbjo/ogg/UncachedUrlStream.java +++ /dev/null | |||
@@ -1,207 +0,0 @@ | |||
1 | /* | ||
2 | * $ProjectName$ | ||
3 | * $ProjectRevision$ | ||
4 | * ----------------------------------------------------------- | ||
5 | * $Id$ | ||
6 | * ----------------------------------------------------------- | ||
7 | * | ||
8 | * $Author$ | ||
9 | * | ||
10 | * Description: | ||
11 | * | ||
12 | * Copyright 2002-2003 Tor-Einar Jarnbjo | ||
13 | * ----------------------------------------------------------- | ||
14 | * | ||
15 | * Change History | ||
16 | * ----------------------------------------------------------- | ||
17 | * $Log$ | ||
18 | * Revision 1.1 2005/07/11 15:42:36 hcl | ||
19 | * Songdb java version, source. only 1.5 compatible | ||
20 | * | ||
21 | * Revision 1.1.1.1 2004/04/04 22:09:12 shred | ||
22 | * First Import | ||
23 | * | ||
24 | * Revision 1.1 2003/04/10 19:48:22 jarnbjo | ||
25 | * no message | ||
26 | * | ||
27 | */ | ||
28 | |||
29 | package de.jarnbjo.ogg; | ||
30 | |||
31 | import java.io.*; | ||
32 | import java.net.*; | ||
33 | import java.util.*; | ||
34 | |||
35 | /** | ||
36 | * Implementation of the <code>PhysicalOggStream</code> interface for reading | ||
37 | * an Ogg stream from a URL. This class performs only the necessary caching | ||
38 | * to provide continous playback. Seeking within the stream is not supported. | ||
39 | */ | ||
40 | |||
41 | public class UncachedUrlStream implements PhysicalOggStream { | ||
42 | |||
43 | private boolean closed=false; | ||
44 | private URLConnection source; | ||
45 | private InputStream sourceStream; | ||
46 | private Object drainLock=new Object(); | ||
47 | private LinkedList pageCache=new LinkedList(); | ||
48 | private long numberOfSamples=-1; | ||
49 | |||
50 | private HashMap logicalStreams=new HashMap(); | ||
51 | |||
52 | private LoaderThread loaderThread; | ||
53 | |||
54 | private static final int PAGECACHE_SIZE = 10; | ||
55 | |||
56 | /** Creates an instance of the <code>PhysicalOggStream</code> interface | ||
57 | * suitable for reading an Ogg stream from a URL. | ||
58 | */ | ||
59 | |||
60 | public UncachedUrlStream(URL source) throws OggFormatException, IOException { | ||
61 | |||
62 | this.source=source.openConnection(); | ||
63 | this.sourceStream=this.source.getInputStream(); | ||
64 | |||
65 | loaderThread=new LoaderThread(sourceStream, pageCache); | ||
66 | new Thread(loaderThread).start(); | ||
67 | |||
68 | while(!loaderThread.isBosDone() || pageCache.size()<PAGECACHE_SIZE) { | ||
69 | try { | ||
70 | Thread.sleep(200); | ||
71 | } | ||
72 | catch (InterruptedException ex) { | ||
73 | } | ||
74 | //System.out.print("caching "+pageCache.size()+"/"+PAGECACHE_SIZE+" pages\r"); | ||
75 | } | ||
76 | //System.out.println(); | ||
77 | } | ||
78 | |||
79 | public Collection getLogicalStreams() { | ||
80 | return logicalStreams.values(); | ||
81 | } | ||
82 | |||
83 | public boolean isOpen() { | ||
84 | return !closed; | ||
85 | } | ||
86 | |||
87 | public void close() throws IOException { | ||
88 | closed=true; | ||
89 | sourceStream.close(); | ||
90 | } | ||
91 | |||
92 | /* | ||
93 | public long getCacheLength() { | ||
94 | return cacheLength; | ||
95 | } | ||
96 | */ | ||
97 | |||
98 | /* | ||
99 | private OggPage getNextPage() throws EndOfOggStreamException, IOException, OggFormatException { | ||
100 | return getNextPage(false); | ||
101 | } | ||
102 | |||
103 | private OggPage getNextPage(boolean skipData) throws EndOfOggStreamException, IOException, OggFormatException { | ||
104 | return OggPage.create(sourceStream, skipData); | ||
105 | } | ||
106 | */ | ||
107 | |||
108 | public OggPage getOggPage(int index) throws IOException { | ||
109 | while(pageCache.size()==0) { | ||
110 | try { | ||
111 | Thread.sleep(100); | ||
112 | } | ||
113 | catch (InterruptedException ex) { | ||
114 | } | ||
115 | } | ||
116 | synchronized(drainLock) { | ||
117 | //OggPage page=(OggPage)pageCache.getFirst(); | ||
118 | //pageCache.removeFirst(); | ||
119 | //return page; | ||
120 | return (OggPage)pageCache.removeFirst(); | ||
121 | } | ||
122 | } | ||
123 | |||
124 | private LogicalOggStream getLogicalStream(int serialNumber) { | ||
125 | return (LogicalOggStream)logicalStreams.get(new Integer(serialNumber)); | ||
126 | } | ||
127 | |||
128 | public void setTime(long granulePosition) throws IOException { | ||
129 | throw new UnsupportedOperationException("Method not supported by this class"); | ||
130 | } | ||
131 | |||
132 | public class LoaderThread implements Runnable { | ||
133 | |||
134 | private InputStream source; | ||
135 | private LinkedList pageCache; | ||
136 | private RandomAccessFile drain; | ||
137 | private byte[] memoryCache; | ||
138 | |||
139 | private boolean bosDone=false; | ||
140 | |||
141 | private int pageNumber; | ||
142 | |||
143 | public LoaderThread(InputStream source, LinkedList pageCache) { | ||
144 | this.source=source; | ||
145 | this.pageCache=pageCache; | ||
146 | } | ||
147 | |||
148 | public void run() { | ||
149 | try { | ||
150 | boolean eos=false; | ||
151 | byte[] buffer=new byte[8192]; | ||
152 | while(!eos) { | ||
153 | OggPage op=OggPage.create(source); | ||
154 | synchronized (drainLock) { | ||
155 | pageCache.add(op); | ||
156 | } | ||
157 | |||
158 | if(!op.isBos()) { | ||
159 | bosDone=true; | ||
160 | } | ||
161 | if(op.isEos()) { | ||
162 | eos=true; | ||
163 | } | ||
164 | |||
165 | LogicalOggStreamImpl los=(LogicalOggStreamImpl)getLogicalStream(op.getStreamSerialNumber()); | ||
166 | if(los==null) { | ||
167 | los=new LogicalOggStreamImpl(UncachedUrlStream.this, op.getStreamSerialNumber()); | ||
168 | logicalStreams.put(new Integer(op.getStreamSerialNumber()), los); | ||
169 | los.checkFormat(op); | ||
170 | } | ||
171 | |||
172 | //los.addPageNumberMapping(pageNumber); | ||
173 | //los.addGranulePosition(op.getAbsoluteGranulePosition()); | ||
174 | |||
175 | pageNumber++; | ||
176 | |||
177 | while(pageCache.size()>PAGECACHE_SIZE) { | ||
178 | try { | ||
179 | Thread.sleep(200); | ||
180 | } | ||
181 | catch (InterruptedException ex) { | ||
182 | } | ||
183 | } | ||
184 | } | ||
185 | } | ||
186 | catch(EndOfOggStreamException e) { | ||
187 | // ok | ||
188 | } | ||
189 | catch(IOException e) { | ||
190 | e.printStackTrace(); | ||
191 | } | ||
192 | } | ||
193 | |||
194 | public boolean isBosDone() { | ||
195 | return bosDone; | ||
196 | } | ||
197 | } | ||
198 | |||
199 | /** | ||
200 | * @return always <code>false</code> | ||
201 | */ | ||
202 | |||
203 | public boolean isSeekable() { | ||
204 | return false; | ||
205 | } | ||
206 | |||
207 | } \ No newline at end of file | ||