Clean up some extrator SeekMap implementations
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=177173618
This commit is contained in:
parent
baa80a1b68
commit
ff49bc97c4
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user