mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
ogg't'opus reader
Support for opus content in ogg container. TODO: Sample duration and seeking. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=121940392
This commit is contained in:
parent
30ab3bef9a
commit
3674f9598e
11 changed files with 277 additions and 31 deletions
|
|
@ -76,8 +76,7 @@ public class SampleChooserActivity extends Activity {
|
||||||
group.addAll(Samples.MISC);
|
group.addAll(Samples.MISC);
|
||||||
sampleGroups.add(group);
|
sampleGroups.add(group);
|
||||||
group = new SampleGroup("Extensions");
|
group = new SampleGroup("Extensions");
|
||||||
group.addAll(Samples.VP9_EXTENSION_SAMPLES);
|
group.addAll(Samples.EXTENSION);
|
||||||
group.addAll(Samples.VP9_OPUS_EXTENSION_SAMPLES);
|
|
||||||
sampleGroups.add(group);
|
sampleGroups.add(group);
|
||||||
|
|
||||||
ExpandableListView sampleList = (ExpandableListView) findViewById(R.id.sample_list);
|
ExpandableListView sampleList = (ExpandableListView) findViewById(R.id.sample_list);
|
||||||
|
|
|
||||||
|
|
@ -262,16 +262,13 @@ import java.util.Locale;
|
||||||
"http://vod.leasewebcdn.com/bbb.flv?ri=1024&rs=150&start=0", Util.TYPE_OTHER),
|
"http://vod.leasewebcdn.com/bbb.flv?ri=1024&rs=150&start=0", Util.TYPE_OTHER),
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final Sample[] VP9_EXTENSION_SAMPLES = new Sample[] {
|
public static final Sample[] EXTENSION = new Sample[] {
|
||||||
new Sample("Google Glass DASH - VP9 Only",
|
new Sample("Google Glass DASH - VP9 Only",
|
||||||
"http://demos.webmproject.org/dash/201410/vp9_glass/manifest_vp9.mpd",
|
"http://demos.webmproject.org/dash/201410/vp9_glass/manifest_vp9.mpd",
|
||||||
Util.TYPE_DASH, true),
|
Util.TYPE_DASH, true),
|
||||||
new Sample("Google Glass DASH - VP9 and Vorbis",
|
new Sample("Google Glass DASH - VP9 and Vorbis",
|
||||||
"http://demos.webmproject.org/dash/201410/vp9_glass/manifest_vp9_vorbis.mpd",
|
"http://demos.webmproject.org/dash/201410/vp9_glass/manifest_vp9_vorbis.mpd",
|
||||||
Util.TYPE_DASH, true),
|
Util.TYPE_DASH, true),
|
||||||
};
|
|
||||||
|
|
||||||
public static final Sample[] VP9_OPUS_EXTENSION_SAMPLES = new Sample[] {
|
|
||||||
new Sample("Google Glass DASH - VP9 and Opus",
|
new Sample("Google Glass DASH - VP9 and Opus",
|
||||||
"http://demos.webmproject.org/dash/201410/vp9_glass/manifest_vp9_opus.mpd",
|
"http://demos.webmproject.org/dash/201410/vp9_glass/manifest_vp9_opus.mpd",
|
||||||
Util.TYPE_DASH, true),
|
Util.TYPE_DASH, true),
|
||||||
|
|
|
||||||
BIN
library/src/androidTest/assets/ogg/bear.opus
Normal file
BIN
library/src/androidTest/assets/ogg/bear.opus
Normal file
Binary file not shown.
|
|
@ -38,17 +38,17 @@ public final class OggExtractorTest extends TestCase {
|
||||||
|
|
||||||
public void testSniffVorbis() throws Exception {
|
public void testSniffVorbis() throws Exception {
|
||||||
byte[] data = TestUtil.joinByteArrays(
|
byte[] data = TestUtil.joinByteArrays(
|
||||||
TestData.buildOggHeader(0x02, 0, 1000, 0x02),
|
TestData.buildOggHeader(0x02, 0, 1000, 1),
|
||||||
TestUtil.createByteArray(120, 120), // Laces
|
TestUtil.createByteArray(7), // Laces
|
||||||
new byte[]{0x01, 'v', 'o', 'r', 'b', 'i', 's'});
|
new byte[]{0x01, 'v', 'o', 'r', 'b', 'i', 's'});
|
||||||
assertTrue(sniff(createInput(data)));
|
assertTrue(sniff(createInput(data)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testSniffFlac() throws Exception {
|
public void testSniffFlac() throws Exception {
|
||||||
byte[] data = TestUtil.joinByteArrays(
|
byte[] data = TestUtil.joinByteArrays(
|
||||||
TestData.buildOggHeader(0x02, 0, 1000, 0x02),
|
TestData.buildOggHeader(0x02, 0, 1000, 1),
|
||||||
TestUtil.createByteArray(120, 120), // Laces
|
TestUtil.createByteArray(5), // Laces
|
||||||
new byte[]{0x7F, 'F', 'L', 'A', 'C', ' ', ' '});
|
new byte[]{0x7F, 'F', 'L', 'A', 'C'});
|
||||||
assertTrue(sniff(createInput(data)));
|
assertTrue(sniff(createInput(data)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -66,8 +66,8 @@ public final class OggExtractorTest extends TestCase {
|
||||||
|
|
||||||
public void testSniffInvalidHeader() throws Exception {
|
public void testSniffInvalidHeader() throws Exception {
|
||||||
byte[] data = TestUtil.joinByteArrays(
|
byte[] data = TestUtil.joinByteArrays(
|
||||||
TestData.buildOggHeader(0x02, 0, 1000, 0x02),
|
TestData.buildOggHeader(0x02, 0, 1000, 1),
|
||||||
TestUtil.createByteArray(120, 120), // Laces
|
TestUtil.createByteArray(7), // Laces
|
||||||
new byte[]{0x7F, 'X', 'o', 'r', 'b', 'i', 's'});
|
new byte[]{0x7F, 'X', 'o', 'r', 'b', 'i', 's'});
|
||||||
assertFalse(sniff(createInput(data)));
|
assertFalse(sniff(createInput(data)));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.google.android.exoplayer.extractor.ogg;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer.C;
|
||||||
|
import com.google.android.exoplayer.Format;
|
||||||
|
import com.google.android.exoplayer.extractor.DefaultExtractorInput;
|
||||||
|
import com.google.android.exoplayer.extractor.Extractor;
|
||||||
|
import com.google.android.exoplayer.extractor.PositionHolder;
|
||||||
|
import com.google.android.exoplayer.testutil.FakeExtractorOutput;
|
||||||
|
import com.google.android.exoplayer.testutil.FakeTrackOutput;
|
||||||
|
import com.google.android.exoplayer.upstream.DataSource;
|
||||||
|
import com.google.android.exoplayer.upstream.DataSpec;
|
||||||
|
import com.google.android.exoplayer.upstream.DefaultDataSource;
|
||||||
|
import com.google.android.exoplayer.util.MimeTypes;
|
||||||
|
import com.google.android.exoplayer.util.Util;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.test.InstrumentationTestCase;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit test for {@link OpusReader}.
|
||||||
|
*/
|
||||||
|
public final class OpusReaderTest extends InstrumentationTestCase {
|
||||||
|
|
||||||
|
private static final String TEST_FILE = "asset:///ogg/bear.opus";
|
||||||
|
|
||||||
|
private OggExtractor extractor;
|
||||||
|
private OpusReader opusReader;
|
||||||
|
private FakeExtractorOutput extractorOutput;
|
||||||
|
private DefaultExtractorInput extractorInput;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
|
||||||
|
Context context = getInstrumentation().getContext();
|
||||||
|
DataSource dataSource = new DefaultDataSource(context, null, Util
|
||||||
|
.getUserAgent(context, "ExoPlayerExtFlacTest"), false);
|
||||||
|
Uri uri = Uri.parse(TEST_FILE);
|
||||||
|
long length = dataSource.open(new DataSpec(uri, 0, C.LENGTH_UNBOUNDED, null));
|
||||||
|
extractorInput = new DefaultExtractorInput(dataSource, 0, length);
|
||||||
|
|
||||||
|
extractor = new OggExtractor();
|
||||||
|
assertTrue(extractor.sniff(extractorInput));
|
||||||
|
extractorInput.resetPeekPosition();
|
||||||
|
|
||||||
|
opusReader = (OpusReader) extractor.getStreamReader();
|
||||||
|
|
||||||
|
extractorOutput = new FakeExtractorOutput();
|
||||||
|
extractor.init(extractorOutput);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSniffOpus() throws Exception {
|
||||||
|
// Do nothing. All assertions are in setUp()
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testParseHeader() throws Exception {
|
||||||
|
FakeTrackOutput trackOutput = parseFile(false);
|
||||||
|
|
||||||
|
trackOutput.assertSampleCount(0);
|
||||||
|
|
||||||
|
Format format = trackOutput.format;
|
||||||
|
assertNotNull(format);
|
||||||
|
assertEquals(MimeTypes.AUDIO_OPUS, format.sampleMimeType);
|
||||||
|
assertEquals(48000, format.sampleRate);
|
||||||
|
assertEquals(2, format.channelCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testParseWholeFile() throws Exception {
|
||||||
|
FakeTrackOutput trackOutput = parseFile(true);
|
||||||
|
|
||||||
|
trackOutput.assertSampleCount(275);
|
||||||
|
}
|
||||||
|
|
||||||
|
private FakeTrackOutput parseFile(boolean parseAll) throws IOException, InterruptedException {
|
||||||
|
PositionHolder seekPositionHolder = new PositionHolder();
|
||||||
|
int readResult = Extractor.RESULT_CONTINUE;
|
||||||
|
do {
|
||||||
|
readResult = extractor.read(extractorInput, seekPositionHolder);
|
||||||
|
if (readResult == Extractor.RESULT_SEEK) {
|
||||||
|
fail("There should be no seek");
|
||||||
|
}
|
||||||
|
} while (readResult != Extractor.RESULT_END_OF_INPUT && parseAll);
|
||||||
|
|
||||||
|
assertEquals(1, extractorOutput.trackOutputs.size());
|
||||||
|
FakeTrackOutput trackOutput = extractorOutput.trackOutputs.get(0);
|
||||||
|
assertNotNull(trackOutput);
|
||||||
|
return trackOutput;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -46,8 +46,8 @@ import java.util.List;
|
||||||
|
|
||||||
private boolean firstAudioPacketProcessed;
|
private boolean firstAudioPacketProcessed;
|
||||||
|
|
||||||
/* package */ static boolean verifyBitstreamType(ParsableByteArray data) {
|
public static boolean verifyBitstreamType(ParsableByteArray data) {
|
||||||
return data.readUnsignedByte() == 0x7F && // packet type
|
return data.bytesLeft() >= 5 && data.readUnsignedByte() == 0x7F && // packet type
|
||||||
data.readUnsignedInt() == 0x464C4143; // ASCII signature "FLAC"
|
data.readUnsignedInt() == 0x464C4143; // ASCII signature "FLAC"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,20 +38,19 @@ public class OggExtractor implements Extractor {
|
||||||
ParsableByteArray scratch = new ParsableByteArray(new byte[OggUtil.PAGE_HEADER_SIZE], 0);
|
ParsableByteArray scratch = new ParsableByteArray(new byte[OggUtil.PAGE_HEADER_SIZE], 0);
|
||||||
OggUtil.PageHeader header = new OggUtil.PageHeader();
|
OggUtil.PageHeader header = new OggUtil.PageHeader();
|
||||||
if (!OggUtil.populatePageHeader(input, header, scratch, true)
|
if (!OggUtil.populatePageHeader(input, header, scratch, true)
|
||||||
|| (header.type & 0x02) != 0x02 || header.bodySize < 7) {
|
|| (header.type & 0x02) != 0x02) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
scratch.reset();
|
input.peekFully(scratch.data, 0, header.bodySize);
|
||||||
input.peekFully(scratch.data, 0, 7);
|
scratch.setLimit(header.bodySize);
|
||||||
if (FlacReader.verifyBitstreamType(scratch)) {
|
if (FlacReader.verifyBitstreamType(resetPosition(scratch))) {
|
||||||
streamReader = new FlacReader();
|
streamReader = new FlacReader();
|
||||||
|
} else if (VorbisReader.verifyBitstreamType(resetPosition(scratch))) {
|
||||||
|
streamReader = new VorbisReader();
|
||||||
|
} else if (OpusReader.verifyBitstreamType(resetPosition(scratch))) {
|
||||||
|
streamReader = new OpusReader();
|
||||||
} else {
|
} else {
|
||||||
scratch.reset();
|
return false;
|
||||||
if (VorbisReader.verifyBitstreamType(scratch)) {
|
|
||||||
streamReader = new VorbisReader();
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} catch (ParserException e) {
|
} catch (ParserException e) {
|
||||||
|
|
@ -83,4 +82,15 @@ public class OggExtractor implements Extractor {
|
||||||
throws IOException, InterruptedException {
|
throws IOException, InterruptedException {
|
||||||
return streamReader.read(input, seekPosition);
|
return streamReader.read(input, seekPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//@VisibleForTesting
|
||||||
|
/* package */ StreamReader getStreamReader() {
|
||||||
|
return streamReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ParsableByteArray resetPosition(ParsableByteArray scratch) {
|
||||||
|
scratch.setPosition(0);
|
||||||
|
return scratch;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ import java.io.IOException;
|
||||||
* as argument.
|
* as argument.
|
||||||
*
|
*
|
||||||
* @param input the {@link ExtractorInput} to read from.
|
* @param input the {@link ExtractorInput} to read from.
|
||||||
* @param header the {@link PageHeader} to read from.
|
* @param header the {@link PageHeader} to be populated.
|
||||||
* @param scratch a scratch array temporary use. Its size should be at least PAGE_HEADER_SIZE
|
* @param scratch a scratch array temporary use. Its size should be at least PAGE_HEADER_SIZE
|
||||||
* @param quite if {@code true} no Exceptions are thrown but {@code false} is return if something
|
* @param quite if {@code true} no Exceptions are thrown but {@code false} is return if something
|
||||||
* goes wrong.
|
* goes wrong.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.google.android.exoplayer.extractor.ogg;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer.C;
|
||||||
|
import com.google.android.exoplayer.Format;
|
||||||
|
import com.google.android.exoplayer.extractor.Extractor;
|
||||||
|
import com.google.android.exoplayer.extractor.ExtractorInput;
|
||||||
|
import com.google.android.exoplayer.extractor.PositionHolder;
|
||||||
|
import com.google.android.exoplayer.extractor.SeekMap;
|
||||||
|
import com.google.android.exoplayer.util.MimeTypes;
|
||||||
|
import com.google.android.exoplayer.util.ParsableByteArray;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link StreamReader} to extract Opus data out of Ogg byte stream.
|
||||||
|
*/
|
||||||
|
/* package */ final class OpusReader extends StreamReader {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opus streams are always decoded at 48000 Hz.
|
||||||
|
*/
|
||||||
|
private static final int SAMPLE_RATE = 48000;
|
||||||
|
|
||||||
|
private static final byte[] OPUS_SIGNATURE = {'O', 'p', 'u', 's', 'H', 'e', 'a', 'd'};
|
||||||
|
|
||||||
|
private static final int STATE_READ_HEADER = 0;
|
||||||
|
private static final int STATE_READ_TAGS = 1;
|
||||||
|
private static final int STATE_READ_AUDIO = 2;
|
||||||
|
|
||||||
|
private int state = STATE_READ_HEADER;
|
||||||
|
private long timeUs;
|
||||||
|
|
||||||
|
public static boolean verifyBitstreamType(ParsableByteArray data) {
|
||||||
|
if (data.bytesLeft() < OPUS_SIGNATURE.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
byte[] header = new byte[OPUS_SIGNATURE.length];
|
||||||
|
data.readBytes(header, 0, OPUS_SIGNATURE.length);
|
||||||
|
return Arrays.equals(header, OPUS_SIGNATURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read(ExtractorInput input, PositionHolder seekPosition)
|
||||||
|
throws IOException, InterruptedException {
|
||||||
|
if (!oggParser.readPacket(input, scratch)) {
|
||||||
|
return Extractor.RESULT_END_OF_INPUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] data = scratch.data;
|
||||||
|
int dataSize = scratch.limit();
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case STATE_READ_HEADER: {
|
||||||
|
byte[] metadata = Arrays.copyOfRange(data, 0, dataSize);
|
||||||
|
int channelCount = metadata[9] & 0xFF;
|
||||||
|
List<byte[]> initializationData = Collections.singletonList(metadata);
|
||||||
|
trackOutput.format(Format.createAudioSampleFormat(null, MimeTypes.AUDIO_OPUS,
|
||||||
|
Format.NO_VALUE, Format.NO_VALUE, channelCount, SAMPLE_RATE,
|
||||||
|
initializationData, null, null));
|
||||||
|
state = STATE_READ_TAGS;
|
||||||
|
} break;
|
||||||
|
case STATE_READ_TAGS:
|
||||||
|
// skip this packet
|
||||||
|
state = STATE_READ_AUDIO;
|
||||||
|
extractorOutput.seekMap(new SeekMap.Unseekable(C.UNSET_TIME_US));
|
||||||
|
break;
|
||||||
|
case STATE_READ_AUDIO:
|
||||||
|
trackOutput.sampleData(scratch, dataSize);
|
||||||
|
trackOutput.sampleMetadata(timeUs, C.BUFFER_FLAG_KEY_FRAME, dataSize, 0, null);
|
||||||
|
timeUs += getPacketDuration(data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
scratch.reset();
|
||||||
|
return Extractor.RESULT_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private long getPacketDuration(byte[] packet) {
|
||||||
|
int toc = packet[0] & 0xFF;
|
||||||
|
int frames;
|
||||||
|
switch (toc & 0x3) {
|
||||||
|
case 0:
|
||||||
|
frames = 1;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
frames = 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
frames = packet[1] & 0x3F;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int config = toc >> 3;
|
||||||
|
int length = config & 0x3;
|
||||||
|
if (config >= 16) {
|
||||||
|
length = 2500 << length;
|
||||||
|
} else if (config >= 12) {
|
||||||
|
length = 10000 << (length & 0x1);
|
||||||
|
} else if (length == 3) {
|
||||||
|
length = 60000;
|
||||||
|
} else {
|
||||||
|
length = 10000 << length;
|
||||||
|
}
|
||||||
|
return frames * length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -51,7 +51,7 @@ import java.util.ArrayList;
|
||||||
private long totalSamples;
|
private long totalSamples;
|
||||||
private long durationUs;
|
private long durationUs;
|
||||||
|
|
||||||
/* package */ static boolean verifyBitstreamType(ParsableByteArray data) {
|
public static boolean verifyBitstreamType(ParsableByteArray data) {
|
||||||
try {
|
try {
|
||||||
return VorbisUtil.verifyVorbisHeaderCapturePattern(0x01, data, true);
|
return VorbisUtil.verifyVorbisHeaderCapturePattern(0x01, data, true);
|
||||||
} catch (ParserException e) {
|
} catch (ParserException e) {
|
||||||
|
|
|
||||||
|
|
@ -121,15 +121,23 @@ import java.util.Arrays;
|
||||||
*
|
*
|
||||||
* @param headerType the type of the header expected.
|
* @param headerType the type of the header expected.
|
||||||
* @param header the alleged header bytes.
|
* @param header the alleged header bytes.
|
||||||
* @param quite if {@code true} no exceptions are thrown. Instead {@code false} is returned.
|
* @param quiet if {@code true} no exceptions are thrown. Instead {@code false} is returned.
|
||||||
* @return the number of bytes read.
|
* @return the number of bytes read.
|
||||||
* @throws ParserException thrown if header type or capture pattern is not as expected.
|
* @throws ParserException thrown if header type or capture pattern is not as expected.
|
||||||
*/
|
*/
|
||||||
public static boolean verifyVorbisHeaderCapturePattern(int headerType, ParsableByteArray header,
|
public static boolean verifyVorbisHeaderCapturePattern(int headerType, ParsableByteArray header,
|
||||||
boolean quite)
|
boolean quiet)
|
||||||
throws ParserException {
|
throws ParserException {
|
||||||
|
if (header.bytesLeft() < 7) {
|
||||||
|
if (quiet) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
throw new ParserException("too short header: " + header.bytesLeft());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (header.readUnsignedByte() != headerType) {
|
if (header.readUnsignedByte() != headerType) {
|
||||||
if (quite) {
|
if (quiet) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
throw new ParserException("expected header type " + Integer.toHexString(headerType));
|
throw new ParserException("expected header type " + Integer.toHexString(headerType));
|
||||||
|
|
@ -142,7 +150,7 @@ import java.util.Arrays;
|
||||||
&& header.readUnsignedByte() == 'b'
|
&& header.readUnsignedByte() == 'b'
|
||||||
&& header.readUnsignedByte() == 'i'
|
&& header.readUnsignedByte() == 'i'
|
||||||
&& header.readUnsignedByte() == 's')) {
|
&& header.readUnsignedByte() == 's')) {
|
||||||
if (quite) {
|
if (quiet) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
throw new ParserException("expected characters 'vorbis'");
|
throw new ParserException("expected characters 'vorbis'");
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue