Clean up Vorbis header

The functional change is to set the bitrate fields to Format.NO_VALUE
in the case that they're non-positive in the header data. Else it's
very easy to to take the fields and copy them directly into Format as
incorrect values.

Issue #2863

PiperOrigin-RevId: 292920141
This commit is contained in:
olly 2020-02-03 16:02:10 +00:00 committed by kim-vde
parent 4bb6036cf6
commit b23940dc61
4 changed files with 69 additions and 29 deletions

View File

@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.extractor; package com.google.android.exoplayer2.extractor;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.ParserException; import com.google.android.exoplayer2.ParserException;
import com.google.android.exoplayer2.util.Log; import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.ParsableByteArray; import com.google.android.exoplayer2.util.ParsableByteArray;
@ -37,27 +38,54 @@ public final class VorbisUtil {
} }
} }
/** Vorbis identification header. */ /**
* Vorbis identification header.
*
* @see <a href="https://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-630004.2.2">Vorbis
* spec/Identification header</a>
*/
public static final class VorbisIdHeader { public static final class VorbisIdHeader {
public final long version; /** The {@code vorbis_version} field. */
public final int version;
/** The {@code audio_channels} field. */
public final int channels; public final int channels;
public final long sampleRate; /** The {@code audio_sample_rate} field. */
public final int bitrateMax; public final int sampleRate;
/** The {@code bitrate_maximum} field, or {@link Format#NO_VALUE} if not greater than zero. */
public final int bitrateMaximum;
/** The {@code bitrate_nominal} field, or {@link Format#NO_VALUE} if not greater than zero. */
public final int bitrateNominal; public final int bitrateNominal;
public final int bitrateMin; /** The {@code bitrate_minimum} field, or {@link Format#NO_VALUE} if not greater than zero. */
public final int bitrateMinimum;
/** The {@code blocksize_0} field. */
public final int blockSize0; public final int blockSize0;
/** The {@code blocksize_1} field. */
public final int blockSize1; public final int blockSize1;
/** The {@code framing_flag} field. */
public final boolean framingFlag; public final boolean framingFlag;
/** The raw header data. */
public final byte[] data; public final byte[] data;
/**
* @param version See {@link #version}.
* @param channels See {@link #channels}.
* @param sampleRate See {@link #sampleRate}.
* @param bitrateMaximum See {@link #bitrateMaximum}.
* @param bitrateNominal See {@link #bitrateNominal}.
* @param bitrateMinimum See {@link #bitrateMinimum}.
* @param blockSize0 See {@link #version}.
* @param blockSize1 See {@link #blockSize1}.
* @param framingFlag See {@link #framingFlag}.
* @param data See {@link #data}.
*/
public VorbisIdHeader( public VorbisIdHeader(
long version, int version,
int channels, int channels,
long sampleRate, int sampleRate,
int bitrateMax, int bitrateMaximum,
int bitrateNominal, int bitrateNominal,
int bitrateMin, int bitrateMinimum,
int blockSize0, int blockSize0,
int blockSize1, int blockSize1,
boolean framingFlag, boolean framingFlag,
@ -65,18 +93,14 @@ public final class VorbisUtil {
this.version = version; this.version = version;
this.channels = channels; this.channels = channels;
this.sampleRate = sampleRate; this.sampleRate = sampleRate;
this.bitrateMax = bitrateMax; this.bitrateMaximum = bitrateMaximum;
this.bitrateNominal = bitrateNominal; this.bitrateNominal = bitrateNominal;
this.bitrateMin = bitrateMin; this.bitrateMinimum = bitrateMinimum;
this.blockSize0 = blockSize0; this.blockSize0 = blockSize0;
this.blockSize1 = blockSize1; this.blockSize1 = blockSize1;
this.framingFlag = framingFlag; this.framingFlag = framingFlag;
this.data = data; this.data = data;
} }
public int getApproximateBitrate() {
return bitrateNominal == 0 ? (bitrateMin + bitrateMax) / 2 : bitrateNominal;
}
} }
/** Vorbis setup header modes. */ /** Vorbis setup header modes. */
@ -128,13 +152,21 @@ public final class VorbisUtil {
verifyVorbisHeaderCapturePattern(0x01, headerData, false); verifyVorbisHeaderCapturePattern(0x01, headerData, false);
long version = headerData.readLittleEndianUnsignedInt(); int version = headerData.readLittleEndianUnsignedIntToInt();
int channels = headerData.readUnsignedByte(); int channels = headerData.readUnsignedByte();
long sampleRate = headerData.readLittleEndianUnsignedInt(); int sampleRate = headerData.readLittleEndianUnsignedIntToInt();
int bitrateMax = headerData.readLittleEndianInt(); int bitrateMaximum = headerData.readLittleEndianInt();
if (bitrateMaximum <= 0) {
bitrateMaximum = Format.NO_VALUE;
}
int bitrateNominal = headerData.readLittleEndianInt(); int bitrateNominal = headerData.readLittleEndianInt();
int bitrateMin = headerData.readLittleEndianInt(); if (bitrateNominal <= 0) {
bitrateNominal = Format.NO_VALUE;
}
int bitrateMinimum = headerData.readLittleEndianInt();
if (bitrateMinimum <= 0) {
bitrateMinimum = Format.NO_VALUE;
}
int blockSize = headerData.readUnsignedByte(); int blockSize = headerData.readUnsignedByte();
int blockSize0 = (int) Math.pow(2, blockSize & 0x0F); int blockSize0 = (int) Math.pow(2, blockSize & 0x0F);
int blockSize1 = (int) Math.pow(2, (blockSize & 0xF0) >> 4); int blockSize1 = (int) Math.pow(2, (blockSize & 0xF0) >> 4);
@ -143,8 +175,17 @@ public final class VorbisUtil {
// raw data of Vorbis setup header has to be passed to decoder as CSD buffer #1 // raw data of Vorbis setup header has to be passed to decoder as CSD buffer #1
byte[] data = Arrays.copyOf(headerData.data, headerData.limit()); byte[] data = Arrays.copyOf(headerData.data, headerData.limit());
return new VorbisIdHeader(version, channels, sampleRate, bitrateMax, bitrateNominal, bitrateMin, return new VorbisIdHeader(
blockSize0, blockSize1, framingFlag, data); version,
channels,
sampleRate,
bitrateMaximum,
bitrateNominal,
bitrateMinimum,
blockSize0,
blockSize1,
framingFlag,
data);
} }
/** /**

View File

@ -108,9 +108,9 @@ import java.util.ArrayList;
null, null,
MimeTypes.AUDIO_VORBIS, MimeTypes.AUDIO_VORBIS,
/* codecs= */ null, /* codecs= */ null,
this.vorbisSetup.idHeader.bitrateNominal, vorbisSetup.idHeader.bitrateNominal,
Format.NO_VALUE, Format.NO_VALUE,
this.vorbisSetup.idHeader.channels, vorbisSetup.idHeader.channels,
(int) this.vorbisSetup.idHeader.sampleRate, (int) this.vorbisSetup.idHeader.sampleRate,
codecInitialisationData, codecInitialisationData,
null, null,

View File

@ -61,10 +61,9 @@ public final class VorbisUtilTest {
assertThat(vorbisIdHeader.channels).isEqualTo(2); assertThat(vorbisIdHeader.channels).isEqualTo(2);
assertThat(vorbisIdHeader.blockSize0).isEqualTo(512); assertThat(vorbisIdHeader.blockSize0).isEqualTo(512);
assertThat(vorbisIdHeader.blockSize1).isEqualTo(1024); assertThat(vorbisIdHeader.blockSize1).isEqualTo(1024);
assertThat(vorbisIdHeader.bitrateMax).isEqualTo(-1); assertThat(vorbisIdHeader.bitrateMaximum).isEqualTo(-1);
assertThat(vorbisIdHeader.bitrateMin).isEqualTo(-1); assertThat(vorbisIdHeader.bitrateMinimum).isEqualTo(-1);
assertThat(vorbisIdHeader.bitrateNominal).isEqualTo(66666); assertThat(vorbisIdHeader.bitrateNominal).isEqualTo(66666);
assertThat(vorbisIdHeader.getApproximateBitrate()).isEqualTo(66666);
} }
@Test @Test

View File

@ -77,8 +77,8 @@ public final class VorbisReaderTest {
assertThat(vorbisSetup.idHeader.data).hasLength(30); assertThat(vorbisSetup.idHeader.data).hasLength(30);
assertThat(vorbisSetup.setupHeaderData).hasLength(3597); assertThat(vorbisSetup.setupHeaderData).hasLength(3597);
assertThat(vorbisSetup.idHeader.bitrateMax).isEqualTo(-1); assertThat(vorbisSetup.idHeader.bitrateMaximum).isEqualTo(-1);
assertThat(vorbisSetup.idHeader.bitrateMin).isEqualTo(-1); assertThat(vorbisSetup.idHeader.bitrateMinimum).isEqualTo(-1);
assertThat(vorbisSetup.idHeader.bitrateNominal).isEqualTo(66666); assertThat(vorbisSetup.idHeader.bitrateNominal).isEqualTo(66666);
assertThat(vorbisSetup.idHeader.blockSize0).isEqualTo(512); assertThat(vorbisSetup.idHeader.blockSize0).isEqualTo(512);
assertThat(vorbisSetup.idHeader.blockSize1).isEqualTo(1024); assertThat(vorbisSetup.idHeader.blockSize1).isEqualTo(1024);