Clean up some extrator SeekMap implementations

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=177173618
This commit is contained in:
olly 2017-11-28 09:43:08 -08:00 committed by Oliver Woodman
parent baa80a1b68
commit ff49bc97c4
4 changed files with 69 additions and 81 deletions

View File

@ -32,7 +32,7 @@ import java.lang.annotation.RetentionPolicy;
/** /**
* Extracts data from the FLV container format. * Extracts data from the FLV container format.
*/ */
public final class FlvExtractor implements Extractor, SeekMap { public final class FlvExtractor implements Extractor {
/** /**
* Factory for {@link FlvExtractor} instances. * Factory for {@link FlvExtractor} instances.
@ -70,32 +70,28 @@ public final class FlvExtractor implements Extractor, SeekMap {
// FLV container identifier. // FLV container identifier.
private static final int FLV_TAG = Util.getIntegerCodeForString("FLV"); private static final int FLV_TAG = Util.getIntegerCodeForString("FLV");
// Temporary buffers.
private final ParsableByteArray scratch; private final ParsableByteArray scratch;
private final ParsableByteArray headerBuffer; private final ParsableByteArray headerBuffer;
private final ParsableByteArray tagHeaderBuffer; private final ParsableByteArray tagHeaderBuffer;
private final ParsableByteArray tagData; private final ParsableByteArray tagData;
private final ScriptTagPayloadReader metadataReader;
// Extractor outputs.
private ExtractorOutput extractorOutput; private ExtractorOutput extractorOutput;
// State variables.
private @States int state; private @States int state;
private int bytesToNextTagHeader; private int bytesToNextTagHeader;
private int tagType; private int tagType;
private int tagDataSize; private int tagDataSize;
private long tagTimestampUs; private long tagTimestampUs;
private boolean outputSeekMap;
// Tags readers.
private AudioTagPayloadReader audioReader; private AudioTagPayloadReader audioReader;
private VideoTagPayloadReader videoReader; private VideoTagPayloadReader videoReader;
private ScriptTagPayloadReader metadataReader;
public FlvExtractor() { public FlvExtractor() {
scratch = new ParsableByteArray(4); scratch = new ParsableByteArray(4);
headerBuffer = new ParsableByteArray(FLV_HEADER_SIZE); headerBuffer = new ParsableByteArray(FLV_HEADER_SIZE);
tagHeaderBuffer = new ParsableByteArray(FLV_TAG_HEADER_SIZE); tagHeaderBuffer = new ParsableByteArray(FLV_TAG_HEADER_SIZE);
tagData = new ParsableByteArray(); tagData = new ParsableByteArray();
metadataReader = new ScriptTagPayloadReader();
state = STATE_READING_FLV_HEADER; state = STATE_READING_FLV_HEADER;
} }
@ -203,11 +199,7 @@ public final class FlvExtractor implements Extractor, SeekMap {
videoReader = new VideoTagPayloadReader( videoReader = new VideoTagPayloadReader(
extractorOutput.track(TAG_TYPE_VIDEO, C.TRACK_TYPE_VIDEO)); extractorOutput.track(TAG_TYPE_VIDEO, C.TRACK_TYPE_VIDEO));
} }
if (metadataReader == null) {
metadataReader = new ScriptTagPayloadReader(null);
}
extractorOutput.endTracks(); extractorOutput.endTracks();
extractorOutput.seekMap(this);
// We need to skip any additional content in the FLV header, plus the 4 byte previous tag size. // We need to skip any additional content in the FLV header, plus the 4 byte previous tag size.
bytesToNextTagHeader = headerBuffer.readInt() - FLV_HEADER_SIZE + 4; bytesToNextTagHeader = headerBuffer.readInt() - FLV_HEADER_SIZE + 4;
@ -263,11 +255,18 @@ public final class FlvExtractor implements Extractor, SeekMap {
private boolean readTagData(ExtractorInput input) throws IOException, InterruptedException { private boolean readTagData(ExtractorInput input) throws IOException, InterruptedException {
boolean wasConsumed = true; boolean wasConsumed = true;
if (tagType == TAG_TYPE_AUDIO && audioReader != null) { if (tagType == TAG_TYPE_AUDIO && audioReader != null) {
ensureOutputSeekMap();
audioReader.consume(prepareTagData(input), tagTimestampUs); audioReader.consume(prepareTagData(input), tagTimestampUs);
} else if (tagType == TAG_TYPE_VIDEO && videoReader != null) { } else if (tagType == TAG_TYPE_VIDEO && videoReader != null) {
ensureOutputSeekMap();
videoReader.consume(prepareTagData(input), tagTimestampUs); videoReader.consume(prepareTagData(input), tagTimestampUs);
} else if (tagType == TAG_TYPE_SCRIPT_DATA && metadataReader != null) { } else if (tagType == TAG_TYPE_SCRIPT_DATA && !outputSeekMap) {
metadataReader.consume(prepareTagData(input), tagTimestampUs); metadataReader.consume(prepareTagData(input), tagTimestampUs);
long durationUs = metadataReader.getDurationUs();
if (durationUs != C.TIME_UNSET) {
extractorOutput.seekMap(new SeekMap.Unseekable(durationUs));
outputSeekMap = true;
}
} else { } else {
input.skipFully(tagDataSize); input.skipFully(tagDataSize);
wasConsumed = false; wasConsumed = false;
@ -289,21 +288,11 @@ public final class FlvExtractor implements Extractor, SeekMap {
return tagData; return tagData;
} }
// SeekMap implementation. private void ensureOutputSeekMap() {
if (!outputSeekMap) {
@Override extractorOutput.seekMap(new SeekMap.Unseekable(C.TIME_UNSET));
public boolean isSeekable() { outputSeekMap = true;
return false; }
}
@Override
public long getDurationUs() {
return metadataReader.getDurationUs();
}
@Override
public long getPosition(long timeUs) {
return 0;
} }
} }

View File

@ -17,7 +17,6 @@ package com.google.android.exoplayer2.extractor.flv;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ParserException; import com.google.android.exoplayer2.ParserException;
import com.google.android.exoplayer2.extractor.TrackOutput;
import com.google.android.exoplayer2.util.ParsableByteArray; import com.google.android.exoplayer2.util.ParsableByteArray;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
@ -44,11 +43,8 @@ import java.util.Map;
private long durationUs; private long durationUs;
/** public ScriptTagPayloadReader() {
* @param output A {@link TrackOutput} to which samples should be written. super(null);
*/
public ScriptTagPayloadReader(TrackOutput output) {
super(output);
durationUs = C.TIME_UNSET; durationUs = C.TIME_UNSET;
} }

View File

@ -23,7 +23,6 @@ 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.PositionHolder; import com.google.android.exoplayer2.extractor.PositionHolder;
import com.google.android.exoplayer2.extractor.SeekMap;
import com.google.android.exoplayer2.extractor.TrackOutput; import com.google.android.exoplayer2.extractor.TrackOutput;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import java.io.IOException; import java.io.IOException;
@ -31,7 +30,7 @@ import java.io.IOException;
/** /**
* Extracts data from WAV byte streams. * Extracts data from WAV byte streams.
*/ */
public final class WavExtractor implements Extractor, SeekMap { public final class WavExtractor implements Extractor {
/** /**
* Factory for {@link WavExtractor} instances. * Factory for {@link WavExtractor} instances.
@ -95,7 +94,7 @@ public final class WavExtractor implements Extractor, SeekMap {
if (!wavHeader.hasDataBounds()) { if (!wavHeader.hasDataBounds()) {
WavHeaderReader.skipToData(input, wavHeader); WavHeaderReader.skipToData(input, wavHeader);
extractorOutput.seekMap(this); extractorOutput.seekMap(wavHeader);
} }
int bytesAppended = trackOutput.sampleData(input, MAX_INPUT_SIZE - pendingBytes, true); int bytesAppended = trackOutput.sampleData(input, MAX_INPUT_SIZE - pendingBytes, true);
@ -115,20 +114,4 @@ public final class WavExtractor implements Extractor, SeekMap {
return bytesAppended == RESULT_END_OF_INPUT ? RESULT_END_OF_INPUT : RESULT_CONTINUE; return bytesAppended == RESULT_END_OF_INPUT ? RESULT_END_OF_INPUT : RESULT_CONTINUE;
} }
// SeekMap implementation.
@Override
public long getDurationUs() {
return wavHeader.getDurationUs();
}
@Override
public boolean isSeekable() {
return true;
}
@Override
public long getPosition(long timeUs) {
return wavHeader.getPosition(timeUs);
}
} }

View File

@ -16,9 +16,10 @@
package com.google.android.exoplayer2.extractor.wav; package com.google.android.exoplayer2.extractor.wav;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.extractor.SeekMap;
/** Header for a WAV file. */ /** Header for a WAV file. */
/*package*/ final class WavHeader { /* package */ final class WavHeader implements SeekMap {
/** Number of audio chanels. */ /** Number of audio chanels. */
private final int numChannels; private final int numChannels;
@ -49,12 +50,56 @@ import com.google.android.exoplayer2.C;
this.encoding = encoding; this.encoding = encoding;
} }
/** Returns the duration in microseconds of this WAV. */ // Setting bounds.
/**
* Sets the data start position and size in bytes of sample data in this WAV.
*
* @param dataStartPosition The data start position in bytes.
* @param dataSize The data size in bytes.
*/
public void setDataBounds(long dataStartPosition, long dataSize) {
this.dataStartPosition = dataStartPosition;
this.dataSize = dataSize;
}
/** Returns whether the data start position and size have been set. */
public boolean hasDataBounds() {
return dataStartPosition != 0 && dataSize != 0;
}
// SeekMap implementation.
@Override
public boolean isSeekable() {
return true;
}
@Override
public long getDurationUs() { public long getDurationUs() {
long numFrames = dataSize / blockAlignment; long numFrames = dataSize / blockAlignment;
return (numFrames * C.MICROS_PER_SECOND) / sampleRateHz; return (numFrames * C.MICROS_PER_SECOND) / sampleRateHz;
} }
@Override
public long getPosition(long timeUs) {
long unroundedPosition = (timeUs * averageBytesPerSecond) / C.MICROS_PER_SECOND;
// Round down to nearest frame.
long position = (unroundedPosition / blockAlignment) * blockAlignment;
return Math.min(position, dataSize - blockAlignment) + dataStartPosition;
}
// Misc getters.
/**
* Returns the time in microseconds for the given position in bytes.
*
* @param position The position in bytes.
*/
public long getTimeUs(long position) {
return position * C.MICROS_PER_SECOND / averageBytesPerSecond;
}
/** Returns the bytes per frame of this WAV. */ /** Returns the bytes per frame of this WAV. */
public int getBytesPerFrame() { public int getBytesPerFrame() {
return blockAlignment; return blockAlignment;
@ -75,33 +120,8 @@ import com.google.android.exoplayer2.C;
return numChannels; return numChannels;
} }
/** Returns the position in bytes in this WAV for the given time in microseconds. */
public long getPosition(long timeUs) {
long unroundedPosition = (timeUs * averageBytesPerSecond) / C.MICROS_PER_SECOND;
// Round down to nearest frame.
long position = (unroundedPosition / blockAlignment) * blockAlignment;
return Math.min(position, dataSize - blockAlignment) + dataStartPosition;
}
/** Returns the time in microseconds for the given position in bytes in this WAV. */
public long getTimeUs(long position) {
return position * C.MICROS_PER_SECOND / averageBytesPerSecond;
}
/** Returns true if the data start position and size have been set. */
public boolean hasDataBounds() {
return dataStartPosition != 0 && dataSize != 0;
}
/** Sets the start position and size in bytes of sample data in this WAV. */
public void setDataBounds(long dataStartPosition, long dataSize) {
this.dataStartPosition = dataStartPosition;
this.dataSize = dataSize;
}
/** Returns the PCM encoding. **/ /** Returns the PCM encoding. **/
@C.PcmEncoding public @C.PcmEncoding int getEncoding() {
public int getEncoding() {
return encoding; return encoding;
} }