Commit ea69a3db by andrewlewis Committed by Ian Baker

Move MpegAudioHeader to MpegUtil

This makes MPEG audio utilities similar to utilities we have for WAV,
AC-3 etc., and moves them out of the extractor package so that an
extractor module can be split out without needing to have a class in the
extractor package in the common library.

PiperOrigin-RevId: 290595089
parent 5e2b4117
...@@ -28,7 +28,6 @@ import com.google.android.exoplayer2.C; ...@@ -28,7 +28,6 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.audio.AudioProcessor.UnhandledAudioFormatException; import com.google.android.exoplayer2.audio.AudioProcessor.UnhandledAudioFormatException;
import com.google.android.exoplayer2.extractor.MpegAudioHeader;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Log; import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
...@@ -1159,7 +1158,7 @@ public final class DefaultAudioSink implements AudioSink { ...@@ -1159,7 +1158,7 @@ public final class DefaultAudioSink implements AudioSink {
private static int getFramesPerEncodedSample(@C.Encoding int encoding, ByteBuffer buffer) { private static int getFramesPerEncodedSample(@C.Encoding int encoding, ByteBuffer buffer) {
switch (encoding) { switch (encoding) {
case C.ENCODING_MP3: case C.ENCODING_MP3:
return MpegAudioHeader.getFrameSampleCount(buffer.get(buffer.position())); return MpegAudioUtil.parseMpegAudioFrameSampleCount(buffer.get(buffer.position()));
case C.ENCODING_DTS: case C.ENCODING_DTS:
case C.ENCODING_DTS_HD: case C.ENCODING_DTS_HD:
return DtsUtil.parseDtsAudioSampleCount(buffer); return DtsUtil.parseDtsAudioSampleCount(buffer);
......
...@@ -24,6 +24,7 @@ import com.google.android.exoplayer2.C; ...@@ -24,6 +24,7 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.ParserException; import com.google.android.exoplayer2.ParserException;
import com.google.android.exoplayer2.audio.Ac3Util; import com.google.android.exoplayer2.audio.Ac3Util;
import com.google.android.exoplayer2.audio.MpegAudioUtil;
import com.google.android.exoplayer2.drm.DrmInitData; import com.google.android.exoplayer2.drm.DrmInitData;
import com.google.android.exoplayer2.drm.DrmInitData.SchemeData; import com.google.android.exoplayer2.drm.DrmInitData.SchemeData;
import com.google.android.exoplayer2.extractor.ChunkIndex; import com.google.android.exoplayer2.extractor.ChunkIndex;
...@@ -31,7 +32,6 @@ import com.google.android.exoplayer2.extractor.Extractor; ...@@ -31,7 +32,6 @@ import com.google.android.exoplayer2.extractor.Extractor;
import com.google.android.exoplayer2.extractor.ExtractorInput; import com.google.android.exoplayer2.extractor.ExtractorInput;
import com.google.android.exoplayer2.extractor.ExtractorOutput; import com.google.android.exoplayer2.extractor.ExtractorOutput;
import com.google.android.exoplayer2.extractor.ExtractorsFactory; import com.google.android.exoplayer2.extractor.ExtractorsFactory;
import com.google.android.exoplayer2.extractor.MpegAudioHeader;
import com.google.android.exoplayer2.extractor.PositionHolder; import com.google.android.exoplayer2.extractor.PositionHolder;
import com.google.android.exoplayer2.extractor.SeekMap; import com.google.android.exoplayer2.extractor.SeekMap;
import com.google.android.exoplayer2.extractor.TrackOutput; import com.google.android.exoplayer2.extractor.TrackOutput;
...@@ -1989,11 +1989,11 @@ public class MatroskaExtractor implements Extractor { ...@@ -1989,11 +1989,11 @@ public class MatroskaExtractor implements Extractor {
break; break;
case CODEC_ID_MP2: case CODEC_ID_MP2:
mimeType = MimeTypes.AUDIO_MPEG_L2; mimeType = MimeTypes.AUDIO_MPEG_L2;
maxInputSize = MpegAudioHeader.MAX_FRAME_SIZE_BYTES; maxInputSize = MpegAudioUtil.MAX_FRAME_SIZE_BYTES;
break; break;
case CODEC_ID_MP3: case CODEC_ID_MP3:
mimeType = MimeTypes.AUDIO_MPEG; mimeType = MimeTypes.AUDIO_MPEG;
maxInputSize = MpegAudioHeader.MAX_FRAME_SIZE_BYTES; maxInputSize = MpegAudioUtil.MAX_FRAME_SIZE_BYTES;
break; break;
case CODEC_ID_AC3: case CODEC_ID_AC3:
mimeType = MimeTypes.AUDIO_AC3; mimeType = MimeTypes.AUDIO_AC3;
......
...@@ -16,8 +16,8 @@ ...@@ -16,8 +16,8 @@
package com.google.android.exoplayer2.extractor.mp3; package com.google.android.exoplayer2.extractor.mp3;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.audio.MpegAudioUtil;
import com.google.android.exoplayer2.extractor.ConstantBitrateSeekMap; import com.google.android.exoplayer2.extractor.ConstantBitrateSeekMap;
import com.google.android.exoplayer2.extractor.MpegAudioHeader;
/** /**
* MP3 seeker that doesn't rely on metadata and seeks assuming the source has a constant bitrate. * MP3 seeker that doesn't rely on metadata and seeks assuming the source has a constant bitrate.
...@@ -30,7 +30,7 @@ import com.google.android.exoplayer2.extractor.MpegAudioHeader; ...@@ -30,7 +30,7 @@ import com.google.android.exoplayer2.extractor.MpegAudioHeader;
* @param mpegAudioHeader The MPEG audio header associated with the first frame. * @param mpegAudioHeader The MPEG audio header associated with the first frame.
*/ */
public ConstantBitrateSeeker( public ConstantBitrateSeeker(
long inputLength, long firstFramePosition, MpegAudioHeader mpegAudioHeader) { long inputLength, long firstFramePosition, MpegAudioUtil.Header mpegAudioHeader) {
super(inputLength, firstFramePosition, mpegAudioHeader.bitrate, mpegAudioHeader.frameSize); super(inputLength, firstFramePosition, mpegAudioHeader.bitrate, mpegAudioHeader.frameSize);
} }
......
...@@ -20,13 +20,13 @@ import androidx.annotation.Nullable; ...@@ -20,13 +20,13 @@ import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.ParserException; import com.google.android.exoplayer2.ParserException;
import com.google.android.exoplayer2.audio.MpegAudioUtil;
import com.google.android.exoplayer2.extractor.Extractor; import com.google.android.exoplayer2.extractor.Extractor;
import com.google.android.exoplayer2.extractor.ExtractorInput; import com.google.android.exoplayer2.extractor.ExtractorInput;
import com.google.android.exoplayer2.extractor.ExtractorOutput; import com.google.android.exoplayer2.extractor.ExtractorOutput;
import com.google.android.exoplayer2.extractor.ExtractorsFactory; import com.google.android.exoplayer2.extractor.ExtractorsFactory;
import com.google.android.exoplayer2.extractor.GaplessInfoHolder; import com.google.android.exoplayer2.extractor.GaplessInfoHolder;
import com.google.android.exoplayer2.extractor.Id3Peeker; import com.google.android.exoplayer2.extractor.Id3Peeker;
import com.google.android.exoplayer2.extractor.MpegAudioHeader;
import com.google.android.exoplayer2.extractor.PositionHolder; import com.google.android.exoplayer2.extractor.PositionHolder;
import com.google.android.exoplayer2.extractor.TrackOutput; import com.google.android.exoplayer2.extractor.TrackOutput;
import com.google.android.exoplayer2.extractor.mp3.Seeker.UnseekableSeeker; import com.google.android.exoplayer2.extractor.mp3.Seeker.UnseekableSeeker;
...@@ -107,7 +107,7 @@ public final class Mp3Extractor implements Extractor { ...@@ -107,7 +107,7 @@ public final class Mp3Extractor implements Extractor {
@Flags private final int flags; @Flags private final int flags;
private final long forcedFirstSampleTimestampUs; private final long forcedFirstSampleTimestampUs;
private final ParsableByteArray scratch; private final ParsableByteArray scratch;
private final MpegAudioHeader synchronizedHeader; private final MpegAudioUtil.Header synchronizedHeader;
private final GaplessInfoHolder gaplessInfoHolder; private final GaplessInfoHolder gaplessInfoHolder;
private final Id3Peeker id3Peeker; private final Id3Peeker id3Peeker;
...@@ -145,7 +145,7 @@ public final class Mp3Extractor implements Extractor { ...@@ -145,7 +145,7 @@ public final class Mp3Extractor implements Extractor {
this.flags = flags; this.flags = flags;
this.forcedFirstSampleTimestampUs = forcedFirstSampleTimestampUs; this.forcedFirstSampleTimestampUs = forcedFirstSampleTimestampUs;
scratch = new ParsableByteArray(SCRATCH_LENGTH); scratch = new ParsableByteArray(SCRATCH_LENGTH);
synchronizedHeader = new MpegAudioHeader(); synchronizedHeader = new MpegAudioUtil.Header();
gaplessInfoHolder = new GaplessInfoHolder(); gaplessInfoHolder = new GaplessInfoHolder();
basisTimeUs = C.TIME_UNSET; basisTimeUs = C.TIME_UNSET;
id3Peeker = new Id3Peeker(); id3Peeker = new Id3Peeker();
...@@ -215,7 +215,7 @@ public final class Mp3Extractor implements Extractor { ...@@ -215,7 +215,7 @@ public final class Mp3Extractor implements Extractor {
synchronizedHeader.mimeType, synchronizedHeader.mimeType,
/* codecs= */ null, /* codecs= */ null,
/* bitrate= */ Format.NO_VALUE, /* bitrate= */ Format.NO_VALUE,
MpegAudioHeader.MAX_FRAME_SIZE_BYTES, MpegAudioUtil.MAX_FRAME_SIZE_BYTES,
synchronizedHeader.channels, synchronizedHeader.channels,
synchronizedHeader.sampleRate, synchronizedHeader.sampleRate,
/* pcmEncoding= */ Format.NO_VALUE, /* pcmEncoding= */ Format.NO_VALUE,
...@@ -258,13 +258,13 @@ public final class Mp3Extractor implements Extractor { ...@@ -258,13 +258,13 @@ public final class Mp3Extractor implements Extractor {
scratch.setPosition(0); scratch.setPosition(0);
int sampleHeaderData = scratch.readInt(); int sampleHeaderData = scratch.readInt();
if (!headersMatch(sampleHeaderData, synchronizedHeaderData) if (!headersMatch(sampleHeaderData, synchronizedHeaderData)
|| MpegAudioHeader.getFrameSize(sampleHeaderData) == C.LENGTH_UNSET) { || MpegAudioUtil.getFrameSize(sampleHeaderData) == C.LENGTH_UNSET) {
// We have lost synchronization, so attempt to resynchronize starting at the next byte. // We have lost synchronization, so attempt to resynchronize starting at the next byte.
extractorInput.skipFully(1); extractorInput.skipFully(1);
synchronizedHeaderData = 0; synchronizedHeaderData = 0;
return RESULT_CONTINUE; return RESULT_CONTINUE;
} }
MpegAudioHeader.populateHeader(sampleHeaderData, synchronizedHeader); synchronizedHeader.setForHeaderData(sampleHeaderData);
if (basisTimeUs == C.TIME_UNSET) { if (basisTimeUs == C.TIME_UNSET) {
basisTimeUs = seeker.getTimeUs(extractorInput.getPosition()); basisTimeUs = seeker.getTimeUs(extractorInput.getPosition());
if (forcedFirstSampleTimestampUs != C.TIME_UNSET) { if (forcedFirstSampleTimestampUs != C.TIME_UNSET) {
...@@ -325,8 +325,8 @@ public final class Mp3Extractor implements Extractor { ...@@ -325,8 +325,8 @@ public final class Mp3Extractor implements Extractor {
int headerData = scratch.readInt(); int headerData = scratch.readInt();
int frameSize; int frameSize;
if ((candidateSynchronizedHeaderData != 0 if ((candidateSynchronizedHeaderData != 0
&& !headersMatch(headerData, candidateSynchronizedHeaderData)) && !headersMatch(headerData, candidateSynchronizedHeaderData))
|| (frameSize = MpegAudioHeader.getFrameSize(headerData)) == C.LENGTH_UNSET) { || (frameSize = MpegAudioUtil.getFrameSize(headerData)) == C.LENGTH_UNSET) {
// The header doesn't match the candidate header or is invalid. Try the next byte offset. // The header doesn't match the candidate header or is invalid. Try the next byte offset.
if (searchedBytes++ == searchLimitBytes) { if (searchedBytes++ == searchLimitBytes) {
if (!sniffing) { if (!sniffing) {
...@@ -346,7 +346,7 @@ public final class Mp3Extractor implements Extractor { ...@@ -346,7 +346,7 @@ public final class Mp3Extractor implements Extractor {
// The header matches the candidate header and/or is valid. // The header matches the candidate header and/or is valid.
validFrameCount++; validFrameCount++;
if (validFrameCount == 1) { if (validFrameCount == 1) {
MpegAudioHeader.populateHeader(headerData, synchronizedHeader); synchronizedHeader.setForHeaderData(headerData);
candidateSynchronizedHeaderData = headerData; candidateSynchronizedHeaderData = headerData;
} else if (validFrameCount == 4) { } else if (validFrameCount == 4) {
break; break;
...@@ -439,7 +439,7 @@ public final class Mp3Extractor implements Extractor { ...@@ -439,7 +439,7 @@ public final class Mp3Extractor implements Extractor {
throws IOException, InterruptedException { throws IOException, InterruptedException {
input.peekFully(scratch.data, 0, 4); input.peekFully(scratch.data, 0, 4);
scratch.setPosition(0); scratch.setPosition(0);
MpegAudioHeader.populateHeader(scratch.readInt(), synchronizedHeader); synchronizedHeader.setForHeaderData(scratch.readInt());
return new ConstantBitrateSeeker(input.getLength(), input.getPosition(), synchronizedHeader); return new ConstantBitrateSeeker(input.getLength(), input.getPosition(), synchronizedHeader);
} }
......
...@@ -17,7 +17,7 @@ package com.google.android.exoplayer2.extractor.mp3; ...@@ -17,7 +17,7 @@ package com.google.android.exoplayer2.extractor.mp3;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.extractor.MpegAudioHeader; import com.google.android.exoplayer2.audio.MpegAudioUtil;
import com.google.android.exoplayer2.extractor.SeekPoint; import com.google.android.exoplayer2.extractor.SeekPoint;
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;
...@@ -43,7 +43,10 @@ import com.google.android.exoplayer2.util.Util; ...@@ -43,7 +43,10 @@ import com.google.android.exoplayer2.util.Util;
*/ */
@Nullable @Nullable
public static VbriSeeker create( public static VbriSeeker create(
long inputLength, long position, MpegAudioHeader mpegAudioHeader, ParsableByteArray frame) { long inputLength,
long position,
MpegAudioUtil.Header mpegAudioHeader,
ParsableByteArray frame) {
frame.skipBytes(10); frame.skipBytes(10);
int numFrames = frame.readInt(); int numFrames = frame.readInt();
if (numFrames <= 0) { if (numFrames <= 0) {
......
...@@ -17,7 +17,7 @@ package com.google.android.exoplayer2.extractor.mp3; ...@@ -17,7 +17,7 @@ package com.google.android.exoplayer2.extractor.mp3;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.extractor.MpegAudioHeader; import com.google.android.exoplayer2.audio.MpegAudioUtil;
import com.google.android.exoplayer2.extractor.SeekPoint; import com.google.android.exoplayer2.extractor.SeekPoint;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Log; import com.google.android.exoplayer2.util.Log;
...@@ -44,7 +44,10 @@ import com.google.android.exoplayer2.util.Util; ...@@ -44,7 +44,10 @@ import com.google.android.exoplayer2.util.Util;
*/ */
@Nullable @Nullable
public static XingSeeker create( public static XingSeeker create(
long inputLength, long position, MpegAudioHeader mpegAudioHeader, ParsableByteArray frame) { long inputLength,
long position,
MpegAudioUtil.Header mpegAudioHeader,
ParsableByteArray frame) {
int samplesPerFrame = mpegAudioHeader.samplesPerFrame; int samplesPerFrame = mpegAudioHeader.samplesPerFrame;
int sampleRate = mpegAudioHeader.sampleRate; int sampleRate = mpegAudioHeader.sampleRate;
......
...@@ -17,8 +17,8 @@ package com.google.android.exoplayer2.extractor.ts; ...@@ -17,8 +17,8 @@ package com.google.android.exoplayer2.extractor.ts;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.audio.MpegAudioUtil;
import com.google.android.exoplayer2.extractor.ExtractorOutput; import com.google.android.exoplayer2.extractor.ExtractorOutput;
import com.google.android.exoplayer2.extractor.MpegAudioHeader;
import com.google.android.exoplayer2.extractor.TrackOutput; import com.google.android.exoplayer2.extractor.TrackOutput;
import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
...@@ -39,7 +39,7 @@ public final class MpegAudioReader implements ElementaryStreamReader { ...@@ -39,7 +39,7 @@ public final class MpegAudioReader implements ElementaryStreamReader {
private static final int HEADER_SIZE = 4; private static final int HEADER_SIZE = 4;
private final ParsableByteArray headerScratch; private final ParsableByteArray headerScratch;
private final MpegAudioHeader header; private final MpegAudioUtil.Header header;
@Nullable private final String language; @Nullable private final String language;
private @MonotonicNonNull TrackOutput output; private @MonotonicNonNull TrackOutput output;
...@@ -68,7 +68,7 @@ public final class MpegAudioReader implements ElementaryStreamReader { ...@@ -68,7 +68,7 @@ public final class MpegAudioReader implements ElementaryStreamReader {
// The first byte of an MPEG Audio frame header is always 0xFF. // The first byte of an MPEG Audio frame header is always 0xFF.
headerScratch = new ParsableByteArray(4); headerScratch = new ParsableByteArray(4);
headerScratch.data[0] = (byte) 0xFF; headerScratch.data[0] = (byte) 0xFF;
header = new MpegAudioHeader(); header = new MpegAudioUtil.Header();
this.language = language; this.language = language;
} }
...@@ -176,7 +176,7 @@ public final class MpegAudioReader implements ElementaryStreamReader { ...@@ -176,7 +176,7 @@ public final class MpegAudioReader implements ElementaryStreamReader {
} }
headerScratch.setPosition(0); headerScratch.setPosition(0);
boolean parsedHeader = MpegAudioHeader.populateHeader(headerScratch.readInt(), header); boolean parsedHeader = header.setForHeaderData(headerScratch.readInt());
if (!parsedHeader) { if (!parsedHeader) {
// We thought we'd located a frame header, but we hadn't. // We thought we'd located a frame header, but we hadn't.
frameBytesRead = 0; frameBytesRead = 0;
...@@ -187,9 +187,19 @@ public final class MpegAudioReader implements ElementaryStreamReader { ...@@ -187,9 +187,19 @@ public final class MpegAudioReader implements ElementaryStreamReader {
frameSize = header.frameSize; frameSize = header.frameSize;
if (!hasOutputFormat) { if (!hasOutputFormat) {
frameDurationUs = (C.MICROS_PER_SECOND * header.samplesPerFrame) / header.sampleRate; frameDurationUs = (C.MICROS_PER_SECOND * header.samplesPerFrame) / header.sampleRate;
Format format = Format.createAudioSampleFormat(formatId, header.mimeType, null, Format format =
Format.NO_VALUE, MpegAudioHeader.MAX_FRAME_SIZE_BYTES, header.channels, header.sampleRate, Format.createAudioSampleFormat(
null, null, 0, language); formatId,
header.mimeType,
null,
Format.NO_VALUE,
MpegAudioUtil.MAX_FRAME_SIZE_BYTES,
header.channels,
header.sampleRate,
null,
null,
0,
language);
output.format(format); output.format(format);
hasOutputFormat = true; hasOutputFormat = true;
} }
......
...@@ -19,7 +19,7 @@ import static com.google.common.truth.Truth.assertThat; ...@@ -19,7 +19,7 @@ import static com.google.common.truth.Truth.assertThat;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.extractor.MpegAudioHeader; import com.google.android.exoplayer2.audio.MpegAudioUtil;
import com.google.android.exoplayer2.extractor.SeekMap.SeekPoints; import com.google.android.exoplayer2.extractor.SeekMap.SeekPoints;
import com.google.android.exoplayer2.extractor.SeekPoint; import com.google.android.exoplayer2.extractor.SeekPoint;
import com.google.android.exoplayer2.util.ParsableByteArray; import com.google.android.exoplayer2.util.ParsableByteArray;
...@@ -59,8 +59,8 @@ public final class XingSeekerTest { ...@@ -59,8 +59,8 @@ public final class XingSeekerTest {
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
MpegAudioHeader xingFrameHeader = new MpegAudioHeader(); MpegAudioUtil.Header xingFrameHeader = new MpegAudioUtil.Header();
MpegAudioHeader.populateHeader(XING_FRAME_HEADER_DATA, xingFrameHeader); xingFrameHeader.setForHeaderData(XING_FRAME_HEADER_DATA);
seeker = XingSeeker.create(C.LENGTH_UNSET, XING_FRAME_POSITION, xingFrameHeader, seeker = XingSeeker.create(C.LENGTH_UNSET, XING_FRAME_POSITION, xingFrameHeader,
new ParsableByteArray(XING_FRAME_PAYLOAD)); new ParsableByteArray(XING_FRAME_PAYLOAD));
seekerWithInputLength = XingSeeker.create(STREAM_LENGTH, seekerWithInputLength = XingSeeker.create(STREAM_LENGTH,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment