Add IndexSeeker to MP3 extractor

This seeker is only seeking to frames that have already been read by the
extractor for playback. Seeking to not-yet-read frames will be
implemented in another change.

Issue: #6787
PiperOrigin-RevId: 291888899
This commit is contained in:
kimvde 2020-01-28 09:48:00 +00:00 committed by Ian Baker
parent bb9b3fd45e
commit 103bd4199c
8 changed files with 1241 additions and 7 deletions

View file

@ -0,0 +1,95 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.extractor.mp3;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.extractor.SeekPoint;
import com.google.android.exoplayer2.util.LongArray;
import com.google.android.exoplayer2.util.Util;
/** MP3 seeker that builds a time-to-byte mapping as the stream is read. */
/* package */ final class IndexSeeker implements Seeker {
private static final long MIN_TIME_BETWEEN_POINTS_US = C.MICROS_PER_SECOND / 10;
private final long durationUs;
private final long dataEndPosition;
private final LongArray timesUs;
private final LongArray positions;
public IndexSeeker(long durationUs, long dataStartPosition, long dataEndPosition) {
this.durationUs = durationUs;
this.dataEndPosition = dataEndPosition;
timesUs = new LongArray();
positions = new LongArray();
timesUs.add(0L);
positions.add(dataStartPosition);
}
@Override
public long getTimeUs(long position) {
int targetIndex =
Util.binarySearchFloor(
positions, position, /* inclusive= */ true, /* stayInBounds= */ true);
return timesUs.get(targetIndex);
}
@Override
public long getDataEndPosition() {
return dataEndPosition;
}
@Override
public boolean isSeekable() {
return true;
}
@Override
public long getDurationUs() {
return durationUs;
}
@Override
public SeekPoints getSeekPoints(long timeUs) {
int targetIndex =
Util.binarySearchFloor(timesUs, timeUs, /* inclusive= */ true, /* stayInBounds= */ true);
SeekPoint seekPoint = new SeekPoint(timesUs.get(targetIndex), positions.get(targetIndex));
if (seekPoint.timeUs >= timeUs || targetIndex == timesUs.size() - 1) {
return new SeekPoints(seekPoint);
} else {
SeekPoint nextSeekPoint =
new SeekPoint(timesUs.get(targetIndex + 1), positions.get(targetIndex + 1));
return new SeekPoints(seekPoint, nextSeekPoint);
}
}
/**
* Adds a seek point to the index if it is sufficiently distant from the other points.
*
* <p>Seek points must be added in order.
*
* @param timeUs The time corresponding to the seek point to add in microseconds.
* @param position The position corresponding to the seek point to add in bytes.
*/
public void maybeAddSeekPoint(long timeUs, long position) {
long lastTimeUs = timesUs.get(timesUs.size() - 1);
if (timeUs - lastTimeUs < MIN_TIME_BETWEEN_POINTS_US) {
return;
}
timesUs.add(timeUs);
positions.add(position);
}
}

View file

