Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

450
LINES

< > BotCompany Repo | #1032913 // OggStreamPage

JavaX fragment (include) [tags: use-pretranspiled]

Transpiled version (4914L) is out of date.

1  
!include once #1032914 // VorbisJava
2  
3  
/*
4  
 * Licensed under the Apache License, Version 2.0 (the "License");
5  
 * you may not use this file except in compliance with the License.
6  
 * You may obtain a copy of the License at
7  
 *
8  
 *     http://www.apache.org/licenses/LICENSE-2.0
9  
 *
10  
 * Unless required by applicable law or agreed to in writing, software
11  
 * distributed under the License is distributed on an "AS IS" BASIS,
12  
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  
 * See the License for the specific language governing permissions and
14  
 * limitations under the License.
15  
 */
16  
 
17  
import java.io.ByteArrayOutputStream;
18  
import java.io.IOException;
19  
import java.io.InputStream;
20  
import java.io.OutputStream;
21  
import java.util.Iterator;
22  
23  
import static org.gagravarr.ogg.IOUtils.readOrEOF;
24  
25  
// replaces OggPage
26  
sclass OggStreamPage {
27  
    private int sid;
28  
    private int seqNum;
29  
    private long checksum;
30  
    private long granulePosition;
31  
32  
    private boolean isBOS;
33  
    private boolean isEOS;
34  
    private boolean isContinue;
35  
36  
    private int numLVs = 0;
37  
    private byte[] lvs = new byte[255];
38  
    private byte[] data;
39  
    private ByteArrayOutputStream tmpData;
40  
41  
    *(int sid, int seqNum) {
42  
      ifdef OggStreamPage_debug
43  
        printVars("OggStreamPage.init", +sid, +seqNum);
44  
      endifdef
45  
        this.sid = sid;
46  
        this.seqNum = seqNum;
47  
        this.tmpData = new ByteArrayOutputStream();
48  
    }
49  
    /**
50  
     * InputStream should be positioned *just after*
51  
     *  the OggS capture pattern.
52  
     */
53  
    *(InputStream inp) throws IOException {
54  
      ifdef OggStreamPage_debug
55  
        printVars("OggStreamPage.init(stream)");
56  
      endifdef
57  
      
58  
        int version = readOrEOF(inp);
59  
        if(version != 0) {
60  
            throw new UnsupportedOperationException("Found Ogg page in format " + version + " but we only support version 0");
61  
        }
62  
63  
        int flags = readOrEOF(inp);
64  
        if((flags & 0x01) == 0x01) {
65  
            isContinue = true;
66  
        }
67  
        if((flags & 0x02) == 0x02) {
68  
            isBOS = true;
69  
        }
70  
        if((flags & 0x04) == 0x04) {
71  
            isEOS = true;
72  
        }
73  
74  
        granulePosition = IOUtils.getInt(
75  
                readOrEOF(inp), readOrEOF(inp), readOrEOF(inp), readOrEOF(inp),
76  
                readOrEOF(inp), readOrEOF(inp), readOrEOF(inp), readOrEOF(inp)
77  
        );
78  
        sid = (int)IOUtils.getInt(
79  
                readOrEOF(inp), readOrEOF(inp), readOrEOF(inp), readOrEOF(inp)
80  
        );
81  
        seqNum = (int)IOUtils.getInt(
82  
                readOrEOF(inp), readOrEOF(inp), readOrEOF(inp), readOrEOF(inp)
83  
        );
84  
        checksum = IOUtils.getInt(
85  
                readOrEOF(inp), readOrEOF(inp), readOrEOF(inp), readOrEOF(inp)
86  
        );
87  
88  
        numLVs = readOrEOF(inp);
89  
        lvs = new byte[numLVs];
90  
        
91  
        ifdef OggStreamPage_debug
92  
          printVars("OggStreamPage", +numLVs);
93  
        endifdef
94  
        readFully(inp, lvs);
95  
        ifdef OggStreamPage_debug
96  
          print("OggStreamPage lvs read");
97  
        endifdef
98  
99  
        data = new byte[ getDataSize() ];
100  
        ifdef OggStreamPage_debug
101  
          printVars("OggStreamPage", dataLength := l(data));
102  
        endifdef
103  
        readFully(inp, data);
104  
        ifdef OggStreamPage_debug
105  
          print("OggStreamPage data read");
106  
        endifdef
107  
    }
108  
    
109  
    void readFully(InputStream inp, byte[] buf) throws IOException {
110  
      if (inp cast InputStreamPlusReadFully)
111  
        inp.readFully(buf);
112  
      else
113  
        IOUtils.readFully(inp, buf);
114  
    }
115  
116  
    /**
117  
     * Adds as much of the packet's data as
118  
     *  we can do.
119  
     */
120  
    protected int addPacket(OggStreamPacket packet, int offset) {
121  
        if(packet.isBeginningOfStream()) {
122  
            isBOS = true;
123  
        }
124  
        if(packet.isEndOfStream()) {
125  
            isEOS = true;
126  
        }
127  
128  
        // Add on in 255 byte chunks
129  
        int size = packet.getData().length;
130  
        for(int i = numLVs; i< 255; i++) {
131  
            int remains = size - offset;
132  
133  
            int toAdd = 255;
134  
            if(remains < 255) {
135  
                toAdd = remains;
136  
            }
137  
            lvs[i] = IOUtils.fromInt(toAdd);
138  
            tmpData.write(packet.getData(), offset, toAdd);
139  
140  
            numLVs++;
141  
            offset += toAdd;
142  
            if(toAdd < 255) {
143  
                break;
144  
            }
145  
        }
146  
147  
        return offset;
148  
    }
149  
150  
    /**
151  
     * Is the checksum for the page valid?
152  
     */
153  
    public boolean isChecksumValid() {
154  
        if(checksum == 0)
155  
            return true;
156  
157  
        int crc = CRCUtils.getCRC(getHeader());
158  
        if(data != null && data.length > 0) {
159  
            crc = CRCUtils.getCRC(data, crc);
160  
        }
161  
162  
        return (checksum == crc);
163  
    }
164  
    protected long getChecksum() {
165  
        return checksum;
166  
    }
167  
168  
    /**
169  
     * Does this Page have space for the given
170  
     *  number of bytes?
171  
     */
172  
    protected boolean hasSpaceFor(int bytes) {
173  
        // Do we have enough lvs spare?
174  
        // (Each LV holds up to 255 bytes, and we're
175  
        //  not allowed more than 255 of them)
176  
        int reqLVs = (int)Math.ceil(bytes / 255.0);
177  
178  
        if(numLVs + reqLVs > 255) {
179  
            return false;
180  
        }
181  
        return true;
182  
    }
183  
184  
    /**
185  
     * Returns the minimum size of a page, which is 27
186  
     *  bytes for the headers
187  
     */
188  
    public static int getMinimumPageSize() {
189  
        return MINIMUM_PAGE_SIZE;
190  
    }
191  
    private static final int MINIMUM_PAGE_SIZE = 27;
192  
193  
    /**
194  
     * How big is the page, including headers?
195  
     */
196  
    public int getPageSize() {
197  
        // Header is 27 bytes + number of headers
198  
        int size = MINIMUM_PAGE_SIZE + numLVs;
199  
        // Data size is given by lvs
200  
        size += getDataSize();
201  
        return size;
202  
    }
203  
    /**
204  
     * How big is the page, excluding headers?
205  
     */
206  
    public int getDataSize() {
207  
        // Data size is given by lvs
208  
        int size = 0;
209  
        for(int i=0; i<numLVs; i++) {
210  
            size += IOUtils.toInt(lvs[i]);
211  
        }
212  
        return size;
213  
    }
214  
215  
216  
    public int getSid() {
217  
        return sid;
218  
    }
219  
    public int getSequenceNumber () {
220  
        return seqNum;
221  
    }
222  
    public long getGranulePosition() {
223  
        return granulePosition;
224  
    }
225  
    public byte[] getData() {
226  
        if(tmpData != null) {
227  
            if(data == null || tmpData.size() != data.length) {
228  
                data = tmpData.toByteArray();
229  
            }
230  
        }
231  
        return data;
232  
    }
233  
234  
    protected void setGranulePosition(long position) {
235  
        this.granulePosition = position;
236  
    }
237  
238  
    /**
239  
     * Is there a subsequent page containing the
240  
     *  remainder of the packets?
241  
     */
242  
    public boolean hasContinuation() {
243  
        // Has a continuation if the last LV
244  
        //  is 255. 
245  
        // Normally one would expect to have 
246  
        //  the full 255 LVs, with the
247  
        //  last one at 255, but technically
248  
        //  you can force a continue without
249  
        //  using all your LVs up
250  
        if(numLVs == 0) {
251  
            return false;
252  
        }
253  
        if(IOUtils.toInt( lvs[numLVs-1] ) == 255) {
254  
            return true;
255  
        }
256  
        return false;
257  
    }
258  
    /**
259  
     * Is this carrying on the packets from
260  
     *  a previous page?
261  
     */
262  
    public boolean isContinuation() {
263  
        return isContinue;
264  
    }
265  
    protected void setIsContinuation() {
266  
        isContinue = true;
267  
    }
268  
269  
    /**
270  
     * This should only ever be called by
271  
     *  {@link OggPacketWriter#close()} !
272  
     */
273  
    protected void setIsEOS() {
274  
        isEOS = true;
275  
    }
276  
277  
    /**
278  
     * For unit testing only!
279  
     */
280  
    protected int getNumLVs() {
281  
        return numLVs;
282  
    }
283  
284  
285  
    public void writeHeader(OutputStream out) throws IOException {
286  
        byte[] header = getHeader();
287  
288  
        // Ensure we've moved from tmpdata to data
289  
        getData();
290  
291  
        // Generate the checksum and store
292  
        int crc = CRCUtils.getCRC(header);
293  
        if(data != null && data.length > 0) {
294  
            crc = CRCUtils.getCRC(data, crc);
295  
        }
296  
        IOUtils.putInt4(header, 22, crc);
297  
        checksum = crc;
298  
299  
        // Write out
300  
        out.write(header);
301  
    }
302  
    /**
303  
     * Gets the header, but with a blank CRC field
304  
     */
305  
    protected byte[] getHeader() {
306  
        byte[] header = new byte[MINIMUM_PAGE_SIZE + numLVs];
307  
        header[0] = (byte)'O';
308  
        header[1] = (byte)'g';
309  
        header[2] = (byte)'g';
310  
        header[3] = (byte)'S';
311  
312  
        header[4] = 0; // Version
313  
314  
        byte flags = 0;
315  
        if(isContinue) {
316  
            flags += 1;
317  
        }
318  
        if(isBOS) {
319  
            flags += 2;
320  
        }
321  
        if(isEOS) {
322  
            flags += 4;
323  
        }
324  
        header[5] = flags;
325  
326  
        IOUtils.putInt8(header, 6, granulePosition);
327  
        IOUtils.putInt4(header, 14, sid);
328  
        IOUtils.putInt4(header, 18, seqNum);
329  
330  
        // Checksum @ 22 left blank for now
331  
332  
        header[26] = IOUtils.fromInt(numLVs);
333  
        System.arraycopy(lvs, 0, header, MINIMUM_PAGE_SIZE, numLVs);
334  
335  
        return header;
336  
    }
337  
338  
339  
    public String toString() {
340  
        return "Ogg Page - " + getSid() + " @ " + getSequenceNumber() +
341  
                " - " + numLVs + " LVs";
342  
    }
343  
344  
345  
    public OggPacketIterator getPacketIterator() {
346  
        return new OggPacketIterator(null);
347  
    }
348  
    public OggPacketIterator getPacketIterator(OggPacketData previousPart) {
349  
        return new OggPacketIterator(previousPart);
350  
    }
351  
    /**
352  
     * Returns a full {@link OggPacket} if it can, otherwise
353  
     *  just the {@link OggPacketData} if the rest of the
354  
     *  packet is in another {@link OggPage}
355  
     */
356  
    protected class OggPacketIterator implements Iterator<OggPacketData> {
357  
        private OggPacketData prevPart;
358  
        private int currentLV = 0;
359  
        private int currentOffset = 0;
360  
361  
        private OggPacketIterator(OggPacketData previousPart) {
362  
            this.prevPart = previousPart;
363  
            
364  
            ifdef OggStreamPage_debug
365  
              printVars("OggPacketIterator", lvsRemaining := numLVs-currentLV, +prevPart);
366  
            endifdef
367  
        }
368  
369  
        public boolean hasNext() {
370  
            if(currentLV < numLVs) {
371  
                return true;
372  
            }
373  
            // Special case for an empty page
374  
            if(currentLV == 0 && numLVs == 0) {
375  
                return true;
376  
            }
377  
378  
            return false;
379  
        }
380  
381  
        public OggPacketData next() {
382  
            boolean continues = false;
383  
            int packetLVs = 0;
384  
            int packetSize = 0;
385  
386  
            // How much data to we have?
387  
            for(int i=currentLV; i< numLVs; i++) {
388  
                int size = IOUtils.toInt( lvs[i] );
389  
                packetSize += size;
390  
                packetLVs++;
391  
392  
                if(size < 255) {
393  
                    break;
394  
                }
395  
                if(i == (numLVs-1) && size == 255) {
396  
                    continues = true;
397  
                }
398  
            }
399  
400  
            // Get the data
401  
            byte[] pd = new byte[packetSize];
402  
            for(int i=currentLV; i<(currentLV + packetLVs); i++) {
403  
                int size = IOUtils.toInt( lvs[i] );
404  
                int offset = (i-currentLV)*255;
405  
                System.arraycopy(data, currentOffset+offset, pd, offset, size);
406  
            }
407  
            // Tack on anything spare from last time too
408  
            if(prevPart != null) {
409  
                int prevSize = prevPart.getData().length;
410  
                byte[] fpd = new byte[prevSize+pd.length];
411  
                System.arraycopy(prevPart.getData(), 0, fpd, 0, prevSize);
412  
                System.arraycopy(pd, 0, fpd, prevSize, pd.length);
413  
414  
                prevPart = null;
415  
                pd = fpd;
416  
            }
417  
418  
            // Create
419  
            OggPacketData packet;
420  
            if(continues) {
421  
                packet = new OggPacketData(pd) {};
422  
            } else {
423  
                boolean packetBOS = false;
424  
                boolean packetEOS = false;
425  
                if(isBOS && currentLV == 0) {
426  
                    packetBOS = true;
427  
                }
428  
                if(isEOS && (currentLV+packetLVs) == numLVs) {
429  
                    packetEOS = true;
430  
                }
431  
432  
                packet = new OggStreamPacket(OggStreamPage.this, pd, packetBOS, packetEOS);
433  
            }
434  
435  
            // Wind on
436  
            currentLV += packetLVs;
437  
            currentOffset += packetSize;
438  
            // Empty page special case wind-on
439  
            if(currentLV == 0)
440  
                currentLV = 1;
441  
442  
            // Done!
443  
            return packet;
444  
        }
445  
446  
        public void remove() {
447  
            throw new IllegalStateException("Remove not supported");
448  
        }
449  
    }
450  
}

download  show line numbers  debug dex  old transpilations   

Travelled to 4 computer(s): bhatertpkbcr, ekrmjmnbrukm, mowyntqkapby, mqqgnosmbjvj

No comments. add comment

Snippet ID: #1032913
Snippet name: OggStreamPage
Eternal ID of this version: #1032913/11
Text MD5: 0085171b4cc2c98b4bacddfcd2badd03
Author: stefan
Category: javax / audio
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2021-10-10 21:51:13
Source code size: 13006 bytes / 450 lines
Pitched / IR pitched: No / No
Views / Downloads: 159 / 463
Version history: 10 change(s)
Referenced in: [show references]