Snap to frame boundary in ConstantBitrateSeeker
- This change snaps the seek position for constant bitrate MP3s to the nearest frame boundary, avoiding the need to skip one byte at a time to re-synchronize (this may still happen if the MP3 does not really have fixed size frames). - Tweaked both ConstantBitrateSeeker and WavHeader to ensure the returned positions are valid. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=177441798
This commit is contained in:
parent
21d55d4eba
commit
cc54d4d3e6
@ -25,5 +25,9 @@ track 0:
|
||||
language = null
|
||||
drmInitData = -
|
||||
initializationData:
|
||||
sample count = 0
|
||||
sample count = 1
|
||||
sample 0:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 418, hash B819987
|
||||
tracksEnded = true
|
||||
|
@ -25,5 +25,9 @@ track 0:
|
||||
language = null
|
||||
drmInitData = -
|
||||
initializationData:
|
||||
sample count = 0
|
||||
sample count = 1
|
||||
sample 0:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 418, hash B819987
|
||||
tracksEnded = true
|
||||
|
@ -25,5 +25,9 @@ track 0:
|
||||
language = null
|
||||
drmInitData = -
|
||||
initializationData:
|
||||
sample count = 0
|
||||
sample count = 1
|
||||
sample 0:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 418, hash B819987
|
||||
tracksEnded = true
|
||||
|
@ -26,27 +26,47 @@ import com.google.android.exoplayer2.util.Util;
|
||||
private static final int BITS_PER_BYTE = 8;
|
||||
|
||||
private final long firstFramePosition;
|
||||
private final long dataSize;
|
||||
private final int frameSize;
|
||||
private final int bitrate;
|
||||
private final long durationUs;
|
||||
|
||||
public ConstantBitrateSeeker(long firstFramePosition, int bitrate, long inputLength) {
|
||||
/**
|
||||
* @param firstFramePosition The position (byte offset) of the first frame.
|
||||
* @param inputLength The length of the stream.
|
||||
* @param frameSize The size of a single frame in the stream.
|
||||
* @param bitrate The stream's bitrate.
|
||||
*/
|
||||
public ConstantBitrateSeeker(long firstFramePosition, long inputLength, int frameSize,
|
||||
int bitrate) {
|
||||
this.firstFramePosition = firstFramePosition;
|
||||
this.frameSize = frameSize;
|
||||
this.bitrate = bitrate;
|
||||
durationUs = inputLength == C.LENGTH_UNSET ? C.TIME_UNSET : getTimeUs(inputLength);
|
||||
if (inputLength == C.LENGTH_UNSET) {
|
||||
dataSize = C.LENGTH_UNSET;
|
||||
durationUs = C.TIME_UNSET;
|
||||
} else {
|
||||
dataSize = inputLength - firstFramePosition;
|
||||
durationUs = getTimeUs(inputLength);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSeekable() {
|
||||
return durationUs != C.TIME_UNSET;
|
||||
return dataSize != C.LENGTH_UNSET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPosition(long timeUs) {
|
||||
if (durationUs == C.TIME_UNSET) {
|
||||
if (dataSize == C.LENGTH_UNSET) {
|
||||
return firstFramePosition;
|
||||
}
|
||||
timeUs = Util.constrainValue(timeUs, 0, durationUs);
|
||||
return firstFramePosition + (timeUs * bitrate) / (C.MICROS_PER_SECOND * BITS_PER_BYTE);
|
||||
long positionOffset = (timeUs * bitrate) / (C.MICROS_PER_SECOND * BITS_PER_BYTE);
|
||||
// Constrain to nearest preceding frame offset.
|
||||
positionOffset = (positionOffset / frameSize) * frameSize;
|
||||
positionOffset = Util.constrainValue(positionOffset, 0, dataSize - frameSize);
|
||||
// Add data start position.
|
||||
return firstFramePosition + positionOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -393,8 +393,8 @@ public final class Mp3Extractor implements Extractor {
|
||||
input.peekFully(scratch.data, 0, 4);
|
||||
scratch.setPosition(0);
|
||||
MpegAudioHeader.populateHeader(scratch.readInt(), synchronizedHeader);
|
||||
return new ConstantBitrateSeeker(input.getPosition(), synchronizedHeader.bitrate,
|
||||
input.getLength());
|
||||
return new ConstantBitrateSeeker(input.getPosition(), input.getLength(),
|
||||
synchronizedHeader.frameSize, synchronizedHeader.bitrate);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -17,6 +17,7 @@ package com.google.android.exoplayer2.extractor.wav;
|
||||
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.extractor.SeekMap;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
|
||||
/** Header for a WAV file. */
|
||||
/* package */ final class WavHeader implements SeekMap {
|
||||
@ -83,10 +84,12 @@ import com.google.android.exoplayer2.extractor.SeekMap;
|
||||
|
||||
@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;
|
||||
long positionOffset = (timeUs * averageBytesPerSecond) / C.MICROS_PER_SECOND;
|
||||
// Constrain to nearest preceding frame offset.
|
||||
positionOffset = (positionOffset / blockAlignment) * blockAlignment;
|
||||
positionOffset = Util.constrainValue(positionOffset, 0, dataSize - blockAlignment);
|
||||
// Add data start position.
|
||||
return dataStartPosition + positionOffset;
|
||||
}
|
||||
|
||||
// Misc getters.
|
||||
|
Loading…
x
Reference in New Issue
Block a user