Parse TLEN duration in Mp3Extractor

Issue: #7949
PiperOrigin-RevId: 333733615
This commit is contained in:
kimvde 2020-09-25 16:01:54 +01:00 committed by Oliver Woodman
parent 19530866c7
commit 57f11d1556
3 changed files with 32 additions and 8 deletions

View File

@ -14,6 +14,8 @@
* Extractors: * Extractors:
* Add support for .mp2 boxes in the `AtomParsers` * Add support for .mp2 boxes in the `AtomParsers`
([#7967](https://github.com/google/ExoPlayer/issues/7967)). ([#7967](https://github.com/google/ExoPlayer/issues/7967)).
* Use TLEN ID3 tag to compute the duration in Mp3Extractor
([#7949](https://github.com/google/ExoPlayer/issues/7949)).
### 2.12.0 (2020-09-11) ### ### 2.12.0 (2020-09-11) ###

View File

@ -29,9 +29,11 @@ import com.google.android.exoplayer2.util.Util;
* *
* @param firstFramePosition The position of the start of the first frame in the stream. * @param firstFramePosition The position of the start of the first frame in the stream.
* @param mlltFrame The MLLT frame with seeking metadata. * @param mlltFrame The MLLT frame with seeking metadata.
* @param durationUs The stream duration in microseconds, or {@link C#TIME_UNSET} if it is
* unknown.
* @return An {@link MlltSeeker} for seeking in the stream. * @return An {@link MlltSeeker} for seeking in the stream.
*/ */
public static MlltSeeker create(long firstFramePosition, MlltFrame mlltFrame) { public static MlltSeeker create(long firstFramePosition, MlltFrame mlltFrame, long durationUs) {
int referenceCount = mlltFrame.bytesDeviations.length; int referenceCount = mlltFrame.bytesDeviations.length;
long[] referencePositions = new long[1 + referenceCount]; long[] referencePositions = new long[1 + referenceCount];
long[] referenceTimesMs = new long[1 + referenceCount]; long[] referenceTimesMs = new long[1 + referenceCount];
@ -45,19 +47,22 @@ import com.google.android.exoplayer2.util.Util;
referencePositions[i] = position; referencePositions[i] = position;
referenceTimesMs[i] = timeMs; referenceTimesMs[i] = timeMs;
} }
return new MlltSeeker(referencePositions, referenceTimesMs); return new MlltSeeker(referencePositions, referenceTimesMs, durationUs);
} }
private final long[] referencePositions; private final long[] referencePositions;
private final long[] referenceTimesMs; private final long[] referenceTimesMs;
private final long durationUs; private final long durationUs;
private MlltSeeker(long[] referencePositions, long[] referenceTimesMs) { private MlltSeeker(long[] referencePositions, long[] referenceTimesMs, long durationUs) {
this.referencePositions = referencePositions; this.referencePositions = referencePositions;
this.referenceTimesMs = referenceTimesMs; this.referenceTimesMs = referenceTimesMs;
// Use the last reference point as the duration, as extrapolating variable bitrate at the end of // Use the last reference point as the duration if it is unknown, as extrapolating variable
// the stream may give a large error. // bitrate at the end of the stream may give a large error.
durationUs = C.msToUs(referenceTimesMs[referenceTimesMs.length - 1]); this.durationUs =
durationUs != C.TIME_UNSET
? durationUs
: C.msToUs(referenceTimesMs[referenceTimesMs.length - 1]);
} }
@Override @Override

View File

@ -35,6 +35,7 @@ import com.google.android.exoplayer2.metadata.Metadata;
import com.google.android.exoplayer2.metadata.id3.Id3Decoder; import com.google.android.exoplayer2.metadata.id3.Id3Decoder;
import com.google.android.exoplayer2.metadata.id3.Id3Decoder.FramePredicate; import com.google.android.exoplayer2.metadata.id3.Id3Decoder.FramePredicate;
import com.google.android.exoplayer2.metadata.id3.MlltFrame; import com.google.android.exoplayer2.metadata.id3.MlltFrame;
import com.google.android.exoplayer2.metadata.id3.TextInformationFrame;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.ParsableByteArray; import com.google.android.exoplayer2.util.ParsableByteArray;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
@ -432,7 +433,7 @@ public final class Mp3Extractor implements Extractor {
@Nullable Seeker resultSeeker = null; @Nullable Seeker resultSeeker = null;
if ((flags & FLAG_ENABLE_INDEX_SEEKING) != 0) { if ((flags & FLAG_ENABLE_INDEX_SEEKING) != 0) {
long durationUs = C.TIME_UNSET; long durationUs;
long dataEndPosition = C.POSITION_UNSET; long dataEndPosition = C.POSITION_UNSET;
if (metadataSeeker != null) { if (metadataSeeker != null) {
durationUs = metadataSeeker.getDurationUs(); durationUs = metadataSeeker.getDurationUs();
@ -440,6 +441,8 @@ public final class Mp3Extractor implements Extractor {
} else if (seekFrameSeeker != null) { } else if (seekFrameSeeker != null) {
durationUs = seekFrameSeeker.getDurationUs(); durationUs = seekFrameSeeker.getDurationUs();
dataEndPosition = seekFrameSeeker.getDataEndPosition(); dataEndPosition = seekFrameSeeker.getDataEndPosition();
} else {
durationUs = getId3TlenUs(metadata);
} }
resultSeeker = resultSeeker =
new IndexSeeker( new IndexSeeker(
@ -554,10 +557,24 @@ public final class Mp3Extractor implements Extractor {
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
Metadata.Entry entry = metadata.get(i); Metadata.Entry entry = metadata.get(i);
if (entry instanceof MlltFrame) { if (entry instanceof MlltFrame) {
return MlltSeeker.create(firstFramePosition, (MlltFrame) entry); return MlltSeeker.create(firstFramePosition, (MlltFrame) entry, getId3TlenUs(metadata));
} }
} }
} }
return null; return null;
} }
private static long getId3TlenUs(@Nullable Metadata metadata) {
if (metadata != null) {
int length = metadata.length();
for (int i = 0; i < length; i++) {
Metadata.Entry entry = metadata.get(i);
if (entry instanceof TextInformationFrame
&& ((TextInformationFrame) entry).id.equals("TLEN")) {
return C.msToUs(Long.parseLong(((TextInformationFrame) entry).value));
}
}
}
return C.TIME_UNSET;
}
} }