@ -56,24 +56,35 @@ public final class Mp3Extractor implements Extractor {
/**
* Flags controlling the behavior of the extractor. Possible flag values are {@link
* #FLAG_ENABLE_CONSTANT_BITRATE_SEEKING} and {@link #FLAG_DISABLE_ID3_METADATA}.
* #FLAG_ENABLE_CONSTANT_BITRATE_SEEKING}, {@link #FLAG_ENABLE_INDEX_SEEKING} and {@link
* #FLAG_DISABLE_ID3_METADATA}.
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@IntDef(
flag = true,
value = {FLAG_ENABLE_CONSTANT_BITRATE_SEEKING, FLAG_DISABLE_ID3_METADATA})
value = {
FLAG_ENABLE_CONSTANT_BITRATE_SEEKING,
FLAG_ENABLE_INDEX_SEEKING,
FLAG_DISABLE_ID3_METADATA
})
public @interface Flags {}
/**
* Flag to force enable seeking using a constant bitrate assumption in cases where seeking would
* otherwise not be possible.
*
* <p>This flag is ignored if {@link #FLAG_ENABLE_INDEX_SEEKING} is set.
*/
public static final int FLAG_ENABLE_CONSTANT_BITRATE_SEEKING = 1;
/**
* Flag to force index seeking, consisting in building a time-to-byte mapping as the file is read.
*/
public static final int FLAG_ENABLE_INDEX_SEEKING = 1 << 1;
/**
* Flag to disable parsing of ID3 metadata. Can be set to save memory if ID3 metadata is not
* required.
*/
public static final int FLAG_DISABLE_ID3_METADATA = 2;
public static final int FLAG_DISABLE_ID3_METADATA = 1 << 2;
/** Predicate that matches ID3 frames containing only required gapless/seeking metadata. */
private static final FramePredicate REQUIRED_ID3_FRAME_PREDICATE =
@ -256,6 +267,9 @@ public final class Mp3Extractor implements Extractor {
}
}
sampleBytesRemaining = synchronizedHeader.frameSize;
maybeAddSeekPointToIndexSeeker(
computeTimeUs(samplesRead + synchronizedHeader.samplesPerFrame),
extractorInput.getPosition() + synchronizedHeader.frameSize);
}
int bytesAppended = trackOutput.sampleData(extractorInput, sampleBytesRemaining, true);
if (bytesAppended == C.RESULT_END_OF_INPUT) {
@ -265,14 +279,24 @@ public final class Mp3Extractor implements Extractor {
if (sampleBytesRemaining > 0) {
return RESULT_CONTINUE;
}
long timeUs = basisTimeUs + (samplesRead * C.MICROS_PER_SECOND / synchronizedHeader.sampleRate);
trackOutput.sampleMetadata(timeUs, C.BUFFER_FLAG_KEY_FRAME, synchronizedHeader.frameSize, 0,
null);
trackOutput.sampleMetadata(
computeTimeUs(samplesRead), C.BUFFER_FLAG_KEY_FRAME, synchronizedHeader.frameSize, 0, null);
samplesRead += synchronizedHeader.samplesPerFrame;
sampleBytesRemaining = 0;
return RESULT_CONTINUE;
}
private long computeTimeUs(long samplesRead) {
return basisTimeUs + samplesRead * C.MICROS_PER_SECOND / synchronizedHeader.sampleRate;
}
private void maybeAddSeekPointToIndexSeeker(long timeUs, long position) {
if (!(seeker instanceof IndexSeeker)) {
return;
}
((IndexSeeker) seeker).maybeAddSeekPoint(timeUs, position);
}
private boolean synchronize(ExtractorInput input, boolean sniffing)
throws IOException, InterruptedException {
int validFrameCount = 0;
@ -379,7 +403,20 @@ public final class Mp3Extractor implements Extractor {
}
@Nullable Seeker resultSeeker = null;
if (metadataSeeker != null) {
if ((flags & FLAG_ENABLE_INDEX_SEEKING) != 0) {
long durationUs = C.TIME_UNSET;
long dataEndPosition = C.POSITION_UNSET;
if (metadataSeeker != null) {
durationUs = metadataSeeker.getDurationUs();
dataEndPosition = metadataSeeker.getDataEndPosition();
} else if (seekFrameSeeker != null) {
durationUs = seekFrameSeeker.getDurationUs();
dataEndPosition = seekFrameSeeker.getDataEndPosition();
}
resultSeeker =
new IndexSeeker(
durationUs, /* dataStartPosition= */ input.getPosition(), dataEndPosition);
} else if (metadataSeeker != null) {
resultSeeker = metadataSeeker;
} else if (seekFrameSeeker != null) {
resultSeeker = seekFrameSeeker;

Binary file not shown.

View file

@ -0,0 +1,499 @@
seekMap:
isSeekable = true
duration = 2808000
getPosition(0) = [[timeUs=0, position=237]]
numberOfTracks = 1
track 0:
format:
bitrate = -1
id = null
containerMimeType = null
sampleMimeType = audio/mpeg
maxInputSize = 4096
width = -1
height = -1
frameRate = -1.0
rotationDegrees = 0
pixelWidthHeightRatio = 1.0
channelCount = 2
sampleRate = 48000
pcmEncoding = -1
encoderDelay = 576
encoderPadding = 576
subsampleOffsetUs = 9223372036854775807
selectionFlags = 0
language = null
drmInitData = -
metadata = entries=[TSSE: description=null: value=Lavf58.29.100]
initializationData:
total output bytes = 38160
sample count = 117
sample 0:
time = 0
flags = 1
data = length 96, hash 1F161542
sample 1:
time = 24000
flags = 1
data = length 768, hash CD1DC50F
sample 2:
time = 48000
flags = 1
data = length 336, hash 3F64124B
sample 3:
time = 72000
flags = 1
data = length 336, hash 8FFED94E
sample 4:
time = 96000
flags = 1
data = length 288, hash 9CD77D47
sample 5:
time = 120000
flags = 1
data = length 384, hash 24607BB5
sample 6:
time = 144000
flags = 1
data = length 480, hash 4937EBAB
sample 7:
time = 168000
flags = 1
data = length 336, hash 546342B1
sample 8:
time = 192000
flags = 1
data = length 336, hash 79E0923F
sample 9:
time = 216000
flags = 1
data = length 336, hash AB1F3948
sample 10:
time = 240000
flags = 1
data = length 336, hash C3A4D888
sample 11:
time = 264000
flags = 1
data = length 288, hash 7867DA45
sample 12:
time = 288000
flags = 1
data = length 336, hash B1240B73
sample 13:
time = 312000
flags = 1
data = length 336, hash 94CFCD35
sample 14:
time = 336000
flags = 1
data = length 288, hash 94F412C
sample 15:
time = 360000
flags = 1
data = length 336, hash A1D9FF41
sample 16:
time = 384000
flags = 1
data = length 288, hash 2A8DA21B
sample 17:
time = 408000
flags = 1
data = length 336, hash 6A429CE
sample 18:
time = 432000
flags = 1
data = length 336, hash 68853982
sample 19:
time = 456000
flags = 1
data = length 384, hash 1D6F779C
sample 20:
time = 480000
flags = 1
data = length 480, hash 6B31EBEE
sample 21:
time = 504000
flags = 1
data = length 336, hash 888335BE
sample 22:
time = 528000
flags = 1
data = length 336, hash 6072AC8B
sample 23:
time = 552000
flags = 1
data = length 336, hash C9D24234
sample 24:
time = 576000
flags = 1
data = length 288, hash 52BF4D1E
sample 25:
time = 600000
flags = 1
data = length 336, hash F93F4F0
sample 26:
time = 624000
flags = 1
data = length 336, hash 8617688A
sample 27:
time = 648000
flags = 1
data = length 480, hash FAB0D31B
sample 28:
time = 672000
flags = 1
data = length 384, hash FA4B53E2
sample 29:
time = 696000
flags = 1
data = length 336, hash 8C435F6A
sample 30:
time = 720000
flags = 1
data = length 336, hash 60D3F80C
sample 31:
time = 744000
flags = 1
data = length 336, hash DC15B68B
sample 32:
time = 768000
flags = 1
data = length 288, hash FF3DF141
sample 33:
time = 792000
flags = 1
data = length 336, hash A64B3042
sample 34:
time = 816000
flags = 1
data = length 336, hash ACA622A1
sample 35:
time = 840000
flags = 1
data = length 288, hash 3E34B8D4
sample 36:
time = 864000
flags = 1
data = length 288, hash 9B96F72A
sample 37:
time = 888000
flags = 1
data = length 336, hash E917C122
sample 38:
time = 912000
flags = 1
data = length 336, hash 10ED1470
sample 39:
time = 936000
flags = 1
data = length 288, hash 706B8A7C
sample 40:
time = 960000
flags = 1
data = length 336, hash 71FFE4A0
sample 41:
time = 984000
flags = 1
data = length 336, hash D4160463
sample 42:
time = 1008000
flags = 1
data = length 336, hash EC557B14
sample 43:
time = 1032000
flags = 1
data = length 288, hash 5598CF8B
sample 44:
time = 1056000
flags = 1
data = length 336, hash 7E0AB41
sample 45:
time = 1080000
flags = 1
data = length 336, hash 1C585FEF
sample 46:
time = 1104000
flags = 1
data = length 336, hash A4A4855E
sample 47:
time = 1128000
flags = 1
data = length 336, hash CECA51D3
sample 48:
time = 1152000
flags = 1
data = length 288, hash 2D362DC5
sample 49:
time = 1176000
flags = 1
data = length 336, hash 9EB2609D
sample 50:
time = 1200000
flags = 1
data = length 336, hash 28FFB3FE
sample 51:
time = 1224000
flags = 1
data = length 288, hash 2AA2D216
sample 52:
time = 1248000
flags = 1
data = length 336, hash CDBC7032
sample 53:
time = 1272000
flags = 1
data = length 336, hash 25B13FE7
sample 54:
time = 1296000
flags = 1
data = length 336, hash DB6BB1E
sample 55:
time = 1320000
flags = 1
data = length 336, hash EBE951F4
sample 56:
time = 1344000
flags = 1
data = length 288, hash 9E2EBFF7
sample 57:
time = 1368000
flags = 1
data = length 336, hash 36A7D455
sample 58:
time = 1392000
flags = 1
data = length 336, hash 84545F8C
sample 59:
time = 1416000
flags = 1
data = length 336, hash F66F3045
sample 60:
time = 1440000
flags = 1
data = length 576, hash 5AB089EA
sample 61:
time = 1464000
flags = 1
data = length 336, hash 8868086
sample 62:
time = 1488000
flags = 1
data = length 336, hash D5EB6D63
sample 63:
time = 1512000
flags = 1
data = length 288, hash 7A5374B7
sample 64:
time = 1536000
flags = 1
data = length 336, hash BEB27A75
sample 65:
time = 1560000
flags = 1
data = length 336, hash E251E0FD
sample 66:
time = 1584000
flags = 1
data = length 288, hash D54C970
sample 67:
time = 1608000
flags = 1
data = length 336, hash 52C473B9
sample 68:
time = 1632000
flags = 1
data = length 336, hash F5F13334
sample 69:
time = 1656000
flags = 1
data = length 480, hash A5F1E987
sample 70:
time = 1680000
flags = 1
data = length 288, hash 453A1267
sample 71:
time = 1704000
flags = 1
data = length 288, hash 7C6C2EA9
sample 72:
time = 1728000
flags = 1
data = length 336, hash F4BFECA4
sample 73:
time = 1752000
flags = 1
data = length 336, hash 751A395A
sample 74:
time = 1776000
flags = 1
data = length 336, hash EE38DB02
sample 75:
time = 1800000
flags = 1
data = length 336, hash F18837E2
sample 76:
time = 1824000
flags = 1
data = length 336, hash ED36B78E
sample 77:
time = 1848000
flags = 1
data = length 336, hash B3D28289
sample 78:
time = 1872000
flags = 1
data = length 288, hash 8BDE28E1
sample 79:
time = 1896000
flags = 1
data = length 336, hash CFD5E966
sample 80:
time = 1920000
flags = 1
data = length 288, hash DC08E267
sample 81:
time = 1944000
flags = 1
data = length 336, hash 6530CB78
sample 82:
time = 1968000
flags = 1
data = length 336, hash 6CC6636E
sample 83:
time = 1992000
flags = 1
data = length 336, hash 613047C1
sample 84:
time = 2016000
flags = 1
data = length 288, hash CDC747BF
sample 85:
time = 2040000
flags = 1
data = length 336, hash AF22AA74
sample 86:
time = 2064000
flags = 1
data = length 384, hash 82F326AA
sample 87:
time = 2088000
flags = 1
data = length 384, hash EDA26C4D
sample 88:
time = 2112000
flags = 1
data = length 336, hash 94C643DC
sample 89:
time = 2136000
flags = 1
data = length 288, hash CB5D9C40
sample 90:
time = 2160000
flags = 1
data = length 336, hash 1E69DE3F
sample 91:
time = 2184000
flags = 1
data = length 336, hash 7E472219
sample 92:
time = 2208000
flags = 1
data = length 336, hash DA47B9FA
sample 93:
time = 2232000
flags = 1
data = length 336, hash DD0ABB7C
sample 94:
time = 2256000
flags = 1
data = length 288, hash DBF93FAC
sample 95:
time = 2280000
flags = 1
data = length 336, hash 243F4B2
sample 96:
time = 2304000
flags = 1
data = length 336, hash 2E881490
sample 97:
time = 2328000
flags = 1
data = length 288, hash 1C28C8BE
sample 98:
time = 2352000
flags = 1
data = length 336, hash C73E5D30
sample 99:
time = 2376000
flags = 1
data = length 288, hash 98B5BFF6
sample 100:
time = 2400000
flags = 1
data = length 336, hash E0135533
sample 101:
time = 2424000
flags = 1
data = length 336, hash D13C9DBC
sample 102:
time = 2448000
flags = 1
data = length 336, hash 63D524CA
sample 103:
time = 2472000
flags = 1
data = length 288, hash A28514C3
sample 104:
time = 2496000
flags = 1
data = length 336, hash 72B647FF
sample 105:
time = 2520000
flags = 1
data = length 336, hash 8F740AB1
sample 106:
time = 2544000
flags = 1
data = length 336, hash 5E3C7E93
sample 107:
time = 2568000
flags = 1
data = length 336, hash 121B913B
sample 108:
time = 2592000
flags = 1
data = length 336, hash 578FCCF2
sample 109:
time = 2616000
flags = 1
data = length 336, hash 5B5823DE
sample 110:
time = 2640000
flags = 1
data = length 384, hash D8B83F78
sample 111:
time = 2664000
flags = 1
data = length 240, hash E649682F
sample 112:
time = 2688000
flags = 1
data = length 96, hash C559A6F4
sample 113:
time = 2712000
flags = 1
data = length 96, hash 792796BC
sample 114:
time = 2736000
flags = 1
data = length 120, hash 8172CD0E
sample 115:
time = 2760000
flags = 1
data = length 120, hash F562B52F
sample 116:
time = 2784000
flags = 1
data = length 96, hash FF8D5B98
tracksEnded = true

View file

@ -0,0 +1,359 @@
seekMap:
isSeekable = true
duration = 2808000
getPosition(0) = [[timeUs=0, position=237]]
numberOfTracks = 1
track 0:
format:
bitrate = -1
id = null
containerMimeType = null
sampleMimeType = audio/mpeg
maxInputSize = 4096
width = -1
height = -1
frameRate = -1.0
rotationDegrees = 0
pixelWidthHeightRatio = 1.0
channelCount = 2
sampleRate = 48000
pcmEncoding = -1
encoderDelay = 576
encoderPadding = 576
subsampleOffsetUs = 9223372036854775807
selectionFlags = 0
language = null
drmInitData = -
metadata = entries=[TSSE: description=null: value=Lavf58.29.100]
initializationData:
total output bytes = 25920
sample count = 82
sample 0:
time = 840000
flags = 1
data = length 288, hash 3E34B8D4
sample 1:
time = 864000
flags = 1
data = length 288, hash 9B96F72A
sample 2:
time = 888000
flags = 1
data = length 336, hash E917C122
sample 3:
time = 912000
flags = 1
data = length 336, hash 10ED1470
sample 4:
time = 936000
flags = 1
data = length 288, hash 706B8A7C
sample 5:
time = 960000
flags = 1
data = length 336, hash 71FFE4A0
sample 6:
time = 984000
flags = 1
data = length 336, hash D4160463
sample 7:
time = 1008000
flags = 1
data = length 336, hash EC557B14
sample 8:
time = 1032000
flags = 1
data = length 288, hash 5598CF8B
sample 9:
time = 1056000
flags = 1
data = length 336, hash 7E0AB41
sample 10:
time = 1080000
flags = 1
data = length 336, hash 1C585FEF
sample 11:
time = 1104000
flags = 1
data = length 336, hash A4A4855E
sample 12:
time = 1128000
flags = 1
data = length 336, hash CECA51D3
sample 13:
time = 1152000
flags = 1
data = length 288, hash 2D362DC5
sample 14:
time = 1176000
flags = 1
data = length 336, hash 9EB2609D
sample 15:
time = 1200000
flags = 1
data = length 336, hash 28FFB3FE
sample 16:
time = 1224000
flags = 1
data = length 288, hash 2AA2D216
sample 17:
time = 1248000
flags = 1
data = length 336, hash CDBC7032
sample 18:
time = 1272000
flags = 1
data = length 336, hash 25B13FE7
sample 19:
time = 1296000
flags = 1
data = length 336, hash DB6BB1E
sample 20:
time = 1320000
flags = 1
data = length 336, hash EBE951F4
sample 21:
time = 1344000
flags = 1
data = length 288, hash 9E2EBFF7
sample 22:
time = 1368000
flags = 1
data = length 336, hash 36A7D455
sample 23:
time = 1392000
flags = 1
data = length 336, hash 84545F8C
sample 24:
time = 1416000
flags = 1
data = length 336, hash F66F3045
sample 25:
time = 1440000
flags = 1
data = length 576, hash 5AB089EA
sample 26:
time = 1464000
flags = 1
data = length 336, hash 8868086
sample 27:
time = 1488000
flags = 1
data = length 336, hash D5EB6D63
sample 28:
time = 1512000
flags = 1
data = length 288, hash 7A5374B7
sample 29:
time = 1536000
flags = 1
data = length 336, hash BEB27A75
sample 30:
time = 1560000
flags = 1
data = length 336, hash E251E0FD
sample 31:
time = 1584000
flags = 1
data = length 288, hash D54C970
sample 32:
time = 1608000
flags = 1
data = length 336, hash 52C473B9
sample 33:
time = 1632000
flags = 1
data = length 336, hash F5F13334
sample 34:
time = 1656000
flags = 1
data = length 480, hash A5F1E987
sample 35:
time = 1680000
flags = 1
data = length 288, hash 453A1267
sample 36:
time = 1704000
flags = 1
data = length 288, hash 7C6C2EA9
sample 37:
time = 1728000
flags = 1
data = length 336, hash F4BFECA4
sample 38:
time = 1752000
flags = 1
data = length 336, hash 751A395A
sample 39:
time = 1776000
flags = 1
data = length 336, hash EE38DB02
sample 40:
time = 1800000
flags = 1
data = length 336, hash F18837E2
sample 41:
time = 1824000
flags = 1
data = length 336, hash ED36B78E
sample 42:
time = 1848000
flags = 1
data = length 336, hash B3D28289
sample 43:
time = 1872000
flags = 1
data = length 288, hash 8BDE28E1
sample 44:
time = 1896000
flags = 1
data = length 336, hash CFD5E966
sample 45:
time = 1920000
flags = 1
data = length 288, hash DC08E267
sample 46:
time = 1944000
flags = 1
data = length 336, hash 6530CB78
sample 47:
time = 1968000
flags = 1
data = length 336, hash 6CC6636E
sample 48:
time = 1992000
flags = 1
data = length 336, hash 613047C1
sample 49:
time = 2016000
flags = 1
data = length 288, hash CDC747BF
sample 50:
time = 2040000
flags = 1
data = length 336, hash AF22AA74
sample 51:
time = 2064000
flags = 1
data = length 384, hash 82F326AA
sample 52:
time = 2088000
flags = 1
data = length 384, hash EDA26C4D
sample 53:
time = 2112000
flags = 1
data = length 336, hash 94C643DC
sample 54:
time = 2136000
flags = 1
data = length 288, hash CB5D9C40
sample 55:
time = 2160000
flags = 1
data = length 336, hash 1E69DE3F
sample 56:
time = 2184000
flags = 1
data = length 336, hash 7E472219
sample 57:
time = 2208000
flags = 1
data = length 336, hash DA47B9FA
sample 58:
time = 2232000
flags = 1
data = length 336, hash DD0ABB7C
sample 59:
time = 2256000
flags = 1
data = length 288, hash DBF93FAC
sample 60:
time = 2280000
flags = 1
data = length 336, hash 243F4B2
sample 61:
time = 2304000
flags = 1
data = length 336, hash 2E881490
sample 62:
time = 2328000
flags = 1
data = length 288, hash 1C28C8BE
sample 63:
time = 2352000
flags = 1
data = length 336, hash C73E5D30
sample 64:
time = 2376000
flags = 1
data = length 288, hash 98B5BFF6
sample 65:
time = 2400000
flags = 1
data = length 336, hash E0135533
sample 66:
time = 2424000
flags = 1
data = length 336, hash D13C9DBC
sample 67:
time = 2448000
flags = 1
data = length 336, hash 63D524CA
sample 68:
time = 2472000
flags = 1
data = length 288, hash A28514C3
sample 69:
time = 2496000
flags = 1
data = length 336, hash 72B647FF
sample 70:
time = 2520000
flags = 1
data = length 336, hash 8F740AB1
sample 71:
time = 2544000
flags = 1
data = length 336, hash 5E3C7E93
sample 72:
time = 2568000
flags = 1
data = length 336, hash 121B913B
sample 73:
time = 2592000
flags = 1
data = length 336, hash 578FCCF2
sample 74:
time = 2616000
flags = 1
data = length 336, hash 5B5823DE
sample 75:
time = 2640000
flags = 1
data = length 384, hash D8B83F78
sample 76:
time = 2664000
flags = 1
data = length 240, hash E649682F
sample 77:
time = 2688000
flags = 1
data = length 96, hash C559A6F4
sample 78:
time = 2712000
flags = 1
data = length 96, hash 792796BC
sample 79:
time = 2736000
flags = 1
data = length 120, hash 8172CD0E
sample 80:
time = 2760000
flags = 1
data = length 120, hash F562B52F
sample 81:
time = 2784000
flags = 1
data = length 96, hash FF8D5B98
tracksEnded = true

View file

@ -0,0 +1,199 @@
seekMap:
isSeekable = true
duration = 2808000
getPosition(0) = [[timeUs=0, position=237]]
numberOfTracks = 1
track 0:
format:
bitrate = -1
id = null
containerMimeType = null
sampleMimeType = audio/mpeg
maxInputSize = 4096
width = -1
height = -1
frameRate = -1.0
rotationDegrees = 0
pixelWidthHeightRatio = 1.0
channelCount = 2
sampleRate = 48000
pcmEncoding = -1
encoderDelay = 576
encoderPadding = 576
subsampleOffsetUs = 9223372036854775807
selectionFlags = 0
language = null
drmInitData = -
metadata = entries=[TSSE: description=null: value=Lavf58.29.100]
initializationData:
total output bytes = 12624
sample count = 42
sample 0:
time = 1800000
flags = 1
data = length 336, hash F18837E2
sample 1:
time = 1824000
flags = 1
data = length 336, hash ED36B78E
sample 2:
time = 1848000
flags = 1
data = length 336, hash B3D28289
sample 3:
time = 1872000
flags = 1
data = length 288, hash 8BDE28E1
sample 4:
time = 1896000
flags = 1
data = length 336, hash CFD5E966
sample 5:
time = 1920000
flags = 1
data = length 288, hash DC08E267
sample 6:
time = 1944000
flags = 1
data = length 336, hash 6530CB78
sample 7:
time = 1968000
flags = 1
data = length 336, hash 6CC6636E
sample 8:
time = 1992000
flags = 1
data = length 336, hash 613047C1
sample 9:
time = 2016000
flags = 1
data = length 288, hash CDC747BF
sample 10:
time = 2040000
flags = 1
data = length 336, hash AF22AA74
sample 11:
time = 2064000
flags = 1
data = length 384, hash 82F326AA
sample 12:
time = 2088000
flags = 1
data = length 384, hash EDA26C4D
sample 13:
time = 2112000
flags = 1
data = length 336, hash 94C643DC
sample 14:
time = 2136000
flags = 1
data = length 288, hash CB5D9C40
sample 15:
time = 2160000
flags = 1
data = length 336, hash 1E69DE3F
sample 16:
time = 2184000
flags = 1
data = length 336, hash 7E472219
sample 17:
time = 2208000
flags = 1
data = length 336, hash DA47B9FA
sample 18:
time = 2232000
flags = 1
data = length 336, hash DD0ABB7C
sample 19:
time = 2256000
flags = 1
data = length 288, hash DBF93FAC
sample 20:
time = 2280000
flags = 1
data = length 336, hash 243F4B2
sample 21:
time = 2304000
flags = 1
data = length 336, hash 2E881490
sample 22:
time = 2328000
flags = 1
data = length 288, hash 1C28C8BE
sample 23:
time = 2352000
flags = 1
data = length 336, hash C73E5D30
sample 24:
time = 2376000
flags = 1
data = length 288, hash 98B5BFF6
sample 25:
time = 2400000
flags = 1
data = length 336, hash E0135533
sample 26:
time = 2424000
flags = 1
data = length 336, hash D13C9DBC
sample 27:
time = 2448000
flags = 1
data = length 336, hash 63D524CA
sample 28:
time = 2472000
flags = 1
data = length 288, hash A28514C3
sample 29:
time = 2496000
flags = 1
data = length 336, hash 72B647FF
sample 30:
time = 2520000
flags = 1
data = length 336, hash 8F740AB1
sample 31:
time = 2544000
flags = 1
data = length 336, hash 5E3C7E93
sample 32:
time = 2568000
flags = 1
data = length 336, hash 121B913B
sample 33:
time = 2592000
flags = 1
data = length 336, hash 578FCCF2
sample 34:
time = 2616000
flags = 1
data = length 336, hash 5B5823DE
sample 35:
time = 2640000
flags = 1
data = length 384, hash D8B83F78
sample 36:
time = 2664000
flags = 1
data = length 240, hash E649682F
sample 37:
time = 2688000
flags = 1
data = length 96, hash C559A6F4
sample 38:
time = 2712000
flags = 1
data = length 96, hash 792796BC
sample 39:
time = 2736000
flags = 1
data = length 120, hash 8172CD0E
sample 40:
time = 2760000
flags = 1
data = length 120, hash F562B52F
sample 41:
time = 2784000
flags = 1
data = length 96, hash FF8D5B98
tracksEnded = true

View file

@ -0,0 +1,39 @@
seekMap:
isSeekable = true
duration = 2808000
getPosition(0) = [[timeUs=0, position=237]]
numberOfTracks = 1
track 0:
format:
bitrate = -1
id = null
containerMimeType = null
sampleMimeType = audio/mpeg
maxInputSize = 4096
width = -1
height = -1
frameRate = -1.0
rotationDegrees = 0
pixelWidthHeightRatio = 1.0
channelCount = 2
sampleRate = 48000
pcmEncoding = -1
encoderDelay = 576
encoderPadding = 576
subsampleOffsetUs = 9223372036854775807
selectionFlags = 0
language = null
drmInitData = -
metadata = entries=[TSSE: description=null: value=Lavf58.29.100]
initializationData:
total output bytes = 216
sample count = 2
sample 0:
time = 2760000
flags = 1
data = length 120, hash F562B52F
sample 1:
time = 2784000
flags = 1
data = length 96, hash FF8D5B98
tracksEnded = true

View file

@ -35,6 +35,12 @@ public final class Mp3ExtractorTest {
Mp3Extractor::new, "mp3/bear-cbr-variable-frame-size-no-seek-table.mp3");
}
@Test
public void testMp3SampleWithIndexSeeker() throws Exception {
ExtractorAsserts.assertBehavior(
() -> new Mp3Extractor(Mp3Extractor.FLAG_ENABLE_INDEX_SEEKING), "mp3/bear-vbr.mp3");
}
@Test
public void testTrimmedMp3Sample() throws Exception {
ExtractorAsserts.assertBehavior(Mp3Extractor::new, "mp3/play-trimmed.mp3");