Skip to content

Commit

Permalink
Clean up Vorbis header
Browse files Browse the repository at this point in the history
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
  • Loading branch information
ojw28 authored and kim-vde committed Feb 11, 2020
1 parent 4bb6036 commit b23940d
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer2.extractor;

import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.ParserException;
import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.ParsableByteArray;
Expand All @@ -37,46 +38,69 @@ public CommentHeader(String vendor, String[] comments, int length) {
}
}

/** 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 final long version;
/** The {@code vorbis_version} field. */
public final int version;
/** The {@code audio_channels} field. */
public final int channels;
public final long sampleRate;
public final int bitrateMax;
/** The {@code audio_sample_rate} field. */
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 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;
/** The {@code blocksize_1} field. */
public final int blockSize1;
/** The {@code framing_flag} field. */
public final boolean framingFlag;
/** The raw header 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(
long version,
int version,
int channels,
long sampleRate,
int bitrateMax,
int sampleRate,
int bitrateMaximum,
int bitrateNominal,
int bitrateMin,
int bitrateMinimum,
int blockSize0,
int blockSize1,
boolean framingFlag,
byte[] data) {
this.version = version;
this.channels = channels;
this.sampleRate = sampleRate;
this.bitrateMax = bitrateMax;
this.bitrateMaximum = bitrateMaximum;
this.bitrateNominal = bitrateNominal;
this.bitrateMin = bitrateMin;
this.bitrateMinimum = bitrateMinimum;
this.blockSize0 = blockSize0;
this.blockSize1 = blockSize1;
this.framingFlag = framingFlag;
this.data = data;
}

public int getApproximateBitrate() {
return bitrateNominal == 0 ? (bitrateMin + bitrateMax) / 2 : bitrateNominal;
}
}

/** Vorbis setup header modes. */
Expand Down Expand Up @@ -128,13 +152,21 @@ public static VorbisIdHeader readVorbisIdentificationHeader(ParsableByteArray he

verifyVorbisHeaderCapturePattern(0x01, headerData, false);

long version = headerData.readLittleEndianUnsignedInt();
int version = headerData.readLittleEndianUnsignedIntToInt();
int channels = headerData.readUnsignedByte();
long sampleRate = headerData.readLittleEndianUnsignedInt();
int bitrateMax = headerData.readLittleEndianInt();
int sampleRate = headerData.readLittleEndianUnsignedIntToInt();
int bitrateMaximum = headerData.readLittleEndianInt();
if (bitrateMaximum <= 0) {
bitrateMaximum = Format.NO_VALUE;
}
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 blockSize0 = (int) Math.pow(2, blockSize & 0x0F);
int blockSize1 = (int) Math.pow(2, (blockSize & 0xF0) >> 4);
Expand All @@ -143,8 +175,17 @@ public static VorbisIdHeader readVorbisIdentificationHeader(ParsableByteArray he
// raw data of Vorbis setup header has to be passed to decoder as CSD buffer #1
byte[] data = Arrays.copyOf(headerData.data, headerData.limit());

return new VorbisIdHeader(version, channels, sampleRate, bitrateMax, bitrateNominal, bitrateMin,
blockSize0, blockSize1, framingFlag, data);
return new VorbisIdHeader(
version,
channels,
sampleRate,
bitrateMaximum,
bitrateNominal,
bitrateMinimum,
blockSize0,
blockSize1,
framingFlag,
data);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,9 @@ protected boolean readHeaders(ParsableByteArray packet, long position, SetupData
null,
MimeTypes.AUDIO_VORBIS,
/* codecs= */ null,
this.vorbisSetup.idHeader.bitrateNominal,
vorbisSetup.idHeader.bitrateNominal,
Format.NO_VALUE,
this.vorbisSetup.idHeader.channels,
vorbisSetup.idHeader.channels,
(int) this.vorbisSetup.idHeader.sampleRate,
codecInitialisationData,
null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,9 @@ public void testReadIdHeader() throws Exception {
assertThat(vorbisIdHeader.channels).isEqualTo(2);
assertThat(vorbisIdHeader.blockSize0).isEqualTo(512);
assertThat(vorbisIdHeader.blockSize1).isEqualTo(1024);
assertThat(vorbisIdHeader.bitrateMax).isEqualTo(-1);
assertThat(vorbisIdHeader.bitrateMin).isEqualTo(-1);
assertThat(vorbisIdHeader.bitrateMaximum).isEqualTo(-1);
assertThat(vorbisIdHeader.bitrateMinimum).isEqualTo(-1);
assertThat(vorbisIdHeader.bitrateNominal).isEqualTo(66666);
assertThat(vorbisIdHeader.getApproximateBitrate()).isEqualTo(66666);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ public void testReadSetupHeadersWithIOExceptions() throws IOException, Interrupt
assertThat(vorbisSetup.idHeader.data).hasLength(30);
assertThat(vorbisSetup.setupHeaderData).hasLength(3597);

assertThat(vorbisSetup.idHeader.bitrateMax).isEqualTo(-1);
assertThat(vorbisSetup.idHeader.bitrateMin).isEqualTo(-1);
assertThat(vorbisSetup.idHeader.bitrateMaximum).isEqualTo(-1);
assertThat(vorbisSetup.idHeader.bitrateMinimum).isEqualTo(-1);
assertThat(vorbisSetup.idHeader.bitrateNominal).isEqualTo(66666);
assertThat(vorbisSetup.idHeader.blockSize0).isEqualTo(512);
assertThat(vorbisSetup.idHeader.blockSize1).isEqualTo(1024);
Expand Down

0 comments on commit b23940d

Please sign in to comment.