Optimize seeking for unseekable SeekMaps

- Avoid re-downloading data prior to the first mdat box when
  seeking back to the start of an unseekable FMP4.
- Avoid re-downloading data prior to the first frame for
  constant bitrate MP3.
- Update SeekMap.getPosition documentation to allow a non-zero
  position for the unseekable case. Note that XingSeeker was
  already returning a non-zero position if unseekable.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=177317256
This commit is contained in:
olly 2017-11-29 09:09:17 -08:00 committed by Oliver Woodman
parent 21ea9a821d
commit a99ef01d3a
3 changed files with 17 additions and 4 deletions

View File

@ -28,13 +28,24 @@ public interface SeekMap {
final class Unseekable implements SeekMap {
private final long durationUs;
private final long startPosition;
/**
* @param durationUs The duration of the stream in microseconds, or {@link C#TIME_UNSET} if
* the duration is unknown.
*/
public Unseekable(long durationUs) {
this(durationUs, 0);
}
/**
* @param durationUs The duration of the stream in microseconds, or {@link C#TIME_UNSET} if
* the duration is unknown.
* @param startPosition The position (byte offset) of the start of the media.
*/
public Unseekable(long durationUs, long startPosition) {
this.durationUs = durationUs;
this.startPosition = startPosition;
}
@Override
@ -49,7 +60,7 @@ public interface SeekMap {
@Override
public long getPosition(long timeUs) {
return 0;
return startPosition;
}
}
@ -78,7 +89,8 @@ public interface SeekMap {
*
* @param timeUs A seek position in microseconds.
* @return The corresponding position (byte offset) in the stream from which data can be provided
* to the extractor, or 0 if {@code #isSeekable()} returns false.
* to the extractor. If {@link #isSeekable()} returns false then the returned value will be
* independent of {@code timeUs}, and will indicate the start of the media in the stream.
*/
long getPosition(long timeUs);

View File

@ -43,7 +43,7 @@ import com.google.android.exoplayer2.util.Util;
@Override
public long getPosition(long timeUs) {
if (durationUs == C.TIME_UNSET) {
return 0;
return firstFramePosition;
}
timeUs = Util.constrainValue(timeUs, 0, durationUs);
return firstFramePosition + (timeUs * bitrate) / (C.MICROS_PER_SECOND * BITS_PER_BYTE);

View File

@ -345,7 +345,8 @@ public final class FragmentedMp4Extractor implements Extractor {
currentTrackBundle = null;
endOfMdatPosition = atomPosition + atomSize;
if (!haveOutputSeekMap) {
extractorOutput.seekMap(new SeekMap.Unseekable(durationUs));
// This must be the first mdat in the stream.
extractorOutput.seekMap(new SeekMap.Unseekable(durationUs, atomPosition));
haveOutputSeekMap = true;
}
parserState = STATE_READING_ENCRYPTION_DATA;