Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
SDK
/
exoplayer
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
694ccf42
authored
Oct 18, 2019
by
samrobinson
Committed by
Oliver Woodman
Oct 18, 2019
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Added an ICY header workaround for unseekable MP3 streams.
Issue:#6537 PiperOrigin-RevId: 275477266
parent
b7f335c7
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
104 additions
and
43 deletions
RELEASENOTES.md
library/core/src/main/java/com/google/android/exoplayer2/extractor/SeekMap.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/ConstantBitrateSeeker.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/MlltSeeker.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/Mp3Extractor.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/Seeker.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/VbriSeeker.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/XingSeeker.java
library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaPeriod.java
RELEASENOTES.md
View file @
694ccf42
...
...
@@ -93,6 +93,11 @@
fragment) (
[
#6470
](
https://github.com/google/ExoPlayer/issues/6470
)
).
*
Add
`MediaPeriod.isLoading`
to improve
`Player.isLoading`
state.
*
Make show and hide player controls accessible for TalkBack in
`PlayerView`
.
*
Add workaround to avoid truncating MP3 live streams with ICY metadata and
introductions that have a seeking header
(
[
#6537
](
https://github.com/google/ExoPlayer/issues/6537
)
,
[
#6315
](
https://github.com/google/ExoPlayer/issues/6315
)
and
[
#5658
](
https://github.com/google/ExoPlayer/issues/5658
)
).
*
Pass the codec output
`MediaFormat`
to
`VideoFrameMetadataListener`
.
### 2.10.6 (2019-10-17) ###
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/SeekMap.java
View file @
694ccf42
...
...
@@ -25,7 +25,7 @@ import com.google.android.exoplayer2.util.Assertions;
public
interface
SeekMap
{
/** A {@link SeekMap} that does not support seeking. */
final
class
Unseekable
implements
SeekMap
{
class
Unseekable
implements
SeekMap
{
private
final
long
durationUs
;
private
final
SeekPoints
startSeekPoints
;
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/ConstantBitrateSeeker.java
View file @
694ccf42
...
...
@@ -22,8 +22,7 @@ import com.google.android.exoplayer2.extractor.MpegAudioHeader;
/**
* MP3 seeker that doesn't rely on metadata and seeks assuming the source has a constant bitrate.
*/
/* package */
final
class
ConstantBitrateSeeker
extends
ConstantBitrateSeekMap
implements
Mp3Extractor
.
Seeker
{
/* package */
final
class
ConstantBitrateSeeker
extends
ConstantBitrateSeekMap
implements
Seeker
{
/**
* @param inputLength The length of the stream in bytes, or {@link C#LENGTH_UNSET} if unknown.
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/MlltSeeker.java
View file @
694ccf42
...
...
@@ -22,7 +22,7 @@ import com.google.android.exoplayer2.metadata.id3.MlltFrame;
import
com.google.android.exoplayer2.util.Util
;
/** MP3 seeker that uses metadata from an {@link MlltFrame}. */
/* package */
final
class
MlltSeeker
implements
Mp3Extractor
.
Seeker
{
/* package */
final
class
MlltSeeker
implements
Seeker
{
/**
* Returns an {@link MlltSeeker} for seeking in the stream.
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/Mp3Extractor.java
View file @
694ccf42
...
...
@@ -28,8 +28,8 @@ import com.google.android.exoplayer2.extractor.GaplessInfoHolder;
import
com.google.android.exoplayer2.extractor.Id3Peeker
;
import
com.google.android.exoplayer2.extractor.MpegAudioHeader
;
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.mp3.Seeker.UnseekableSeeker
;
import
com.google.android.exoplayer2.metadata.Metadata
;
import
com.google.android.exoplayer2.metadata.id3.Id3Decoder
;
import
com.google.android.exoplayer2.metadata.id3.Id3Decoder.FramePredicate
;
...
...
@@ -113,7 +113,8 @@ public final class Mp3Extractor implements Extractor {
private
int
synchronizedHeaderData
;
private
Metadata
metadata
;
private
Seeker
seeker
;
@Nullable
private
Seeker
seeker
;
private
boolean
disableSeeking
;
private
long
basisTimeUs
;
private
long
samplesRead
;
private
long
firstSamplePosition
;
...
...
@@ -187,14 +188,19 @@ public final class Mp3Extractor implements Extractor {
// takes priority as it can provide greater precision.
Seeker
seekFrameSeeker
=
maybeReadSeekFrame
(
input
);
Seeker
metadataSeeker
=
maybeHandleSeekMetadata
(
metadata
,
input
.
getPosition
());
if
(
metadataSeeker
!=
null
)
{
seeker
=
metadataSeeker
;
}
else
if
(
seekFrameSeeker
!=
null
)
{
seeker
=
seekFrameSeeker
;
}
if
(
seeker
==
null
||
(!
seeker
.
isSeekable
()
&&
(
flags
&
FLAG_ENABLE_CONSTANT_BITRATE_SEEKING
)
!=
0
))
{
seeker
=
getConstantBitrateSeeker
(
input
);
if
(
disableSeeking
)
{
seeker
=
new
UnseekableSeeker
();
}
else
{
if
(
metadataSeeker
!=
null
)
{
seeker
=
metadataSeeker
;
}
else
if
(
seekFrameSeeker
!=
null
)
{
seeker
=
seekFrameSeeker
;
}
if
(
seeker
==
null
||
(!
seeker
.
isSeekable
()
&&
(
flags
&
FLAG_ENABLE_CONSTANT_BITRATE_SEEKING
)
!=
0
))
{
seeker
=
getConstantBitrateSeeker
(
input
);
}
}
extractorOutput
.
seekMap
(
seeker
);
trackOutput
.
format
(
...
...
@@ -225,6 +231,15 @@ public final class Mp3Extractor implements Extractor {
return
readSample
(
input
);
}
/**
* Disables the extractor from being able to seek through the media.
*
* <p>Please note that this needs to be called before {@link #read}.
*/
public
void
disableSeeking
()
{
disableSeeking
=
true
;
}
// Internal methods.
private
int
readSample
(
ExtractorInput
extractorInput
)
throws
IOException
,
InterruptedException
{
...
...
@@ -463,26 +478,5 @@ public final class Mp3Extractor implements Extractor {
return
null
;
}
/**
* {@link SeekMap} that provides the end position of audio data and also allows mapping from
* position (byte offset) back to time, which can be used to work out the new sample basis
* timestamp after seeking and resynchronization.
*/
/* package */
interface
Seeker
extends
SeekMap
{
/**
* Maps a position (byte offset) to a corresponding sample timestamp.
*
* @param position A seek position (byte offset) relative to the start of the stream.
* @return The corresponding timestamp of the next sample to be read, in microseconds.
*/
long
getTimeUs
(
long
position
);
/**
* Returns the position (byte offset) in the stream that is immediately after audio data, or
* {@link C#POSITION_UNSET} if not known.
*/
long
getDataEndPosition
();
}
}
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/Seeker.java
0 → 100644
View file @
694ccf42
/*
* Copyright (C) 2019 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.SeekMap
;
/**
* {@link SeekMap} that provides the end position of audio data and also allows mapping from
* position (byte offset) back to time, which can be used to work out the new sample basis timestamp
* after seeking and resynchronization.
*/
/* package */
interface
Seeker
extends
SeekMap
{
/**
* Maps a position (byte offset) to a corresponding sample timestamp.
*
* @param position A seek position (byte offset) relative to the start of the stream.
* @return The corresponding timestamp of the next sample to be read, in microseconds.
*/
long
getTimeUs
(
long
position
);
/**
* Returns the position (byte offset) in the stream that is immediately after audio data, or
* {@link C#POSITION_UNSET} if not known.
*/
long
getDataEndPosition
();
/** A {@link Seeker} that does not support seeking through audio data. */
/* package */
class
UnseekableSeeker
extends
SeekMap
.
Unseekable
implements
Seeker
{
public
UnseekableSeeker
()
{
super
(
/* durationUs= */
C
.
TIME_UNSET
);
}
@Override
public
long
getTimeUs
(
long
position
)
{
return
0
;
}
@Override
public
long
getDataEndPosition
()
{
// Position unset as we do not know the data end position. Note that returning 0 doesn't work.
return
C
.
POSITION_UNSET
;
}
}
}
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/VbriSeeker.java
View file @
694ccf42
...
...
@@ -23,10 +23,8 @@ import com.google.android.exoplayer2.util.Log;
import
com.google.android.exoplayer2.util.ParsableByteArray
;
import
com.google.android.exoplayer2.util.Util
;
/**
* MP3 seeker that uses metadata from a VBRI header.
*/
/* package */
final
class
VbriSeeker
implements
Mp3Extractor
.
Seeker
{
/** MP3 seeker that uses metadata from a VBRI header. */
/* package */
final
class
VbriSeeker
implements
Seeker
{
private
static
final
String
TAG
=
"VbriSeeker"
;
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/XingSeeker.java
View file @
694ccf42
...
...
@@ -24,10 +24,8 @@ import com.google.android.exoplayer2.util.Log;
import
com.google.android.exoplayer2.util.ParsableByteArray
;
import
com.google.android.exoplayer2.util.Util
;
/**
* MP3 seeker that uses metadata from a Xing header.
*/
/* package */
final
class
XingSeeker
implements
Mp3Extractor
.
Seeker
{
/** MP3 seeker that uses metadata from a Xing header. */
/* package */
final
class
XingSeeker
implements
Seeker
{
private
static
final
String
TAG
=
"XingSeeker"
;
...
...
library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaPeriod.java
View file @
694ccf42
...
...
@@ -34,6 +34,7 @@ import com.google.android.exoplayer2.extractor.SeekMap;
import
com.google.android.exoplayer2.extractor.SeekMap.SeekPoints
;
import
com.google.android.exoplayer2.extractor.SeekMap.Unseekable
;
import
com.google.android.exoplayer2.extractor.TrackOutput
;
import
com.google.android.exoplayer2.extractor.mp3.Mp3Extractor
;
import
com.google.android.exoplayer2.metadata.Metadata
;
import
com.google.android.exoplayer2.metadata.icy.IcyHeaders
;
import
com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher
;
...
...
@@ -985,6 +986,12 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
}
input
=
new
DefaultExtractorInput
(
extractorDataSource
,
position
,
length
);
Extractor
extractor
=
extractorHolder
.
selectExtractor
(
input
,
extractorOutput
,
uri
);
// MP3 live streams commonly have seekable metadata, despite being unseekable.
if
(
icyHeaders
!=
null
&&
extractor
instanceof
Mp3Extractor
)
{
((
Mp3Extractor
)
extractor
).
disableSeeking
();
}
if
(
pendingExtractorSeek
)
{
extractor
.
seek
(
position
,
seekTimeUs
);
pendingExtractorSeek
=
false
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment