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
71f72c59
authored
Dec 21, 2018
by
Oliver Woodman
Committed by
GitHub
Dec 21, 2018
Browse files
Options
_('Browse Files')
Download
Plain Diff
Merge pull request #5283 from google/dev-v2-r2.9.3
r2.9.3
parents
6b0e1758
f042ae4c
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
68 changed files
with
909 additions
and
301 deletions
RELEASENOTES.md
constants.gradle
extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java
extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java
extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/TimelineQueueEditor.java
library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java
library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java
library/core/src/main/java/com/google/android/exoplayer2/Player.java
library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java
library/core/src/main/java/com/google/android/exoplayer2/audio/AudioRendererEventListener.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/MpegAudioHeader.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/Ac3Extractor.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/Ac3Reader.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/AdtsExtractor.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/AdtsReader.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/DtsReader.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/DvbSubtitleReader.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/ElementaryStreamReader.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H262Reader.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H264Reader.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H265Reader.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/Id3Reader.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/LatmReader.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/MpegAudioReader.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/PesReader.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/PsExtractor.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/SectionReader.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsPayloadReader.java
library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecInfo.java
library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java
library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java
library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java
library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java
library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java
library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java
library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java
library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaSource.java
library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java
library/core/src/main/java/com/google/android/exoplayer2/source/ads/AdsMediaSource.java
library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlDecoder.java
library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlNode.java
library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlSubtitle.java
library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/Cache.java
library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CachedContentIndex.java
library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/SimpleCache.java
library/core/src/main/java/com/google/android/exoplayer2/util/Util.java
library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java
library/core/src/main/java/com/google/android/exoplayer2/video/VideoRendererEventListener.java
library/core/src/test/assets/mp3/play-trimmed.mp3.0.dump
library/core/src/test/assets/mp3/play-trimmed.mp3.1.dump
library/core/src/test/assets/mp3/play-trimmed.mp3.2.dump
library/core/src/test/assets/mp3/play-trimmed.mp3.3.dump
library/core/src/test/assets/ttml/bitmap_percentage_region.xml
library/core/src/test/assets/ttml/bitmap_pixel_region.xml
library/core/src/test/assets/ttml/bitmap_unsupported_region.xml
library/core/src/test/java/com/google/android/exoplayer2/extractor/ts/AdtsReaderTest.java
library/core/src/test/java/com/google/android/exoplayer2/extractor/ts/SectionReaderTest.java
library/core/src/test/java/com/google/android/exoplayer2/extractor/ts/TsExtractorTest.java
library/core/src/test/java/com/google/android/exoplayer2/text/ttml/TtmlDecoderTest.java
library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java
library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/SimpleCacheTest.java
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java
library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java
library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerView.java
testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaSource.java
testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java
RELEASENOTES.md
View file @
71f72c59
# Release notes #
# Release notes #
### 2.9.3 ###
*
Captions: Support PNG subtitles in SMPTE-TT
(
[
#1583
](
https://github.com/google/ExoPlayer/issues/1583
)
).
*
MPEG-TS: Use random access indicators to minimize the need for
`FLAG_ALLOW_NON_IDR_KEYFRAMES`
.
*
Downloading: Reduce time taken to remove downloads
(
[
#5136
](
https://github.com/google/ExoPlayer/issues/5136
)
).
*
MP3:
*
Use the true bitrate for constant-bitrate MP3 seeking.
*
Fix issue where streams would play twice on some Samsung devices
(
[
#4519
](
https://github.com/google/ExoPlayer/issues/4519
)
).
*
Fix regression where some audio formats were incorrectly marked as being
unplayable due to under-reporting of platform decoder capabilities
(
[
#5145
](
https://github.com/google/ExoPlayer/issues/5145
)
).
*
Fix decode-only frame skipping on Nvidia Shield TV devices.
*
Workaround for MiTV (dangal) issue when swapping output surface
(
[
#5169
](
https://github.com/google/ExoPlayer/issues/5169
)
).
### 2.9.2 ###
### 2.9.2 ###
*
HLS:
*
HLS:
...
@@ -47,10 +66,10 @@
...
@@ -47,10 +66,10 @@
*
DASH: Parse ProgramInformation element if present in the manifest.
*
DASH: Parse ProgramInformation element if present in the manifest.
*
HLS:
*
HLS:
*
Add constructor to
`DefaultHlsExtractorFactory`
for adding TS payload
*
Add constructor to
`DefaultHlsExtractorFactory`
for adding TS payload
reader factory flags.
reader factory flags
(
[
#4861
](
https://github.com/google/ExoPlayer/issues/4861
)
).
*
Fix bug in segment sniffing
*
Fix bug in segment sniffing
(
[
#5039
](
https://github.com/google/ExoPlayer/issues/5039
)
).
(
[
#5039
](
https://github.com/google/ExoPlayer/issues/5039
)
).
(
[
#4861
](
https://github.com/google/ExoPlayer/issues/4861
)
).
*
SubRip: Add support for alignment tags, and remove tags from the displayed
*
SubRip: Add support for alignment tags, and remove tags from the displayed
captions (
[
#4306
](
https://github.com/google/ExoPlayer/issues/4306
)
).
captions (
[
#4306
](
https://github.com/google/ExoPlayer/issues/4306
)
).
*
Fix issue with blind seeking to windows with non-zero offset in a
*
Fix issue with blind seeking to windows with non-zero offset in a
...
...
constants.gradle
View file @
71f72c59
...
@@ -13,8 +13,8 @@
...
@@ -13,8 +13,8 @@
// limitations under the License.
// limitations under the License.
project
.
ext
{
project
.
ext
{
// ExoPlayer version and version code.
// ExoPlayer version and version code.
releaseVersion
=
'2.9.
2
'
releaseVersion
=
'2.9.
3
'
releaseVersionCode
=
200900
2
releaseVersionCode
=
200900
3
// Important: ExoPlayer specifies a minSdkVersion of 14 because various
// Important: ExoPlayer specifies a minSdkVersion of 14 because various
// components provided by the library may be of use on older devices.
// components provided by the library may be of use on older devices.
// However, please note that the core media playback functionality provided
// However, please note that the core media playback functionality provided
...
...
extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java
View file @
71f72c59
...
@@ -283,21 +283,30 @@ public final class CastPlayer extends BasePlayer {
...
@@ -283,21 +283,30 @@ public final class CastPlayer extends BasePlayer {
// Player implementation.
// Player implementation.
@Override
@Override
@Nullable
public
AudioComponent
getAudioComponent
()
{
public
AudioComponent
getAudioComponent
()
{
return
null
;
return
null
;
}
}
@Override
@Override
@Nullable
public
VideoComponent
getVideoComponent
()
{
public
VideoComponent
getVideoComponent
()
{
return
null
;
return
null
;
}
}
@Override
@Override
@Nullable
public
TextComponent
getTextComponent
()
{
public
TextComponent
getTextComponent
()
{
return
null
;
return
null
;
}
}
@Override
@Override
@Nullable
public
MetadataComponent
getMetadataComponent
()
{
return
null
;
}
@Override
public
Looper
getApplicationLooper
()
{
public
Looper
getApplicationLooper
()
{
return
Looper
.
getMainLooper
();
return
Looper
.
getMainLooper
();
}
}
...
...
extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java
View file @
71f72c59
...
@@ -77,6 +77,12 @@ public final class ImaAdsMediaSource extends BaseMediaSource implements SourceIn
...
@@ -77,6 +77,12 @@ public final class ImaAdsMediaSource extends BaseMediaSource implements SourceIn
}
}
@Override
@Override
@Nullable
public
Object
getTag
()
{
return
adsMediaSource
.
getTag
();
}
@Override
public
void
prepareSourceInternal
(
public
void
prepareSourceInternal
(
final
ExoPlayer
player
,
final
ExoPlayer
player
,
boolean
isTopLevelSource
,
boolean
isTopLevelSource
,
...
...
extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/TimelineQueueEditor.java
View file @
71f72c59
...
@@ -65,13 +65,6 @@ public final class TimelineQueueEditor
...
@@ -65,13 +65,6 @@ public final class TimelineQueueEditor
*/
*/
public
interface
QueueDataAdapter
{
public
interface
QueueDataAdapter
{
/**
/**
* Gets the {@link MediaDescriptionCompat} for a {@code position}.
*
* @param position The position in the queue for which to provide a description.
* @return A {@link MediaDescriptionCompat}.
*/
MediaDescriptionCompat
getMediaDescription
(
int
position
);
/**
* Adds a {@link MediaDescriptionCompat} at the given {@code position}.
* Adds a {@link MediaDescriptionCompat} at the given {@code position}.
*
*
* @param position The position at which to add.
* @param position The position at which to add.
...
...
library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java
View file @
71f72c59
...
@@ -144,21 +144,30 @@ import java.util.concurrent.CopyOnWriteArraySet;
...
@@ -144,21 +144,30 @@ import java.util.concurrent.CopyOnWriteArraySet;
}
}
@Override
@Override
@Nullable
public
AudioComponent
getAudioComponent
()
{
public
AudioComponent
getAudioComponent
()
{
return
null
;
return
null
;
}
}
@Override
@Override
@Nullable
public
VideoComponent
getVideoComponent
()
{
public
VideoComponent
getVideoComponent
()
{
return
null
;
return
null
;
}
}
@Override
@Override
@Nullable
public
TextComponent
getTextComponent
()
{
public
TextComponent
getTextComponent
()
{
return
null
;
return
null
;
}
}
@Override
@Override
@Nullable
public
MetadataComponent
getMetadataComponent
()
{
return
null
;
}
@Override
public
Looper
getPlaybackLooper
()
{
public
Looper
getPlaybackLooper
()
{
return
internalPlayer
.
getPlaybackLooper
();
return
internalPlayer
.
getPlaybackLooper
();
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java
View file @
71f72c59
...
@@ -29,11 +29,11 @@ public final class ExoPlayerLibraryInfo {
...
@@ -29,11 +29,11 @@ public final class ExoPlayerLibraryInfo {
/** The version of the library expressed as a string, for example "1.2.3". */
/** The version of the library expressed as a string, for example "1.2.3". */
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION_INT) or vice versa.
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION_INT) or vice versa.
public
static
final
String
VERSION
=
"2.9.
2
"
;
public
static
final
String
VERSION
=
"2.9.
3
"
;
/** The version of the library expressed as {@code "ExoPlayerLib/" + VERSION}. */
/** The version of the library expressed as {@code "ExoPlayerLib/" + VERSION}. */
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
public
static
final
String
VERSION_SLASHY
=
"ExoPlayerLib/2.9.
2
"
;
public
static
final
String
VERSION_SLASHY
=
"ExoPlayerLib/2.9.
3
"
;
/**
/**
* The version of the library expressed as an integer, for example 1002003.
* The version of the library expressed as an integer, for example 1002003.
...
@@ -43,7 +43,7 @@ public final class ExoPlayerLibraryInfo {
...
@@ -43,7 +43,7 @@ public final class ExoPlayerLibraryInfo {
* integer version 123045006 (123-045-006).
* integer version 123045006 (123-045-006).
*/
*/
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
public
static
final
int
VERSION_INT
=
200900
2
;
public
static
final
int
VERSION_INT
=
200900
3
;
/**
/**
* Whether the library was compiled with {@link com.google.android.exoplayer2.util.Assertions}
* Whether the library was compiled with {@link com.google.android.exoplayer2.util.Assertions}
...
...
library/core/src/main/java/com/google/android/exoplayer2/Player.java
View file @
71f72c59
...
@@ -26,6 +26,7 @@ import com.google.android.exoplayer2.C.VideoScalingMode;
...
@@ -26,6 +26,7 @@ import com.google.android.exoplayer2.C.VideoScalingMode;
import
com.google.android.exoplayer2.audio.AudioAttributes
;
import
com.google.android.exoplayer2.audio.AudioAttributes
;
import
com.google.android.exoplayer2.audio.AudioListener
;
import
com.google.android.exoplayer2.audio.AudioListener
;
import
com.google.android.exoplayer2.audio.AuxEffectInfo
;
import
com.google.android.exoplayer2.audio.AuxEffectInfo
;
import
com.google.android.exoplayer2.metadata.MetadataOutput
;
import
com.google.android.exoplayer2.source.TrackGroupArray
;
import
com.google.android.exoplayer2.source.TrackGroupArray
;
import
com.google.android.exoplayer2.text.TextOutput
;
import
com.google.android.exoplayer2.text.TextOutput
;
import
com.google.android.exoplayer2.trackselection.TrackSelectionArray
;
import
com.google.android.exoplayer2.trackselection.TrackSelectionArray
;
...
@@ -299,6 +300,24 @@ public interface Player {
...
@@ -299,6 +300,24 @@ public interface Player {
void
removeTextOutput
(
TextOutput
listener
);
void
removeTextOutput
(
TextOutput
listener
);
}
}
/** The metadata component of a {@link Player}. */
interface
MetadataComponent
{
/**
* Adds a {@link MetadataOutput} to receive metadata.
*
* @param output The output to register.
*/
void
addMetadataOutput
(
MetadataOutput
output
);
/**
* Removes a {@link MetadataOutput}.
*
* @param output The output to remove.
*/
void
removeMetadataOutput
(
MetadataOutput
output
);
}
/**
/**
* Listener of changes in player state. All methods have no-op default implementations to allow
* Listener of changes in player state. All methods have no-op default implementations to allow
* selective overrides.
* selective overrides.
...
@@ -534,6 +553,12 @@ public interface Player {
...
@@ -534,6 +553,12 @@ public interface Player {
TextComponent
getTextComponent
();
TextComponent
getTextComponent
();
/**
/**
* Returns the component of this player for metadata output, or null if metadata is not supported.
*/
@Nullable
MetadataComponent
getMetadataComponent
();
/**
* Returns the {@link Looper} associated with the application thread that's used to access the
* Returns the {@link Looper} associated with the application thread that's used to access the
* player and on which player events are received.
* player and on which player events are received.
*/
*/
...
...
library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java
View file @
71f72c59
...
@@ -65,7 +65,11 @@ import java.util.concurrent.CopyOnWriteArraySet;
...
@@ -65,7 +65,11 @@ import java.util.concurrent.CopyOnWriteArraySet;
*/
*/
@TargetApi
(
16
)
@TargetApi
(
16
)
public
class
SimpleExoPlayer
extends
BasePlayer
public
class
SimpleExoPlayer
extends
BasePlayer
implements
ExoPlayer
,
Player
.
AudioComponent
,
Player
.
VideoComponent
,
Player
.
TextComponent
{
implements
ExoPlayer
,
Player
.
AudioComponent
,
Player
.
VideoComponent
,
Player
.
TextComponent
,
Player
.
MetadataComponent
{
/** @deprecated Use {@link com.google.android.exoplayer2.video.VideoListener}. */
/** @deprecated Use {@link com.google.android.exoplayer2.video.VideoListener}. */
@Deprecated
@Deprecated
...
@@ -243,20 +247,29 @@ public class SimpleExoPlayer extends BasePlayer
...
@@ -243,20 +247,29 @@ public class SimpleExoPlayer extends BasePlayer
}
}
@Override
@Override
@Nullable
public
AudioComponent
getAudioComponent
()
{
public
AudioComponent
getAudioComponent
()
{
return
this
;
return
this
;
}
}
@Override
@Override
@Nullable
public
VideoComponent
getVideoComponent
()
{
public
VideoComponent
getVideoComponent
()
{
return
this
;
return
this
;
}
}
@Override
@Override
@Nullable
public
TextComponent
getTextComponent
()
{
public
TextComponent
getTextComponent
()
{
return
this
;
return
this
;
}
}
@Override
@Nullable
public
MetadataComponent
getMetadataComponent
()
{
return
this
;
}
/**
/**
* Sets the video scaling mode.
* Sets the video scaling mode.
*
*
...
@@ -713,20 +726,12 @@ public class SimpleExoPlayer extends BasePlayer
...
@@ -713,20 +726,12 @@ public class SimpleExoPlayer extends BasePlayer
removeTextOutput
(
output
);
removeTextOutput
(
output
);
}
}
/**
@Override
* Adds a {@link MetadataOutput} to receive metadata.
*
* @param listener The output to register.
*/
public
void
addMetadataOutput
(
MetadataOutput
listener
)
{
public
void
addMetadataOutput
(
MetadataOutput
listener
)
{
metadataOutputs
.
add
(
listener
);
metadataOutputs
.
add
(
listener
);
}
}
/**
@Override
* Removes a {@link MetadataOutput}.
*
* @param listener The output to remove.
*/
public
void
removeMetadataOutput
(
MetadataOutput
listener
)
{
public
void
removeMetadataOutput
(
MetadataOutput
listener
)
{
metadataOutputs
.
remove
(
listener
);
metadataOutputs
.
remove
(
listener
);
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/audio/AudioRendererEventListener.java
View file @
71f72c59
...
@@ -25,7 +25,8 @@ import com.google.android.exoplayer2.decoder.DecoderCounters;
...
@@ -25,7 +25,8 @@ import com.google.android.exoplayer2.decoder.DecoderCounters;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.Assertions
;
/**
/**
* Listener of audio {@link Renderer} events.
* Listener of audio {@link Renderer} events. All methods have no-op default implementations to
* allow selective overrides.
*/
*/
public
interface
AudioRendererEventListener
{
public
interface
AudioRendererEventListener
{
...
@@ -35,14 +36,14 @@ public interface AudioRendererEventListener {
...
@@ -35,14 +36,14 @@ public interface AudioRendererEventListener {
* @param counters {@link DecoderCounters} that will be updated by the renderer for as long as it
* @param counters {@link DecoderCounters} that will be updated by the renderer for as long as it
* remains enabled.
* remains enabled.
*/
*/
void
onAudioEnabled
(
DecoderCounters
counters
);
default
void
onAudioEnabled
(
DecoderCounters
counters
)
{}
/**
/**
* Called when the audio session is set.
* Called when the audio session is set.
*
*
* @param audioSessionId The audio session id.
* @param audioSessionId The audio session id.
*/
*/
void
onAudioSessionId
(
int
audioSessionId
);
default
void
onAudioSessionId
(
int
audioSessionId
)
{}
/**
/**
* Called when a decoder is created.
* Called when a decoder is created.
...
@@ -52,15 +53,15 @@ public interface AudioRendererEventListener {
...
@@ -52,15 +53,15 @@ public interface AudioRendererEventListener {
* finished.
* finished.
* @param initializationDurationMs The time taken to initialize the decoder in milliseconds.
* @param initializationDurationMs The time taken to initialize the decoder in milliseconds.
*/
*/
void
onAudioDecoderInitialized
(
String
decoderName
,
long
initializedTimestampMs
,
default
void
onAudioDecoderInitialized
(
long
initializationDurationMs
);
String
decoderName
,
long
initializedTimestampMs
,
long
initializationDurationMs
)
{}
/**
/**
* Called when the format of the media being consumed by the renderer changes.
* Called when the format of the media being consumed by the renderer changes.
*
*
* @param format The new format.
* @param format The new format.
*/
*/
void
onAudioInputFormatChanged
(
Format
format
);
default
void
onAudioInputFormatChanged
(
Format
format
)
{}
/**
/**
* Called when an {@link AudioSink} underrun occurs.
* Called when an {@link AudioSink} underrun occurs.
...
@@ -71,14 +72,15 @@ public interface AudioRendererEventListener {
...
@@ -71,14 +72,15 @@ public interface AudioRendererEventListener {
* as the buffered media can have a variable bitrate so the duration may be unknown.
* as the buffered media can have a variable bitrate so the duration may be unknown.
* @param elapsedSinceLastFeedMs The time since the {@link AudioSink} was last fed data.
* @param elapsedSinceLastFeedMs The time since the {@link AudioSink} was last fed data.
*/
*/
void
onAudioSinkUnderrun
(
int
bufferSize
,
long
bufferSizeMs
,
long
elapsedSinceLastFeedMs
);
default
void
onAudioSinkUnderrun
(
int
bufferSize
,
long
bufferSizeMs
,
long
elapsedSinceLastFeedMs
)
{}
/**
/**
* Called when the renderer is disabled.
* Called when the renderer is disabled.
*
*
* @param counters {@link DecoderCounters} that were updated by the renderer.
* @param counters {@link DecoderCounters} that were updated by the renderer.
*/
*/
void
onAudioDisabled
(
DecoderCounters
counters
);
default
void
onAudioDisabled
(
DecoderCounters
counters
)
{}
/**
/**
* Dispatches events to a {@link AudioRendererEventListener}.
* Dispatches events to a {@link AudioRendererEventListener}.
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/MpegAudioHeader.java
View file @
71f72c59
...
@@ -34,16 +34,26 @@ public final class MpegAudioHeader {
...
@@ -34,16 +34,26 @@ public final class MpegAudioHeader {
private
static
final
String
[]
MIME_TYPE_BY_LAYER
=
private
static
final
String
[]
MIME_TYPE_BY_LAYER
=
new
String
[]
{
MimeTypes
.
AUDIO_MPEG_L1
,
MimeTypes
.
AUDIO_MPEG_L2
,
MimeTypes
.
AUDIO_MPEG
};
new
String
[]
{
MimeTypes
.
AUDIO_MPEG_L1
,
MimeTypes
.
AUDIO_MPEG_L2
,
MimeTypes
.
AUDIO_MPEG
};
private
static
final
int
[]
SAMPLING_RATE_V1
=
{
44100
,
48000
,
32000
};
private
static
final
int
[]
SAMPLING_RATE_V1
=
{
44100
,
48000
,
32000
};
private
static
final
int
[]
BITRATE_V1_L1
=
private
static
final
int
[]
BITRATE_V1_L1
=
{
{
32
,
64
,
96
,
128
,
160
,
192
,
224
,
256
,
288
,
320
,
352
,
384
,
416
,
448
};
32000
,
64000
,
96000
,
128000
,
160000
,
192000
,
224000
,
256000
,
288000
,
320000
,
352000
,
384000
,
private
static
final
int
[]
BITRATE_V2_L1
=
416000
,
448000
{
32
,
48
,
56
,
64
,
80
,
96
,
112
,
128
,
144
,
160
,
176
,
192
,
224
,
256
};
};
private
static
final
int
[]
BITRATE_V1_L2
=
private
static
final
int
[]
BITRATE_V2_L1
=
{
{
32
,
48
,
56
,
64
,
80
,
96
,
112
,
128
,
160
,
192
,
224
,
256
,
320
,
384
};
32000
,
48000
,
56000
,
64000
,
80000
,
96000
,
112000
,
128000
,
144000
,
160000
,
176000
,
192000
,
private
static
final
int
[]
BITRATE_V1_L3
=
224000
,
256000
{
32
,
40
,
48
,
56
,
64
,
80
,
96
,
112
,
128
,
160
,
192
,
224
,
256
,
320
};
};
private
static
final
int
[]
BITRATE_V2
=
private
static
final
int
[]
BITRATE_V1_L2
=
{
{
8
,
16
,
24
,
32
,
40
,
48
,
56
,
64
,
80
,
96
,
112
,
128
,
144
,
160
};
32000
,
48000
,
56000
,
64000
,
80000
,
96000
,
112000
,
128000
,
160000
,
192000
,
224000
,
256000
,
320000
,
384000
};
private
static
final
int
[]
BITRATE_V1_L3
=
{
32000
,
40000
,
48000
,
56000
,
64000
,
80000
,
96000
,
112000
,
128000
,
160000
,
192000
,
224000
,
256000
,
320000
};
private
static
final
int
[]
BITRATE_V2
=
{
8000
,
16000
,
24000
,
32000
,
40000
,
48000
,
56000
,
64000
,
80000
,
96000
,
112000
,
128000
,
144000
,
160000
};
/**
/**
* Returns the size of the frame associated with {@code header}, or {@link C#LENGTH_UNSET} if it
* Returns the size of the frame associated with {@code header}, or {@link C#LENGTH_UNSET} if it
...
@@ -89,7 +99,7 @@ public final class MpegAudioHeader {
...
@@ -89,7 +99,7 @@ public final class MpegAudioHeader {
if
(
layer
==
3
)
{
if
(
layer
==
3
)
{
// Layer I (layer == 3)
// Layer I (layer == 3)
bitrate
=
version
==
3
?
BITRATE_V1_L1
[
bitrateIndex
-
1
]
:
BITRATE_V2_L1
[
bitrateIndex
-
1
];
bitrate
=
version
==
3
?
BITRATE_V1_L1
[
bitrateIndex
-
1
]
:
BITRATE_V2_L1
[
bitrateIndex
-
1
];
return
(
12
000
*
bitrate
/
samplingRate
+
padding
)
*
4
;
return
(
12
*
bitrate
/
samplingRate
+
padding
)
*
4
;
}
else
{
}
else
{
// Layer II (layer == 2) or III (layer == 1)
// Layer II (layer == 2) or III (layer == 1)
if
(
version
==
3
)
{
if
(
version
==
3
)
{
...
@@ -102,10 +112,10 @@ public final class MpegAudioHeader {
...
@@ -102,10 +112,10 @@ public final class MpegAudioHeader {
if
(
version
==
3
)
{
if
(
version
==
3
)
{
// Version 1
// Version 1
return
144
000
*
bitrate
/
samplingRate
+
padding
;
return
144
*
bitrate
/
samplingRate
+
padding
;
}
else
{
}
else
{
// Version 2 or 2.5
// Version 2 or 2.5
return
(
layer
==
1
?
72
000
:
144000
)
*
bitrate
/
samplingRate
+
padding
;
return
(
layer
==
1
?
72
:
144
)
*
bitrate
/
samplingRate
+
padding
;
}
}
}
}
...
@@ -159,7 +169,7 @@ public final class MpegAudioHeader {
...
@@ -159,7 +169,7 @@ public final class MpegAudioHeader {
if
(
layer
==
3
)
{
if
(
layer
==
3
)
{
// Layer I (layer == 3)
// Layer I (layer == 3)
bitrate
=
version
==
3
?
BITRATE_V1_L1
[
bitrateIndex
-
1
]
:
BITRATE_V2_L1
[
bitrateIndex
-
1
];
bitrate
=
version
==
3
?
BITRATE_V1_L1
[
bitrateIndex
-
1
]
:
BITRATE_V2_L1
[
bitrateIndex
-
1
];
frameSize
=
(
12
000
*
bitrate
/
sampleRate
+
padding
)
*
4
;
frameSize
=
(
12
*
bitrate
/
sampleRate
+
padding
)
*
4
;
samplesPerFrame
=
384
;
samplesPerFrame
=
384
;
}
else
{
}
else
{
// Layer II (layer == 2) or III (layer == 1)
// Layer II (layer == 2) or III (layer == 1)
...
@@ -167,19 +177,22 @@ public final class MpegAudioHeader {
...
@@ -167,19 +177,22 @@ public final class MpegAudioHeader {
// Version 1
// Version 1
bitrate
=
layer
==
2
?
BITRATE_V1_L2
[
bitrateIndex
-
1
]
:
BITRATE_V1_L3
[
bitrateIndex
-
1
];
bitrate
=
layer
==
2
?
BITRATE_V1_L2
[
bitrateIndex
-
1
]
:
BITRATE_V1_L3
[
bitrateIndex
-
1
];
samplesPerFrame
=
1152
;
samplesPerFrame
=
1152
;
frameSize
=
144
000
*
bitrate
/
sampleRate
+
padding
;
frameSize
=
144
*
bitrate
/
sampleRate
+
padding
;
}
else
{
}
else
{
// Version 2 or 2.5.
// Version 2 or 2.5.
bitrate
=
BITRATE_V2
[
bitrateIndex
-
1
];
bitrate
=
BITRATE_V2
[
bitrateIndex
-
1
];
samplesPerFrame
=
layer
==
1
?
576
:
1152
;
samplesPerFrame
=
layer
==
1
?
576
:
1152
;
frameSize
=
(
layer
==
1
?
72
000
:
144000
)
*
bitrate
/
sampleRate
+
padding
;
frameSize
=
(
layer
==
1
?
72
:
144
)
*
bitrate
/
sampleRate
+
padding
;
}
}
}
}
// Calculate the bitrate in the same way Mp3Extractor calculates sample timestamps so that
// seeking to a given timestamp and playing from the start up to that timestamp give the same
// results for CBR streams. See also [internal: b/120390268].
bitrate
=
8
*
frameSize
*
sampleRate
/
samplesPerFrame
;
String
mimeType
=
MIME_TYPE_BY_LAYER
[
3
-
layer
];
String
mimeType
=
MIME_TYPE_BY_LAYER
[
3
-
layer
];
int
channels
=
((
headerData
>>
6
)
&
3
)
==
3
?
1
:
2
;
int
channels
=
((
headerData
>>
6
)
&
3
)
==
3
?
1
:
2
;
header
.
setValues
(
version
,
mimeType
,
frameSize
,
sampleRate
,
channels
,
bitrate
*
1000
,
header
.
setValues
(
version
,
mimeType
,
frameSize
,
sampleRate
,
channels
,
bitrate
,
samplesPerFrame
);
samplesPerFrame
);
return
true
;
return
true
;
}
}
...
@@ -198,8 +211,14 @@ public final class MpegAudioHeader {
...
@@ -198,8 +211,14 @@ public final class MpegAudioHeader {
/** Number of samples stored in the frame. */
/** Number of samples stored in the frame. */
public
int
samplesPerFrame
;
public
int
samplesPerFrame
;
private
void
setValues
(
int
version
,
String
mimeType
,
int
frameSize
,
int
sampleRate
,
int
channels
,
private
void
setValues
(
int
bitrate
,
int
samplesPerFrame
)
{
int
version
,
String
mimeType
,
int
frameSize
,
int
sampleRate
,
int
channels
,
int
bitrate
,
int
samplesPerFrame
)
{
this
.
version
=
version
;
this
.
version
=
version
;
this
.
mimeType
=
mimeType
;
this
.
mimeType
=
mimeType
;
this
.
frameSize
=
frameSize
;
this
.
frameSize
=
frameSize
;
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/Ac3Extractor.java
View file @
71f72c59
...
@@ -15,6 +15,8 @@
...
@@ -15,6 +15,8 @@
*/
*/
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
ts
;
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
ts
;
import
static
com
.
google
.
android
.
exoplayer2
.
extractor
.
ts
.
TsPayloadReader
.
FLAG_DATA_ALIGNMENT_INDICATOR
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.audio.Ac3Util
;
import
com.google.android.exoplayer2.audio.Ac3Util
;
import
com.google.android.exoplayer2.extractor.Extractor
;
import
com.google.android.exoplayer2.extractor.Extractor
;
...
@@ -140,7 +142,7 @@ public final class Ac3Extractor implements Extractor {
...
@@ -140,7 +142,7 @@ public final class Ac3Extractor implements Extractor {
if
(!
startedPacket
)
{
if
(!
startedPacket
)
{
// Pass data to the reader as though it's contained within a single infinitely long packet.
// Pass data to the reader as though it's contained within a single infinitely long packet.
reader
.
packetStarted
(
firstSampleTimestampUs
,
true
);
reader
.
packetStarted
(
firstSampleTimestampUs
,
FLAG_DATA_ALIGNMENT_INDICATOR
);
startedPacket
=
true
;
startedPacket
=
true
;
}
}
// TODO: Make it possible for the reader to consume the dataSource directly, so that it becomes
// TODO: Make it possible for the reader to consume the dataSource directly, so that it becomes
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/Ac3Reader.java
View file @
71f72c59
...
@@ -100,7 +100,7 @@ public final class Ac3Reader implements ElementaryStreamReader {
...
@@ -100,7 +100,7 @@ public final class Ac3Reader implements ElementaryStreamReader {
}
}
@Override
@Override
public
void
packetStarted
(
long
pesTimeUs
,
boolean
dataAlignmentIndicator
)
{
public
void
packetStarted
(
long
pesTimeUs
,
@TsPayloadReader
.
Flags
int
flags
)
{
timeUs
=
pesTimeUs
;
timeUs
=
pesTimeUs
;
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/AdtsExtractor.java
View file @
71f72c59
...
@@ -15,6 +15,8 @@
...
@@ -15,6 +15,8 @@
*/
*/
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
ts
;
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
ts
;
import
static
com
.
google
.
android
.
exoplayer2
.
extractor
.
ts
.
TsPayloadReader
.
FLAG_DATA_ALIGNMENT_INDICATOR
;
import
android.support.annotation.IntDef
;
import
android.support.annotation.IntDef
;
import
android.support.annotation.Nullable
;
import
android.support.annotation.Nullable
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.C
;
...
@@ -202,7 +204,7 @@ public final class AdtsExtractor implements Extractor {
...
@@ -202,7 +204,7 @@ public final class AdtsExtractor implements Extractor {
if
(!
startedPacket
)
{
if
(!
startedPacket
)
{
// Pass data to the reader as though it's contained within a single infinitely long packet.
// Pass data to the reader as though it's contained within a single infinitely long packet.
reader
.
packetStarted
(
firstSampleTimestampUs
,
true
);
reader
.
packetStarted
(
firstSampleTimestampUs
,
FLAG_DATA_ALIGNMENT_INDICATOR
);
startedPacket
=
true
;
startedPacket
=
true
;
}
}
// TODO: Make it possible for reader to consume the dataSource directly, so that it becomes
// TODO: Make it possible for reader to consume the dataSource directly, so that it becomes
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/AdtsReader.java
View file @
71f72c59
...
@@ -141,7 +141,7 @@ public final class AdtsReader implements ElementaryStreamReader {
...
@@ -141,7 +141,7 @@ public final class AdtsReader implements ElementaryStreamReader {
}
}
@Override
@Override
public
void
packetStarted
(
long
pesTimeUs
,
boolean
dataAlignmentIndicator
)
{
public
void
packetStarted
(
long
pesTimeUs
,
@TsPayloadReader
.
Flags
int
flags
)
{
timeUs
=
pesTimeUs
;
timeUs
=
pesTimeUs
;
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/DtsReader.java
View file @
71f72c59
...
@@ -80,7 +80,7 @@ public final class DtsReader implements ElementaryStreamReader {
...
@@ -80,7 +80,7 @@ public final class DtsReader implements ElementaryStreamReader {
}
}
@Override
@Override
public
void
packetStarted
(
long
pesTimeUs
,
boolean
dataAlignmentIndicator
)
{
public
void
packetStarted
(
long
pesTimeUs
,
@TsPayloadReader
.
Flags
int
flags
)
{
timeUs
=
pesTimeUs
;
timeUs
=
pesTimeUs
;
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/DvbSubtitleReader.java
View file @
71f72c59
...
@@ -15,6 +15,8 @@
...
@@ -15,6 +15,8 @@
*/
*/
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
ts
;
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
ts
;
import
static
com
.
google
.
android
.
exoplayer2
.
extractor
.
ts
.
TsPayloadReader
.
FLAG_DATA_ALIGNMENT_INDICATOR
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.extractor.ExtractorOutput
;
import
com.google.android.exoplayer2.extractor.ExtractorOutput
;
...
@@ -73,8 +75,8 @@ public final class DvbSubtitleReader implements ElementaryStreamReader {
...
@@ -73,8 +75,8 @@ public final class DvbSubtitleReader implements ElementaryStreamReader {
}
}
@Override
@Override
public
void
packetStarted
(
long
pesTimeUs
,
boolean
dataAlignmentIndicator
)
{
public
void
packetStarted
(
long
pesTimeUs
,
@TsPayloadReader
.
Flags
int
flags
)
{
if
(
!
dataAlignmentIndicator
)
{
if
(
(
flags
&
FLAG_DATA_ALIGNMENT_INDICATOR
)
==
0
)
{
return
;
return
;
}
}
writingSample
=
true
;
writingSample
=
true
;
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/ElementaryStreamReader.java
View file @
71f72c59
...
@@ -43,9 +43,9 @@ public interface ElementaryStreamReader {
...
@@ -43,9 +43,9 @@ public interface ElementaryStreamReader {
* Called when a packet starts.
* Called when a packet starts.
*
*
* @param pesTimeUs The timestamp associated with the packet.
* @param pesTimeUs The timestamp associated with the packet.
* @param
dataAlignmentIndicator The data alignment indicator associated with the packet
.
* @param
flags See {@link TsPayloadReader.Flags}
.
*/
*/
void
packetStarted
(
long
pesTimeUs
,
boolean
dataAlignmentIndicator
);
void
packetStarted
(
long
pesTimeUs
,
@TsPayloadReader
.
Flags
int
flags
);
/**
/**
* Consumes (possibly partial) data from the current packet.
* Consumes (possibly partial) data from the current packet.
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H262Reader.java
View file @
71f72c59
...
@@ -107,7 +107,8 @@ public final class H262Reader implements ElementaryStreamReader {
...
@@ -107,7 +107,8 @@ public final class H262Reader implements ElementaryStreamReader {
}
}
@Override
@Override
public
void
packetStarted
(
long
pesTimeUs
,
boolean
dataAlignmentIndicator
)
{
public
void
packetStarted
(
long
pesTimeUs
,
@TsPayloadReader
.
Flags
int
flags
)
{
// TODO (Internal b/32267012): Consider using random access indicator.
this
.
pesTimeUs
=
pesTimeUs
;
this
.
pesTimeUs
=
pesTimeUs
;
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H264Reader.java
View file @
71f72c59
...
@@ -15,6 +15,8 @@
...
@@ -15,6 +15,8 @@
*/
*/
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
ts
;
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
ts
;
import
static
com
.
google
.
android
.
exoplayer2
.
extractor
.
ts
.
TsPayloadReader
.
FLAG_RANDOM_ACCESS_INDICATOR
;
import
android.util.SparseArray
;
import
android.util.SparseArray
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.Format
;
...
@@ -56,9 +58,12 @@ public final class H264Reader implements ElementaryStreamReader {
...
@@ -56,9 +58,12 @@ public final class H264Reader implements ElementaryStreamReader {
// State that should not be reset on seek.
// State that should not be reset on seek.
private
boolean
hasOutputFormat
;
private
boolean
hasOutputFormat
;
// Per
packet state that gets reset at the start of each
packet.
// Per
PES packet state that gets reset at the start of each PES
packet.
private
long
pesTimeUs
;
private
long
pesTimeUs
;
// State inherited from the TS packet header.
private
boolean
randomAccessIndicator
;
// Scratch variables to avoid allocations.
// Scratch variables to avoid allocations.
private
final
ParsableByteArray
seiWrapper
;
private
final
ParsableByteArray
seiWrapper
;
...
@@ -88,6 +93,7 @@ public final class H264Reader implements ElementaryStreamReader {
...
@@ -88,6 +93,7 @@ public final class H264Reader implements ElementaryStreamReader {
sei
.
reset
();
sei
.
reset
();
sampleReader
.
reset
();
sampleReader
.
reset
();
totalBytesWritten
=
0
;
totalBytesWritten
=
0
;
randomAccessIndicator
=
false
;
}
}
@Override
@Override
...
@@ -100,8 +106,9 @@ public final class H264Reader implements ElementaryStreamReader {
...
@@ -100,8 +106,9 @@ public final class H264Reader implements ElementaryStreamReader {
}
}
@Override
@Override
public
void
packetStarted
(
long
pesTimeUs
,
boolean
dataAlignmentIndicator
)
{
public
void
packetStarted
(
long
pesTimeUs
,
@TsPayloadReader
.
Flags
int
flags
)
{
this
.
pesTimeUs
=
pesTimeUs
;
this
.
pesTimeUs
=
pesTimeUs
;
randomAccessIndicator
|=
(
flags
&
FLAG_RANDOM_ACCESS_INDICATOR
)
!=
0
;
}
}
@Override
@Override
...
@@ -220,12 +227,17 @@ public final class H264Reader implements ElementaryStreamReader {
...
@@ -220,12 +227,17 @@ public final class H264Reader implements ElementaryStreamReader {
seiWrapper
.
setPosition
(
4
);
// NAL prefix and nal_unit() header.
seiWrapper
.
setPosition
(
4
);
// NAL prefix and nal_unit() header.
seiReader
.
consume
(
pesTimeUs
,
seiWrapper
);
seiReader
.
consume
(
pesTimeUs
,
seiWrapper
);
}
}
sampleReader
.
endNalUnit
(
position
,
offset
);
boolean
sampleIsKeyFrame
=
sampleReader
.
endNalUnit
(
position
,
offset
,
hasOutputFormat
,
randomAccessIndicator
);
if
(
sampleIsKeyFrame
)
{
// This is either an IDR frame or the first I-frame since the random access indicator, so mark
// it as a keyframe. Clear the flag so that subsequent non-IDR I-frames are not marked as
// keyframes until we see another random access indicator.
randomAccessIndicator
=
false
;
}
}
}
/**
/** Consumes a stream of NAL units and outputs samples. */
* Consumes a stream of NAL units and outputs samples.
*/
private
static
final
class
SampleReader
{
private
static
final
class
SampleReader
{
private
static
final
int
DEFAULT_BUFFER_SIZE
=
128
;
private
static
final
int
DEFAULT_BUFFER_SIZE
=
128
;
...
@@ -430,11 +442,12 @@ public final class H264Reader implements ElementaryStreamReader {
...
@@ -430,11 +442,12 @@ public final class H264Reader implements ElementaryStreamReader {
isFilling
=
false
;
isFilling
=
false
;
}
}
public
void
endNalUnit
(
long
position
,
int
offset
)
{
public
boolean
endNalUnit
(
long
position
,
int
offset
,
boolean
hasOutputFormat
,
boolean
randomAccessIndicator
)
{
if
(
nalUnitType
==
NAL_UNIT_TYPE_AUD
if
(
nalUnitType
==
NAL_UNIT_TYPE_AUD
||
(
detectAccessUnits
&&
sliceHeader
.
isFirstVclNalUnitOfPicture
(
previousSliceHeader
)))
{
||
(
detectAccessUnits
&&
sliceHeader
.
isFirstVclNalUnitOfPicture
(
previousSliceHeader
)))
{
// If the NAL unit ending is the start of a new sample, output the previous one.
// If the NAL unit ending is the start of a new sample, output the previous one.
if
(
readingSample
)
{
if
(
hasOutputFormat
&&
readingSample
)
{
int
nalUnitLength
=
(
int
)
(
position
-
nalUnitStartPosition
);
int
nalUnitLength
=
(
int
)
(
position
-
nalUnitStartPosition
);
outputSample
(
offset
+
nalUnitLength
);
outputSample
(
offset
+
nalUnitLength
);
}
}
...
@@ -443,8 +456,12 @@ public final class H264Reader implements ElementaryStreamReader {
...
@@ -443,8 +456,12 @@ public final class H264Reader implements ElementaryStreamReader {
sampleIsKeyframe
=
false
;
sampleIsKeyframe
=
false
;
readingSample
=
true
;
readingSample
=
true
;
}
}
sampleIsKeyframe
|=
nalUnitType
==
NAL_UNIT_TYPE_IDR
||
(
allowNonIdrKeyframes
boolean
treatIFrameAsKeyframe
=
&&
nalUnitType
==
NAL_UNIT_TYPE_NON_IDR
&&
sliceHeader
.
isISlice
());
allowNonIdrKeyframes
?
sliceHeader
.
isISlice
()
:
randomAccessIndicator
;
sampleIsKeyframe
|=
nalUnitType
==
NAL_UNIT_TYPE_IDR
||
(
treatIFrameAsKeyframe
&&
nalUnitType
==
NAL_UNIT_TYPE_NON_IDR
);
return
sampleIsKeyframe
;
}
}
private
void
outputSample
(
int
offset
)
{
private
void
outputSample
(
int
offset
)
{
...
@@ -486,10 +503,21 @@ public final class H264Reader implements ElementaryStreamReader {
...
@@ -486,10 +503,21 @@ public final class H264Reader implements ElementaryStreamReader {
hasSliceType
=
true
;
hasSliceType
=
true
;
}
}
public
void
setAll
(
SpsData
spsData
,
int
nalRefIdc
,
int
sliceType
,
int
frameNum
,
public
void
setAll
(
int
picParameterSetId
,
boolean
fieldPicFlag
,
boolean
bottomFieldFlagPresent
,
SpsData
spsData
,
boolean
bottomFieldFlag
,
boolean
idrPicFlag
,
int
idrPicId
,
int
picOrderCntLsb
,
int
nalRefIdc
,
int
deltaPicOrderCntBottom
,
int
deltaPicOrderCnt0
,
int
deltaPicOrderCnt1
)
{
int
sliceType
,
int
frameNum
,
int
picParameterSetId
,
boolean
fieldPicFlag
,
boolean
bottomFieldFlagPresent
,
boolean
bottomFieldFlag
,
boolean
idrPicFlag
,
int
idrPicId
,
int
picOrderCntLsb
,
int
deltaPicOrderCntBottom
,
int
deltaPicOrderCnt0
,
int
deltaPicOrderCnt1
)
{
this
.
spsData
=
spsData
;
this
.
spsData
=
spsData
;
this
.
nalRefIdc
=
nalRefIdc
;
this
.
nalRefIdc
=
nalRefIdc
;
this
.
sliceType
=
sliceType
;
this
.
sliceType
=
sliceType
;
...
@@ -514,23 +542,26 @@ public final class H264Reader implements ElementaryStreamReader {
...
@@ -514,23 +542,26 @@ public final class H264Reader implements ElementaryStreamReader {
private
boolean
isFirstVclNalUnitOfPicture
(
SliceHeaderData
other
)
{
private
boolean
isFirstVclNalUnitOfPicture
(
SliceHeaderData
other
)
{
// See ISO 14496-10 subsection 7.4.1.2.4.
// See ISO 14496-10 subsection 7.4.1.2.4.
return
isComplete
&&
(!
other
.
isComplete
||
frameNum
!=
other
.
frameNum
return
isComplete
||
picParameterSetId
!=
other
.
picParameterSetId
||
fieldPicFlag
!=
other
.
fieldPicFlag
&&
(!
other
.
isComplete
||
(
bottomFieldFlagPresent
&&
other
.
bottomFieldFlagPresent
||
frameNum
!=
other
.
frameNum
||
picParameterSetId
!=
other
.
picParameterSetId
||
fieldPicFlag
!=
other
.
fieldPicFlag
||
(
bottomFieldFlagPresent
&&
other
.
bottomFieldFlagPresent
&&
bottomFieldFlag
!=
other
.
bottomFieldFlag
)
&&
bottomFieldFlag
!=
other
.
bottomFieldFlag
)
||
(
nalRefIdc
!=
other
.
nalRefIdc
&&
(
nalRefIdc
==
0
||
other
.
nalRefIdc
==
0
))
||
(
nalRefIdc
!=
other
.
nalRefIdc
&&
(
nalRefIdc
==
0
||
other
.
nalRefIdc
==
0
))
||
(
spsData
.
picOrderCountType
==
0
&&
other
.
spsData
.
picOrderCountType
==
0
||
(
spsData
.
picOrderCountType
==
0
&&
other
.
spsData
.
picOrderCountType
==
0
&&
(
picOrderCntLsb
!=
other
.
picOrderCntLsb
&&
(
picOrderCntLsb
!=
other
.
picOrderCntLsb
||
deltaPicOrderCntBottom
!=
other
.
deltaPicOrderCntBottom
))
||
deltaPicOrderCntBottom
!=
other
.
deltaPicOrderCntBottom
))
||
(
spsData
.
picOrderCountType
==
1
&&
other
.
spsData
.
picOrderCountType
==
1
||
(
spsData
.
picOrderCountType
==
1
&&
other
.
spsData
.
picOrderCountType
==
1
&&
(
deltaPicOrderCnt0
!=
other
.
deltaPicOrderCnt0
&&
(
deltaPicOrderCnt0
!=
other
.
deltaPicOrderCnt0
||
deltaPicOrderCnt1
!=
other
.
deltaPicOrderCnt1
))
||
deltaPicOrderCnt1
!=
other
.
deltaPicOrderCnt1
))
||
idrPicFlag
!=
other
.
idrPicFlag
||
idrPicFlag
!=
other
.
idrPicFlag
||
(
idrPicFlag
&&
other
.
idrPicFlag
&&
idrPicId
!=
other
.
idrPicId
));
||
(
idrPicFlag
&&
other
.
idrPicFlag
&&
idrPicId
!=
other
.
idrPicId
));
}
}
}
}
}
}
}
}
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H265Reader.java
View file @
71f72c59
...
@@ -104,7 +104,8 @@ public final class H265Reader implements ElementaryStreamReader {
...
@@ -104,7 +104,8 @@ public final class H265Reader implements ElementaryStreamReader {
}
}
@Override
@Override
public
void
packetStarted
(
long
pesTimeUs
,
boolean
dataAlignmentIndicator
)
{
public
void
packetStarted
(
long
pesTimeUs
,
@TsPayloadReader
.
Flags
int
flags
)
{
// TODO (Internal b/32267012): Consider using random access indicator.
this
.
pesTimeUs
=
pesTimeUs
;
this
.
pesTimeUs
=
pesTimeUs
;
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/Id3Reader.java
View file @
71f72c59
...
@@ -15,6 +15,8 @@
...
@@ -15,6 +15,8 @@
*/
*/
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
ts
;
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
ts
;
import
static
com
.
google
.
android
.
exoplayer2
.
extractor
.
ts
.
TsPayloadReader
.
FLAG_DATA_ALIGNMENT_INDICATOR
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.extractor.ExtractorOutput
;
import
com.google.android.exoplayer2.extractor.ExtractorOutput
;
...
@@ -63,8 +65,8 @@ public final class Id3Reader implements ElementaryStreamReader {
...
@@ -63,8 +65,8 @@ public final class Id3Reader implements ElementaryStreamReader {
}
}
@Override
@Override
public
void
packetStarted
(
long
pesTimeUs
,
boolean
dataAlignmentIndicator
)
{
public
void
packetStarted
(
long
pesTimeUs
,
@TsPayloadReader
.
Flags
int
flags
)
{
if
(
!
dataAlignmentIndicator
)
{
if
(
(
flags
&
FLAG_DATA_ALIGNMENT_INDICATOR
)
==
0
)
{
return
;
return
;
}
}
writingSample
=
true
;
writingSample
=
true
;
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/LatmReader.java
View file @
71f72c59
...
@@ -93,7 +93,7 @@ public final class LatmReader implements ElementaryStreamReader {
...
@@ -93,7 +93,7 @@ public final class LatmReader implements ElementaryStreamReader {
}
}
@Override
@Override
public
void
packetStarted
(
long
pesTimeUs
,
boolean
dataAlignmentIndicator
)
{
public
void
packetStarted
(
long
pesTimeUs
,
@TsPayloadReader
.
Flags
int
flags
)
{
timeUs
=
pesTimeUs
;
timeUs
=
pesTimeUs
;
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/MpegAudioReader.java
View file @
71f72c59
...
@@ -83,7 +83,7 @@ public final class MpegAudioReader implements ElementaryStreamReader {
...
@@ -83,7 +83,7 @@ public final class MpegAudioReader implements ElementaryStreamReader {
}
}
@Override
@Override
public
void
packetStarted
(
long
pesTimeUs
,
boolean
dataAlignmentIndicator
)
{
public
void
packetStarted
(
long
pesTimeUs
,
@TsPayloadReader
.
Flags
int
flags
)
{
timeUs
=
pesTimeUs
;
timeUs
=
pesTimeUs
;
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/PesReader.java
View file @
71f72c59
...
@@ -78,9 +78,8 @@ public final class PesReader implements TsPayloadReader {
...
@@ -78,9 +78,8 @@ public final class PesReader implements TsPayloadReader {
}
}
@Override
@Override
public
final
void
consume
(
ParsableByteArray
data
,
boolean
payloadUnitStartIndicator
)
public
final
void
consume
(
ParsableByteArray
data
,
@Flags
int
flags
)
throws
ParserException
{
throws
ParserException
{
if
((
flags
&
FLAG_PAYLOAD_UNIT_START_INDICATOR
)
!=
0
)
{
if
(
payloadUnitStartIndicator
)
{
switch
(
state
)
{
switch
(
state
)
{
case
STATE_FINDING_HEADER:
case
STATE_FINDING_HEADER:
case
STATE_READING_HEADER:
case
STATE_READING_HEADER:
...
@@ -122,7 +121,8 @@ public final class PesReader implements TsPayloadReader {
...
@@ -122,7 +121,8 @@ public final class PesReader implements TsPayloadReader {
if
(
continueRead
(
data
,
pesScratch
.
data
,
readLength
)
if
(
continueRead
(
data
,
pesScratch
.
data
,
readLength
)
&&
continueRead
(
data
,
null
,
extendedHeaderLength
))
{
&&
continueRead
(
data
,
null
,
extendedHeaderLength
))
{
parseHeaderExtension
();
parseHeaderExtension
();
reader
.
packetStarted
(
timeUs
,
dataAlignmentIndicator
);
flags
|=
dataAlignmentIndicator
?
FLAG_DATA_ALIGNMENT_INDICATOR
:
0
;
reader
.
packetStarted
(
timeUs
,
flags
);
setState
(
STATE_READING_BODY
);
setState
(
STATE_READING_BODY
);
}
}
break
;
break
;
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/PsExtractor.java
View file @
71f72c59
...
@@ -343,7 +343,7 @@ public final class PsExtractor implements Extractor {
...
@@ -343,7 +343,7 @@ public final class PsExtractor implements Extractor {
data
.
readBytes
(
pesScratch
.
data
,
0
,
extendedHeaderLength
);
data
.
readBytes
(
pesScratch
.
data
,
0
,
extendedHeaderLength
);
pesScratch
.
setPosition
(
0
);
pesScratch
.
setPosition
(
0
);
parseHeaderExtension
();
parseHeaderExtension
();
pesPayloadReader
.
packetStarted
(
timeUs
,
true
);
pesPayloadReader
.
packetStarted
(
timeUs
,
TsPayloadReader
.
FLAG_DATA_ALIGNMENT_INDICATOR
);
pesPayloadReader
.
consume
(
data
);
pesPayloadReader
.
consume
(
data
);
// We always have complete PES packets with program stream.
// We always have complete PES packets with program stream.
pesPayloadReader
.
packetFinished
();
pesPayloadReader
.
packetFinished
();
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/SectionReader.java
View file @
71f72c59
...
@@ -57,7 +57,8 @@ public final class SectionReader implements TsPayloadReader {
...
@@ -57,7 +57,8 @@ public final class SectionReader implements TsPayloadReader {
}
}
@Override
@Override
public
void
consume
(
ParsableByteArray
data
,
boolean
payloadUnitStartIndicator
)
{
public
void
consume
(
ParsableByteArray
data
,
@Flags
int
flags
)
{
boolean
payloadUnitStartIndicator
=
(
flags
&
FLAG_PAYLOAD_UNIT_START_INDICATOR
)
!=
0
;
int
payloadStartPosition
=
C
.
POSITION_UNSET
;
int
payloadStartPosition
=
C
.
POSITION_UNSET
;
if
(
payloadUnitStartIndicator
)
{
if
(
payloadUnitStartIndicator
)
{
int
payloadStartOffset
=
data
.
readUnsignedByte
();
int
payloadStartOffset
=
data
.
readUnsignedByte
();
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java
View file @
71f72c59
...
@@ -15,6 +15,8 @@
...
@@ -15,6 +15,8 @@
*/
*/
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
ts
;
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
ts
;
import
static
com
.
google
.
android
.
exoplayer2
.
extractor
.
ts
.
TsPayloadReader
.
FLAG_PAYLOAD_UNIT_START_INDICATOR
;
import
android.support.annotation.IntDef
;
import
android.support.annotation.IntDef
;
import
android.util.SparseArray
;
import
android.util.SparseArray
;
import
android.util.SparseBooleanArray
;
import
android.util.SparseBooleanArray
;
...
@@ -279,6 +281,8 @@ public final class TsExtractor implements Extractor {
...
@@ -279,6 +281,8 @@ public final class TsExtractor implements Extractor {
return
RESULT_CONTINUE
;
return
RESULT_CONTINUE
;
}
}
@TsPayloadReader
.
Flags
int
packetHeaderFlags
=
0
;
// Note: See ISO/IEC 13818-1, section 2.4.3.2 for details of the header format.
// Note: See ISO/IEC 13818-1, section 2.4.3.2 for details of the header format.
int
tsPacketHeader
=
tsPacketBuffer
.
readInt
();
int
tsPacketHeader
=
tsPacketBuffer
.
readInt
();
if
((
tsPacketHeader
&
0x800000
)
!=
0
)
{
// transport_error_indicator
if
((
tsPacketHeader
&
0x800000
)
!=
0
)
{
// transport_error_indicator
...
@@ -286,7 +290,7 @@ public final class TsExtractor implements Extractor {
...
@@ -286,7 +290,7 @@ public final class TsExtractor implements Extractor {
tsPacketBuffer
.
setPosition
(
endOfPacket
);
tsPacketBuffer
.
setPosition
(
endOfPacket
);
return
RESULT_CONTINUE
;
return
RESULT_CONTINUE
;
}
}
boolean
payloadUnitStartIndicator
=
(
tsPacketHeader
&
0x400000
)
!=
0
;
packetHeaderFlags
|=
(
tsPacketHeader
&
0x400000
)
!=
0
?
FLAG_PAYLOAD_UNIT_START_INDICATOR
:
0
;
// Ignoring transport_priority (tsPacketHeader & 0x200000)
// Ignoring transport_priority (tsPacketHeader & 0x200000)
int
pid
=
(
tsPacketHeader
&
0x1FFF00
)
>>
8
;
int
pid
=
(
tsPacketHeader
&
0x1FFF00
)
>>
8
;
// Ignoring transport_scrambling_control (tsPacketHeader & 0xC0)
// Ignoring transport_scrambling_control (tsPacketHeader & 0xC0)
...
@@ -317,14 +321,20 @@ public final class TsExtractor implements Extractor {
...
@@ -317,14 +321,20 @@ public final class TsExtractor implements Extractor {
// Skip the adaptation field.
// Skip the adaptation field.
if
(
adaptationFieldExists
)
{
if
(
adaptationFieldExists
)
{
int
adaptationFieldLength
=
tsPacketBuffer
.
readUnsignedByte
();
int
adaptationFieldLength
=
tsPacketBuffer
.
readUnsignedByte
();
tsPacketBuffer
.
skipBytes
(
adaptationFieldLength
);
int
adaptationFieldFlags
=
tsPacketBuffer
.
readUnsignedByte
();
packetHeaderFlags
|=
(
adaptationFieldFlags
&
0x40
)
!=
0
// random_access_indicator.
?
TsPayloadReader
.
FLAG_RANDOM_ACCESS_INDICATOR
:
0
;
tsPacketBuffer
.
skipBytes
(
adaptationFieldLength
-
1
/* flags */
);
}
}
// Read the payload.
// Read the payload.
boolean
wereTracksEnded
=
tracksEnded
;
boolean
wereTracksEnded
=
tracksEnded
;
if
(
shouldConsumePacketPayload
(
pid
))
{
if
(
shouldConsumePacketPayload
(
pid
))
{
tsPacketBuffer
.
setLimit
(
endOfPacket
);
tsPacketBuffer
.
setLimit
(
endOfPacket
);
payloadReader
.
consume
(
tsPacketBuffer
,
pa
yloadUnitStartIndicator
);
payloadReader
.
consume
(
tsPacketBuffer
,
pa
cketHeaderFlags
);
tsPacketBuffer
.
setLimit
(
limit
);
tsPacketBuffer
.
setLimit
(
limit
);
}
}
if
(
mode
!=
MODE_HLS
&&
!
wereTracksEnded
&&
tracksEnded
&&
inputLength
!=
C
.
LENGTH_UNSET
)
{
if
(
mode
!=
MODE_HLS
&&
!
wereTracksEnded
&&
tracksEnded
&&
inputLength
!=
C
.
LENGTH_UNSET
)
{
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsPayloadReader.java
View file @
71f72c59
...
@@ -15,12 +15,16 @@
...
@@ -15,12 +15,16 @@
*/
*/
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
ts
;
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
ts
;
import
android.support.annotation.IntDef
;
import
android.util.SparseArray
;
import
android.util.SparseArray
;
import
com.google.android.exoplayer2.ParserException
;
import
com.google.android.exoplayer2.ParserException
;
import
com.google.android.exoplayer2.extractor.ExtractorOutput
;
import
com.google.android.exoplayer2.extractor.ExtractorOutput
;
import
com.google.android.exoplayer2.extractor.TrackOutput
;
import
com.google.android.exoplayer2.extractor.TrackOutput
;
import
com.google.android.exoplayer2.util.ParsableByteArray
;
import
com.google.android.exoplayer2.util.ParsableByteArray
;
import
com.google.android.exoplayer2.util.TimestampAdjuster
;
import
com.google.android.exoplayer2.util.TimestampAdjuster
;
import
java.lang.annotation.Documented
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.RetentionPolicy
;
import
java.util.Collections
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.List
;
...
@@ -175,6 +179,29 @@ public interface TsPayloadReader {
...
@@ -175,6 +179,29 @@ public interface TsPayloadReader {
}
}
/**
/**
* Contextual flags indicating the presence of indicators in the TS packet or PES packet headers.
*/
@Documented
@Retention
(
RetentionPolicy
.
SOURCE
)
@IntDef
(
flag
=
true
,
value
=
{
FLAG_PAYLOAD_UNIT_START_INDICATOR
,
FLAG_RANDOM_ACCESS_INDICATOR
,
FLAG_DATA_ALIGNMENT_INDICATOR
})
@interface
Flags
{}
/** Indicates the presence of the payload_unit_start_indicator in the TS packet header. */
int
FLAG_PAYLOAD_UNIT_START_INDICATOR
=
1
;
/**
* Indicates the presence of the random_access_indicator in the TS packet header adaptation field.
*/
int
FLAG_RANDOM_ACCESS_INDICATOR
=
1
<<
1
;
/** Indicates the presence of the data_alignment_indicator in the PES header. */
int
FLAG_DATA_ALIGNMENT_INDICATOR
=
1
<<
2
;
/**
* Initializes the payload reader.
* Initializes the payload reader.
*
*
* @param timestampAdjuster A timestamp adjuster for offsetting and scaling sample timestamps.
* @param timestampAdjuster A timestamp adjuster for offsetting and scaling sample timestamps.
...
@@ -187,10 +214,10 @@ public interface TsPayloadReader {
...
@@ -187,10 +214,10 @@ public interface TsPayloadReader {
/**
/**
* Notifies the reader that a seek has occurred.
* Notifies the reader that a seek has occurred.
*
<p>
*
*
Following a call to this method, the data passed to the next invocation of
*
<p>Following a call to this method, the data passed to the next invocation of {@link #consume}
*
{@link #consume(ParsableByteArray, boolean)} will not be a continuation of the data that was
*
will not be a continuation of the data that was previously passed. Hence the reader should
*
previously passed. Hence the reader should
reset any internal state.
* reset any internal state.
*/
*/
void
seek
();
void
seek
();
...
@@ -198,9 +225,8 @@ public interface TsPayloadReader {
...
@@ -198,9 +225,8 @@ public interface TsPayloadReader {
* Consumes the payload of a TS packet.
* Consumes the payload of a TS packet.
*
*
* @param data The TS packet. The position will be set to the start of the payload.
* @param data The TS packet. The position will be set to the start of the payload.
* @param
payloadUnitStartIndicator Whether payloadUnitStartIndicator was set on the TS packet
.
* @param
flags See {@link Flags}
.
* @throws ParserException If the payload could not be parsed.
* @throws ParserException If the payload could not be parsed.
*/
*/
void
consume
(
ParsableByteArray
data
,
boolean
payloadUnitStartIndicator
)
throws
ParserException
;
void
consume
(
ParsableByteArray
data
,
@Flags
int
flags
)
throws
ParserException
;
}
}
library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecInfo.java
View file @
71f72c59
...
@@ -248,9 +248,15 @@ public final class MediaCodecInfo {
...
@@ -248,9 +248,15 @@ public final class MediaCodecInfo {
// If we don't know any better, we assume that the profile and level are supported.
// If we don't know any better, we assume that the profile and level are supported.
return
true
;
return
true
;
}
}
int
profile
=
codecProfileAndLevel
.
first
;
int
level
=
codecProfileAndLevel
.
second
;
if
(!
isVideo
&&
profile
!=
CodecProfileLevel
.
AACObjectXHE
)
{
// Some devices/builds under-report audio capabilities, so assume support except for xHE-AAC
// which is not widely supported. See https://github.com/google/ExoPlayer/issues/5145.
return
true
;
}
for
(
CodecProfileLevel
capabilities
:
getProfileLevels
())
{
for
(
CodecProfileLevel
capabilities
:
getProfileLevels
())
{
if
(
capabilities
.
profile
==
codecProfileAndLevel
.
first
if
(
capabilities
.
profile
==
profile
&&
capabilities
.
level
>=
level
)
{
&&
capabilities
.
level
>=
codecProfileAndLevel
.
second
)
{
return
true
;
return
true
;
}
}
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java
View file @
71f72c59
...
@@ -1622,7 +1622,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
...
@@ -1622,7 +1622,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
*/
*/
private
static
boolean
codecNeedsEosFlushWorkaround
(
String
name
)
{
private
static
boolean
codecNeedsEosFlushWorkaround
(
String
name
)
{
return
(
Util
.
SDK_INT
<=
23
&&
"OMX.google.vorbis.decoder"
.
equals
(
name
))
return
(
Util
.
SDK_INT
<=
23
&&
"OMX.google.vorbis.decoder"
.
equals
(
name
))
||
(
Util
.
SDK_INT
<=
19
&&
"hb2000"
.
equals
(
Util
.
DEVICE
)
||
(
Util
.
SDK_INT
<=
19
&&
(
"hb2000"
.
equals
(
Util
.
DEVICE
)
||
"stvm8"
.
equals
(
Util
.
DEVICE
))
&&
(
"OMX.amlogic.avc.decoder.awesome"
.
equals
(
name
)
&&
(
"OMX.amlogic.avc.decoder.awesome"
.
equals
(
name
)
||
"OMX.amlogic.avc.decoder.awesome.secure"
.
equals
(
name
)));
||
"OMX.amlogic.avc.decoder.awesome.secure"
.
equals
(
name
)));
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java
View file @
71f72c59
...
@@ -318,7 +318,21 @@ public final class MediaCodecUtil {
...
@@ -318,7 +318,21 @@ public final class MediaCodecUtil {
}
}
// Work around https://github.com/google/ExoPlayer/issues/4519.
// Work around https://github.com/google/ExoPlayer/issues/4519.
if
(
"OMX.SEC.mp3.dec"
.
equals
(
name
)
&&
"SM-T530"
.
equals
(
Util
.
MODEL
))
{
if
(
"OMX.SEC.mp3.dec"
.
equals
(
name
)
&&
(
Util
.
MODEL
.
startsWith
(
"GT-I9152"
)
||
Util
.
MODEL
.
startsWith
(
"GT-I9515"
)
||
Util
.
MODEL
.
startsWith
(
"GT-P5220"
)
||
Util
.
MODEL
.
startsWith
(
"GT-S7580"
)
||
Util
.
MODEL
.
startsWith
(
"SM-G350"
)
||
Util
.
MODEL
.
startsWith
(
"SM-G386"
)
||
Util
.
MODEL
.
startsWith
(
"SM-T231"
)
||
Util
.
MODEL
.
startsWith
(
"SM-T530"
)))
{
return
false
;
}
if
(
"OMX.brcm.audio.mp3.decoder"
.
equals
(
name
)
&&
(
Util
.
MODEL
.
startsWith
(
"GT-I9152"
)
||
Util
.
MODEL
.
startsWith
(
"GT-S7580"
)
||
Util
.
MODEL
.
startsWith
(
"SM-G350"
)))
{
return
false
;
return
false
;
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java
View file @
71f72c59
...
@@ -217,6 +217,12 @@ public final class ClippingMediaSource extends CompositeMediaSource<Void> {
...
@@ -217,6 +217,12 @@ public final class ClippingMediaSource extends CompositeMediaSource<Void> {
}
}
@Override
@Override
@Nullable
public
Object
getTag
()
{
return
mediaSource
.
getTag
();
}
@Override
public
void
prepareSourceInternal
(
public
void
prepareSourceInternal
(
ExoPlayer
player
,
ExoPlayer
player
,
boolean
isTopLevelSource
,
boolean
isTopLevelSource
,
...
...
library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java
View file @
71f72c59
...
@@ -454,6 +454,12 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
...
@@ -454,6 +454,12 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
}
}
@Override
@Override
@Nullable
public
Object
getTag
()
{
return
null
;
}
@Override
public
final
synchronized
void
prepareSourceInternal
(
public
final
synchronized
void
prepareSourceInternal
(
ExoPlayer
player
,
ExoPlayer
player
,
boolean
isTopLevelSource
,
boolean
isTopLevelSource
,
...
@@ -820,7 +826,7 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
...
@@ -820,7 +826,7 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
public
MediaSourceHolder
(
MediaSource
mediaSource
)
{
public
MediaSourceHolder
(
MediaSource
mediaSource
)
{
this
.
mediaSource
=
mediaSource
;
this
.
mediaSource
=
mediaSource
;
this
.
timeline
=
new
DeferredTimeline
(
);
this
.
timeline
=
DeferredTimeline
.
createWithDummyTimeline
(
mediaSource
.
getTag
()
);
this
.
activeMediaPeriods
=
new
ArrayList
<>();
this
.
activeMediaPeriods
=
new
ArrayList
<>();
this
.
uid
=
new
Object
();
this
.
uid
=
new
Object
();
}
}
...
@@ -945,11 +951,19 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
...
@@ -945,11 +951,19 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
private
static
final
class
DeferredTimeline
extends
ForwardingTimeline
{
private
static
final
class
DeferredTimeline
extends
ForwardingTimeline
{
private
static
final
Object
DUMMY_ID
=
new
Object
();
private
static
final
Object
DUMMY_ID
=
new
Object
();
private
static
final
DummyTimeline
DUMMY_TIMELINE
=
new
DummyTimeline
();
private
final
Object
replacedId
;
private
final
Object
replacedId
;
/**
/**
* Returns an instance with a dummy timeline using the provided window tag.
*
* @param windowTag A window tag.
*/
public
static
DeferredTimeline
createWithDummyTimeline
(
@Nullable
Object
windowTag
)
{
return
new
DeferredTimeline
(
new
DummyTimeline
(
windowTag
),
DUMMY_ID
);
}
/**
* Returns an instance with a real timeline, replacing the provided period ID with the already
* Returns an instance with a real timeline, replacing the provided period ID with the already
* assigned dummy period ID.
* assigned dummy period ID.
*
*
...
@@ -962,11 +976,6 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
...
@@ -962,11 +976,6 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
return
new
DeferredTimeline
(
timeline
,
firstPeriodUid
);
return
new
DeferredTimeline
(
timeline
,
firstPeriodUid
);
}
}
/** Creates deferred timeline exposing a {@link DummyTimeline}. */
public
DeferredTimeline
()
{
this
(
DUMMY_TIMELINE
,
DUMMY_ID
);
}
private
DeferredTimeline
(
Timeline
timeline
,
Object
replacedId
)
{
private
DeferredTimeline
(
Timeline
timeline
,
Object
replacedId
)
{
super
(
timeline
);
super
(
timeline
);
this
.
replacedId
=
replacedId
;
this
.
replacedId
=
replacedId
;
...
@@ -1010,6 +1019,12 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
...
@@ -1010,6 +1019,12 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
/** Dummy placeholder timeline with one dynamic window with a period of indeterminate duration. */
/** Dummy placeholder timeline with one dynamic window with a period of indeterminate duration. */
private
static
final
class
DummyTimeline
extends
Timeline
{
private
static
final
class
DummyTimeline
extends
Timeline
{
@Nullable
private
final
Object
tag
;
public
DummyTimeline
(
@Nullable
Object
tag
)
{
this
.
tag
=
tag
;
}
@Override
@Override
public
int
getWindowCount
()
{
public
int
getWindowCount
()
{
return
1
;
return
1
;
...
@@ -1019,7 +1034,7 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
...
@@ -1019,7 +1034,7 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
public
Window
getWindow
(
public
Window
getWindow
(
int
windowIndex
,
Window
window
,
boolean
setTag
,
long
defaultPositionProjectionUs
)
{
int
windowIndex
,
Window
window
,
boolean
setTag
,
long
defaultPositionProjectionUs
)
{
return
window
.
set
(
return
window
.
set
(
/* tag= */
null
,
tag
,
/* presentationStartTimeMs= */
C
.
TIME_UNSET
,
/* presentationStartTimeMs= */
C
.
TIME_UNSET
,
/* windowStartTimeMs= */
C
.
TIME_UNSET
,
/* windowStartTimeMs= */
C
.
TIME_UNSET
,
/* isSeekable= */
false
,
/* isSeekable= */
false
,
...
@@ -1070,6 +1085,12 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
...
@@ -1070,6 +1085,12 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
}
}
@Override
@Override
@Nullable
public
Object
getTag
()
{
return
null
;
}
@Override
protected
void
releaseSourceInternal
()
{
protected
void
releaseSourceInternal
()
{
// Do nothing.
// Do nothing.
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java
View file @
71f72c59
...
@@ -359,6 +359,12 @@ public final class ExtractorMediaSource extends BaseMediaSource
...
@@ -359,6 +359,12 @@ public final class ExtractorMediaSource extends BaseMediaSource
}
}
@Override
@Override
@Nullable
public
Object
getTag
()
{
return
tag
;
}
@Override
public
void
prepareSourceInternal
(
public
void
prepareSourceInternal
(
ExoPlayer
player
,
ExoPlayer
player
,
boolean
isTopLevelSource
,
boolean
isTopLevelSource
,
...
...
library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java
View file @
71f72c59
...
@@ -65,6 +65,12 @@ public final class LoopingMediaSource extends CompositeMediaSource<Void> {
...
@@ -65,6 +65,12 @@ public final class LoopingMediaSource extends CompositeMediaSource<Void> {
}
}
@Override
@Override
@Nullable
public
Object
getTag
()
{
return
childSource
.
getTag
();
}
@Override
public
void
prepareSourceInternal
(
public
void
prepareSourceInternal
(
ExoPlayer
player
,
ExoPlayer
player
,
boolean
isTopLevelSource
,
boolean
isTopLevelSource
,
...
...
library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java
View file @
71f72c59
...
@@ -220,6 +220,12 @@ public interface MediaSource {
...
@@ -220,6 +220,12 @@ public interface MediaSource {
*/
*/
void
removeEventListener
(
MediaSourceEventListener
eventListener
);
void
removeEventListener
(
MediaSourceEventListener
eventListener
);
/** Returns the tag set on the media source, or null if none was set. */
@Nullable
default
Object
getTag
()
{
return
null
;
}
/** @deprecated Will be removed in the next release. */
/** @deprecated Will be removed in the next release. */
@Deprecated
@Deprecated
void
prepareSource
(
void
prepareSource
(
...
...
library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaSource.java
View file @
71f72c59
...
@@ -99,6 +99,12 @@ public final class MergingMediaSource extends CompositeMediaSource<Integer> {
...
@@ -99,6 +99,12 @@ public final class MergingMediaSource extends CompositeMediaSource<Integer> {
}
}
@Override
@Override
@Nullable
public
Object
getTag
()
{
return
mediaSources
.
length
>
0
?
mediaSources
[
0
].
getTag
()
:
null
;
}
@Override
public
void
prepareSourceInternal
(
public
void
prepareSourceInternal
(
ExoPlayer
player
,
ExoPlayer
player
,
boolean
isTopLevelSource
,
boolean
isTopLevelSource
,
...
...
library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java
View file @
71f72c59
...
@@ -185,6 +185,7 @@ public final class SingleSampleMediaSource extends BaseMediaSource {
...
@@ -185,6 +185,7 @@ public final class SingleSampleMediaSource extends BaseMediaSource {
private
final
LoadErrorHandlingPolicy
loadErrorHandlingPolicy
;
private
final
LoadErrorHandlingPolicy
loadErrorHandlingPolicy
;
private
final
boolean
treatLoadErrorsAsEndOfStream
;
private
final
boolean
treatLoadErrorsAsEndOfStream
;
private
final
Timeline
timeline
;
private
final
Timeline
timeline
;
@Nullable
private
final
Object
tag
;
private
@Nullable
TransferListener
transferListener
;
private
@Nullable
TransferListener
transferListener
;
...
@@ -287,6 +288,7 @@ public final class SingleSampleMediaSource extends BaseMediaSource {
...
@@ -287,6 +288,7 @@ public final class SingleSampleMediaSource extends BaseMediaSource {
this
.
durationUs
=
durationUs
;
this
.
durationUs
=
durationUs
;
this
.
loadErrorHandlingPolicy
=
loadErrorHandlingPolicy
;
this
.
loadErrorHandlingPolicy
=
loadErrorHandlingPolicy
;
this
.
treatLoadErrorsAsEndOfStream
=
treatLoadErrorsAsEndOfStream
;
this
.
treatLoadErrorsAsEndOfStream
=
treatLoadErrorsAsEndOfStream
;
this
.
tag
=
tag
;
dataSpec
=
dataSpec
=
new
DataSpec
(
uri
,
DataSpec
.
FLAG_ALLOW_GZIP
|
DataSpec
.
FLAG_ALLOW_CACHING_UNKNOWN_LENGTH
);
new
DataSpec
(
uri
,
DataSpec
.
FLAG_ALLOW_GZIP
|
DataSpec
.
FLAG_ALLOW_CACHING_UNKNOWN_LENGTH
);
timeline
=
timeline
=
...
@@ -296,6 +298,12 @@ public final class SingleSampleMediaSource extends BaseMediaSource {
...
@@ -296,6 +298,12 @@ public final class SingleSampleMediaSource extends BaseMediaSource {
// MediaSource implementation.
// MediaSource implementation.
@Override
@Override
@Nullable
public
Object
getTag
()
{
return
tag
;
}
@Override
public
void
prepareSourceInternal
(
public
void
prepareSourceInternal
(
ExoPlayer
player
,
ExoPlayer
player
,
boolean
isTopLevelSource
,
boolean
isTopLevelSource
,
...
...
library/core/src/main/java/com/google/android/exoplayer2/source/ads/AdsMediaSource.java
View file @
71f72c59
...
@@ -320,6 +320,12 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
...
@@ -320,6 +320,12 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
}
}
@Override
@Override
@Nullable
public
Object
getTag
()
{
return
contentMediaSource
.
getTag
();
}
@Override
public
void
prepareSourceInternal
(
public
void
prepareSourceInternal
(
final
ExoPlayer
player
,
final
ExoPlayer
player
,
boolean
isTopLevelSource
,
boolean
isTopLevelSource
,
...
...
library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlDecoder.java
View file @
71f72c59
This diff is collapsed.
Click to expand it.
library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlNode.java
View file @
71f72c59
...
@@ -15,7 +15,12 @@
...
@@ -15,7 +15,12 @@
*/
*/
package
com
.
google
.
android
.
exoplayer2
.
text
.
ttml
;
package
com
.
google
.
android
.
exoplayer2
.
text
.
ttml
;
import
android.graphics.Bitmap
;
import
android.graphics.BitmapFactory
;
import
android.support.annotation.Nullable
;
import
android.text.SpannableStringBuilder
;
import
android.text.SpannableStringBuilder
;
import
android.util.Base64
;
import
android.util.Pair
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.text.Cue
;
import
com.google.android.exoplayer2.text.Cue
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.Assertions
;
...
@@ -44,9 +49,9 @@ import java.util.TreeSet;
...
@@ -44,9 +49,9 @@ import java.util.TreeSet;
public
static
final
String
TAG_LAYOUT
=
"layout"
;
public
static
final
String
TAG_LAYOUT
=
"layout"
;
public
static
final
String
TAG_REGION
=
"region"
;
public
static
final
String
TAG_REGION
=
"region"
;
public
static
final
String
TAG_METADATA
=
"metadata"
;
public
static
final
String
TAG_METADATA
=
"metadata"
;
public
static
final
String
TAG_
SMPTE_IMAGE
=
"smpte:
image"
;
public
static
final
String
TAG_
IMAGE
=
"
image"
;
public
static
final
String
TAG_
SMPTE_DATA
=
"smpte:
data"
;
public
static
final
String
TAG_
DATA
=
"
data"
;
public
static
final
String
TAG_
SMPTE_INFORMATION
=
"smpte:
information"
;
public
static
final
String
TAG_
INFORMATION
=
"
information"
;
public
static
final
String
ANONYMOUS_REGION_ID
=
""
;
public
static
final
String
ANONYMOUS_REGION_ID
=
""
;
public
static
final
String
ATTR_ID
=
"id"
;
public
static
final
String
ATTR_ID
=
"id"
;
...
@@ -75,34 +80,57 @@ import java.util.TreeSet;
...
@@ -75,34 +80,57 @@ import java.util.TreeSet;
public
static
final
String
START
=
"start"
;
public
static
final
String
START
=
"start"
;
public
static
final
String
END
=
"end"
;
public
static
final
String
END
=
"end"
;
public
final
String
tag
;
@Nullable
public
final
String
tag
;
public
final
String
text
;
@Nullable
public
final
String
text
;
public
final
boolean
isTextNode
;
public
final
boolean
isTextNode
;
public
final
long
startTimeUs
;
public
final
long
startTimeUs
;
public
final
long
endTimeUs
;
public
final
long
endTimeUs
;
public
final
TtmlStyle
style
;
@Nullable
public
final
TtmlStyle
style
;
@Nullable
private
final
String
[]
styleIds
;
public
final
String
regionId
;
public
final
String
regionId
;
@Nullable
public
final
String
imageId
;
private
final
String
[]
styleIds
;
private
final
HashMap
<
String
,
Integer
>
nodeStartsByRegion
;
private
final
HashMap
<
String
,
Integer
>
nodeStartsByRegion
;
private
final
HashMap
<
String
,
Integer
>
nodeEndsByRegion
;
private
final
HashMap
<
String
,
Integer
>
nodeEndsByRegion
;
private
List
<
TtmlNode
>
children
;
private
List
<
TtmlNode
>
children
;
public
static
TtmlNode
buildTextNode
(
String
text
)
{
public
static
TtmlNode
buildTextNode
(
String
text
)
{
return
new
TtmlNode
(
null
,
TtmlRenderUtil
.
applyTextElementSpacePolicy
(
text
),
C
.
TIME_UNSET
,
return
new
TtmlNode
(
C
.
TIME_UNSET
,
null
,
null
,
ANONYMOUS_REGION_ID
);
/* tag= */
null
,
TtmlRenderUtil
.
applyTextElementSpacePolicy
(
text
),
/* startTimeUs= */
C
.
TIME_UNSET
,
/* endTimeUs= */
C
.
TIME_UNSET
,
/* style= */
null
,
/* styleIds= */
null
,
ANONYMOUS_REGION_ID
,
/* imageId= */
null
);
}
}
public
static
TtmlNode
buildNode
(
String
tag
,
long
startTimeUs
,
long
endTimeUs
,
public
static
TtmlNode
buildNode
(
TtmlStyle
style
,
String
[]
styleIds
,
String
regionId
)
{
@Nullable
String
tag
,
return
new
TtmlNode
(
tag
,
null
,
startTimeUs
,
endTimeUs
,
style
,
styleIds
,
regionId
);
long
startTimeUs
,
long
endTimeUs
,
@Nullable
TtmlStyle
style
,
@Nullable
String
[]
styleIds
,
String
regionId
,
@Nullable
String
imageId
)
{
return
new
TtmlNode
(
tag
,
/* text= */
null
,
startTimeUs
,
endTimeUs
,
style
,
styleIds
,
regionId
,
imageId
);
}
}
private
TtmlNode
(
String
tag
,
String
text
,
long
startTimeUs
,
long
endTimeUs
,
private
TtmlNode
(
TtmlStyle
style
,
String
[]
styleIds
,
String
regionId
)
{
@Nullable
String
tag
,
@Nullable
String
text
,
long
startTimeUs
,
long
endTimeUs
,
@Nullable
TtmlStyle
style
,
@Nullable
String
[]
styleIds
,
String
regionId
,
@Nullable
String
imageId
)
{
this
.
tag
=
tag
;
this
.
tag
=
tag
;
this
.
text
=
text
;
this
.
text
=
text
;
this
.
imageId
=
imageId
;
this
.
style
=
style
;
this
.
style
=
style
;
this
.
styleIds
=
styleIds
;
this
.
styleIds
=
styleIds
;
this
.
isTextNode
=
text
!=
null
;
this
.
isTextNode
=
text
!=
null
;
...
@@ -151,7 +179,8 @@ import java.util.TreeSet;
...
@@ -151,7 +179,8 @@ import java.util.TreeSet;
private
void
getEventTimes
(
TreeSet
<
Long
>
out
,
boolean
descendsPNode
)
{
private
void
getEventTimes
(
TreeSet
<
Long
>
out
,
boolean
descendsPNode
)
{
boolean
isPNode
=
TAG_P
.
equals
(
tag
);
boolean
isPNode
=
TAG_P
.
equals
(
tag
);
if
(
descendsPNode
||
isPNode
)
{
boolean
isDivNode
=
TAG_DIV
.
equals
(
tag
);
if
(
descendsPNode
||
isPNode
||
(
isDivNode
&&
imageId
!=
null
))
{
if
(
startTimeUs
!=
C
.
TIME_UNSET
)
{
if
(
startTimeUs
!=
C
.
TIME_UNSET
)
{
out
.
add
(
startTimeUs
);
out
.
add
(
startTimeUs
);
}
}
...
@@ -171,13 +200,46 @@ import java.util.TreeSet;
...
@@ -171,13 +200,46 @@ import java.util.TreeSet;
return
styleIds
;
return
styleIds
;
}
}
public
List
<
Cue
>
getCues
(
long
timeUs
,
Map
<
String
,
TtmlStyle
>
globalStyles
,
public
List
<
Cue
>
getCues
(
Map
<
String
,
TtmlRegion
>
regionMap
)
{
long
timeUs
,
TreeMap
<
String
,
SpannableStringBuilder
>
regionOutputs
=
new
TreeMap
<>();
Map
<
String
,
TtmlStyle
>
globalStyles
,
traverseForText
(
timeUs
,
false
,
regionId
,
regionOutputs
);
Map
<
String
,
TtmlRegion
>
regionMap
,
traverseForStyle
(
timeUs
,
globalStyles
,
regionOutputs
);
Map
<
String
,
String
>
imageMap
)
{
List
<
Pair
<
String
,
String
>>
regionImageOutputs
=
new
ArrayList
<>();
traverseForImage
(
timeUs
,
regionId
,
regionImageOutputs
);
TreeMap
<
String
,
SpannableStringBuilder
>
regionTextOutputs
=
new
TreeMap
<>();
traverseForText
(
timeUs
,
false
,
regionId
,
regionTextOutputs
);
traverseForStyle
(
timeUs
,
globalStyles
,
regionTextOutputs
);
List
<
Cue
>
cues
=
new
ArrayList
<>();
List
<
Cue
>
cues
=
new
ArrayList
<>();
for
(
Entry
<
String
,
SpannableStringBuilder
>
entry
:
regionOutputs
.
entrySet
())
{
// Create image based cues.
for
(
Pair
<
String
,
String
>
regionImagePair
:
regionImageOutputs
)
{
String
encodedBitmapData
=
imageMap
.
get
(
regionImagePair
.
second
);
if
(
encodedBitmapData
==
null
)
{
// Image reference points to an invalid image. Do nothing.
continue
;
}
byte
[]
bitmapData
=
Base64
.
decode
(
encodedBitmapData
,
Base64
.
DEFAULT
);
Bitmap
bitmap
=
BitmapFactory
.
decodeByteArray
(
bitmapData
,
/* offset= */
0
,
bitmapData
.
length
);
TtmlRegion
region
=
regionMap
.
get
(
regionImagePair
.
first
);
cues
.
add
(
new
Cue
(
bitmap
,
region
.
position
,
Cue
.
ANCHOR_TYPE_MIDDLE
,
region
.
line
,
region
.
lineAnchor
,
region
.
width
,
/* height= */
Cue
.
DIMEN_UNSET
));
}
// Create text based cues.
for
(
Entry
<
String
,
SpannableStringBuilder
>
entry
:
regionTextOutputs
.
entrySet
())
{
TtmlRegion
region
=
regionMap
.
get
(
entry
.
getKey
());
TtmlRegion
region
=
regionMap
.
get
(
entry
.
getKey
());
cues
.
add
(
cues
.
add
(
new
Cue
(
new
Cue
(
...
@@ -192,9 +254,22 @@ import java.util.TreeSet;
...
@@ -192,9 +254,22 @@ import java.util.TreeSet;
region
.
textSizeType
,
region
.
textSizeType
,
region
.
textSize
));
region
.
textSize
));
}
}
return
cues
;
return
cues
;
}
}
private
void
traverseForImage
(
long
timeUs
,
String
inheritedRegion
,
List
<
Pair
<
String
,
String
>>
regionImageList
)
{
String
resolvedRegionId
=
ANONYMOUS_REGION_ID
.
equals
(
regionId
)
?
inheritedRegion
:
regionId
;
if
(
isActive
(
timeUs
)
&&
TAG_DIV
.
equals
(
tag
)
&&
imageId
!=
null
)
{
regionImageList
.
add
(
new
Pair
<>(
resolvedRegionId
,
imageId
));
return
;
}
for
(
int
i
=
0
;
i
<
getChildCount
();
++
i
)
{
getChild
(
i
).
traverseForImage
(
timeUs
,
resolvedRegionId
,
regionImageList
);
}
}
private
void
traverseForText
(
private
void
traverseForText
(
long
timeUs
,
long
timeUs
,
boolean
descendsPNode
,
boolean
descendsPNode
,
...
...
library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlSubtitle.java
View file @
71f72c59
...
@@ -32,11 +32,16 @@ import java.util.Map;
...
@@ -32,11 +32,16 @@ import java.util.Map;
private
final
long
[]
eventTimesUs
;
private
final
long
[]
eventTimesUs
;
private
final
Map
<
String
,
TtmlStyle
>
globalStyles
;
private
final
Map
<
String
,
TtmlStyle
>
globalStyles
;
private
final
Map
<
String
,
TtmlRegion
>
regionMap
;
private
final
Map
<
String
,
TtmlRegion
>
regionMap
;
private
final
Map
<
String
,
String
>
imageMap
;
public
TtmlSubtitle
(
TtmlNode
root
,
Map
<
String
,
TtmlStyle
>
globalStyles
,
public
TtmlSubtitle
(
Map
<
String
,
TtmlRegion
>
regionMap
)
{
TtmlNode
root
,
Map
<
String
,
TtmlStyle
>
globalStyles
,
Map
<
String
,
TtmlRegion
>
regionMap
,
Map
<
String
,
String
>
imageMap
)
{
this
.
root
=
root
;
this
.
root
=
root
;
this
.
regionMap
=
regionMap
;
this
.
regionMap
=
regionMap
;
this
.
imageMap
=
imageMap
;
this
.
globalStyles
=
this
.
globalStyles
=
globalStyles
!=
null
?
Collections
.
unmodifiableMap
(
globalStyles
)
:
Collections
.
emptyMap
();
globalStyles
!=
null
?
Collections
.
unmodifiableMap
(
globalStyles
)
:
Collections
.
emptyMap
();
this
.
eventTimesUs
=
root
.
getEventTimesUs
();
this
.
eventTimesUs
=
root
.
getEventTimesUs
();
...
@@ -65,7 +70,7 @@ import java.util.Map;
...
@@ -65,7 +70,7 @@ import java.util.Map;
@Override
@Override
public
List
<
Cue
>
getCues
(
long
timeUs
)
{
public
List
<
Cue
>
getCues
(
long
timeUs
)
{
return
root
.
getCues
(
timeUs
,
globalStyles
,
regionMap
);
return
root
.
getCues
(
timeUs
,
globalStyles
,
regionMap
,
imageMap
);
}
}
/* @VisibleForTesting */
/* @VisibleForTesting */
...
...
library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/Cache.java
View file @
71f72c59
...
@@ -82,7 +82,7 @@ public interface Cache {
...
@@ -82,7 +82,7 @@ public interface Cache {
* Releases the cache. This method must be called when the cache is no longer required. The cache
* Releases the cache. This method must be called when the cache is no longer required. The cache
* must not be used after calling this method.
* must not be used after calling this method.
*/
*/
void
release
()
throws
CacheException
;
void
release
();
/**
/**
* Registers a listener to listen for changes to a given key.
* Registers a listener to listen for changes to a given key.
...
...
library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CachedContentIndex.java
View file @
71f72c59
...
@@ -16,6 +16,7 @@
...
@@ -16,6 +16,7 @@
package
com
.
google
.
android
.
exoplayer2
.
upstream
.
cache
;
package
com
.
google
.
android
.
exoplayer2
.
upstream
.
cache
;
import
android.util.SparseArray
;
import
android.util.SparseArray
;
import
android.util.SparseBooleanArray
;
import
com.google.android.exoplayer2.upstream.cache.Cache.CacheException
;
import
com.google.android.exoplayer2.upstream.cache.Cache.CacheException
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.AtomicFile
;
import
com.google.android.exoplayer2.util.AtomicFile
;
...
@@ -41,6 +42,7 @@ import javax.crypto.CipherOutputStream;
...
@@ -41,6 +42,7 @@ import javax.crypto.CipherOutputStream;
import
javax.crypto.NoSuchPaddingException
;
import
javax.crypto.NoSuchPaddingException
;
import
javax.crypto.spec.IvParameterSpec
;
import
javax.crypto.spec.IvParameterSpec
;
import
javax.crypto.spec.SecretKeySpec
;
import
javax.crypto.spec.SecretKeySpec
;
import
org.checkerframework.checker.nullness.compatqual.NullableType
;
/** Maintains the index of cached content. */
/** Maintains the index of cached content. */
/*package*/
class
CachedContentIndex
{
/*package*/
class
CachedContentIndex
{
...
@@ -52,7 +54,30 @@ import javax.crypto.spec.SecretKeySpec;
...
@@ -52,7 +54,30 @@ import javax.crypto.spec.SecretKeySpec;
private
static
final
int
FLAG_ENCRYPTED_INDEX
=
1
;
private
static
final
int
FLAG_ENCRYPTED_INDEX
=
1
;
private
final
HashMap
<
String
,
CachedContent
>
keyToContent
;
private
final
HashMap
<
String
,
CachedContent
>
keyToContent
;
private
final
SparseArray
<
String
>
idToKey
;
/**
* Maps assigned ids to their corresponding keys. Also contains (id -> null) entries for ids that
* have been removed from the index since it was last stored. This prevents reuse of these ids,
* which is necessary to avoid clashes that could otherwise occur as a result of the sequence:
*
* <p>[1] (key1, id1) is removed from the in-memory index ... the index is not stored to disk ...
* [2] id1 is reused for a different key2 ... the index is not stored to disk ... [3] A file for
* key2 is partially written using a path corresponding to id1 ... the process is killed before
* the index is stored to disk ... [4] The index is read from disk, causing the partially written
* file to be incorrectly associated to key1
*
* <p>By avoiding id reuse in step [2], a new id2 will be used instead. Step [4] will then delete
* the partially written file because the index does not contain an entry for id2.
*
* <p>When the index is next stored (id -> null) entries are removed, making the ids eligible for
* reuse.
*/
private
final
SparseArray
<
@NullableType
String
>
idToKey
;
/**
* Tracks ids for which (id -> null) entries are present in idToKey, so that they can be removed
* efficiently when the index is next stored.
*/
private
final
SparseBooleanArray
removedIds
;
private
final
AtomicFile
atomicFile
;
private
final
AtomicFile
atomicFile
;
private
final
Cipher
cipher
;
private
final
Cipher
cipher
;
private
final
SecretKeySpec
secretKeySpec
;
private
final
SecretKeySpec
secretKeySpec
;
...
@@ -104,6 +129,7 @@ import javax.crypto.spec.SecretKeySpec;
...
@@ -104,6 +129,7 @@ import javax.crypto.spec.SecretKeySpec;
}
}
keyToContent
=
new
HashMap
<>();
keyToContent
=
new
HashMap
<>();
idToKey
=
new
SparseArray
<>();
idToKey
=
new
SparseArray
<>();
removedIds
=
new
SparseBooleanArray
();
atomicFile
=
new
AtomicFile
(
new
File
(
cacheDir
,
FILE_NAME
));
atomicFile
=
new
AtomicFile
(
new
File
(
cacheDir
,
FILE_NAME
));
}
}
...
@@ -124,6 +150,12 @@ import javax.crypto.spec.SecretKeySpec;
...
@@ -124,6 +150,12 @@ import javax.crypto.spec.SecretKeySpec;
}
}
writeFile
();
writeFile
();
changed
=
false
;
changed
=
false
;
// Make ids that were removed since the index was last stored eligible for re-use.
int
removedIdCount
=
removedIds
.
size
();
for
(
int
i
=
0
;
i
<
removedIdCount
;
i
++)
{
idToKey
.
remove
(
removedIds
.
keyAt
(
i
));
}
removedIds
.
clear
();
}
}
/**
/**
...
@@ -168,8 +200,11 @@ import javax.crypto.spec.SecretKeySpec;
...
@@ -168,8 +200,11 @@ import javax.crypto.spec.SecretKeySpec;
CachedContent
cachedContent
=
keyToContent
.
get
(
key
);
CachedContent
cachedContent
=
keyToContent
.
get
(
key
);
if
(
cachedContent
!=
null
&&
cachedContent
.
isEmpty
()
&&
!
cachedContent
.
isLocked
())
{
if
(
cachedContent
!=
null
&&
cachedContent
.
isEmpty
()
&&
!
cachedContent
.
isLocked
())
{
keyToContent
.
remove
(
key
);
keyToContent
.
remove
(
key
);
idToKey
.
remove
(
cachedContent
.
id
);
changed
=
true
;
changed
=
true
;
// Keep an entry in idToKey to stop the id from being reused until the index is next stored.
idToKey
.
put
(
cachedContent
.
id
,
/* value= */
null
);
// Track that the entry should be removed from idToKey when the index is next stored.
removedIds
.
put
(
cachedContent
.
id
,
/* value= */
true
);
}
}
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/SimpleCache.java
View file @
71f72c59
...
@@ -146,13 +146,16 @@ public final class SimpleCache implements Cache {
...
@@ -146,13 +146,16 @@ public final class SimpleCache implements Cache {
}
}
@Override
@Override
public
synchronized
void
release
()
throws
CacheException
{
public
synchronized
void
release
()
{
if
(
released
)
{
if
(
released
)
{
return
;
return
;
}
}
listeners
.
clear
();
listeners
.
clear
();
removeStaleSpans
();
try
{
try
{
removeStaleSpansAndCachedContents
();
index
.
store
();
}
catch
(
CacheException
e
)
{
Log
.
e
(
TAG
,
"Storing index file failed"
,
e
);
}
finally
{
}
finally
{
unlockFolder
(
cacheDir
);
unlockFolder
(
cacheDir
);
released
=
true
;
released
=
true
;
...
@@ -265,7 +268,7 @@ public final class SimpleCache implements Cache {
...
@@ -265,7 +268,7 @@ public final class SimpleCache implements Cache {
if
(!
cacheDir
.
exists
())
{
if
(!
cacheDir
.
exists
())
{
// For some reason the cache directory doesn't exist. Make a best effort to create it.
// For some reason the cache directory doesn't exist. Make a best effort to create it.
cacheDir
.
mkdirs
();
cacheDir
.
mkdirs
();
removeStaleSpans
AndCachedContents
();
removeStaleSpans
();
}
}
evictor
.
onStartFile
(
this
,
key
,
position
,
maxLength
);
evictor
.
onStartFile
(
this
,
key
,
position
,
maxLength
);
return
SimpleCacheSpan
.
getCacheFile
(
return
SimpleCacheSpan
.
getCacheFile
(
...
@@ -311,9 +314,9 @@ public final class SimpleCache implements Cache {
...
@@ -311,9 +314,9 @@ public final class SimpleCache implements Cache {
}
}
@Override
@Override
public
synchronized
void
removeSpan
(
CacheSpan
span
)
throws
CacheException
{
public
synchronized
void
removeSpan
(
CacheSpan
span
)
{
Assertions
.
checkState
(!
released
);
Assertions
.
checkState
(!
released
);
removeSpan
(
span
,
true
);
removeSpan
Internal
(
span
);
}
}
@Override
@Override
...
@@ -379,7 +382,7 @@ public final class SimpleCache implements Cache {
...
@@ -379,7 +382,7 @@ public final class SimpleCache implements Cache {
if
(
span
.
isCached
&&
!
span
.
file
.
exists
())
{
if
(
span
.
isCached
&&
!
span
.
file
.
exists
())
{
// The file has been deleted from under us. It's likely that other files will have been
// The file has been deleted from under us. It's likely that other files will have been
// deleted too, so scan the whole in-memory representation.
// deleted too, so scan the whole in-memory representation.
removeStaleSpans
AndCachedContents
();
removeStaleSpans
();
continue
;
continue
;
}
}
return
span
;
return
span
;
...
@@ -431,27 +434,21 @@ public final class SimpleCache implements Cache {
...
@@ -431,27 +434,21 @@ public final class SimpleCache implements Cache {
notifySpanAdded
(
span
);
notifySpanAdded
(
span
);
}
}
private
void
removeSpan
(
CacheSpan
span
,
boolean
removeEmptyCachedContent
)
throws
CacheException
{
private
void
removeSpan
Internal
(
CacheSpan
span
)
{
CachedContent
cachedContent
=
index
.
get
(
span
.
key
);
CachedContent
cachedContent
=
index
.
get
(
span
.
key
);
if
(
cachedContent
==
null
||
!
cachedContent
.
removeSpan
(
span
))
{
if
(
cachedContent
==
null
||
!
cachedContent
.
removeSpan
(
span
))
{
return
;
return
;
}
}
totalSpace
-=
span
.
length
;
totalSpace
-=
span
.
length
;
try
{
if
(
removeEmptyCachedContent
)
{
index
.
maybeRemove
(
cachedContent
.
key
);
index
.
maybeRemove
(
cachedContent
.
key
);
index
.
store
();
}
}
finally
{
notifySpanRemoved
(
span
);
notifySpanRemoved
(
span
);
}
}
}
/**
/**
* Scans all of the cached spans in the in-memory representation, removing any for which files no
* Scans all of the cached spans in the in-memory representation, removing any for which files no
* longer exist.
* longer exist.
*/
*/
private
void
removeStaleSpans
AndCachedContents
()
throws
CacheException
{
private
void
removeStaleSpans
()
{
ArrayList
<
CacheSpan
>
spansToBeRemoved
=
new
ArrayList
<>();
ArrayList
<
CacheSpan
>
spansToBeRemoved
=
new
ArrayList
<>();
for
(
CachedContent
cachedContent
:
index
.
getAll
())
{
for
(
CachedContent
cachedContent
:
index
.
getAll
())
{
for
(
CacheSpan
span
:
cachedContent
.
getSpans
())
{
for
(
CacheSpan
span
:
cachedContent
.
getSpans
())
{
...
@@ -461,11 +458,8 @@ public final class SimpleCache implements Cache {
...
@@ -461,11 +458,8 @@ public final class SimpleCache implements Cache {
}
}
}
}
for
(
int
i
=
0
;
i
<
spansToBeRemoved
.
size
();
i
++)
{
for
(
int
i
=
0
;
i
<
spansToBeRemoved
.
size
();
i
++)
{
// Remove span but not CachedContent to prevent multiple index.store() calls.
removeSpanInternal
(
spansToBeRemoved
.
get
(
i
));
removeSpan
(
spansToBeRemoved
.
get
(
i
),
false
);
}
}
index
.
removeEmpty
();
index
.
store
();
}
}
private
void
notifySpanRemoved
(
CacheSpan
span
)
{
private
void
notifySpanRemoved
(
CacheSpan
span
)
{
...
...
library/core/src/main/java/com/google/android/exoplayer2/util/Util.java
View file @
71f72c59
...
@@ -1436,11 +1436,12 @@ public final class Util {
...
@@ -1436,11 +1436,12 @@ public final class Util {
}
}
/**
/**
* Maps a {@link C} {@code TRACK_TYPE_*} constant to the corresponding {@link C}
* Maps a {@link C} {@code TRACK_TYPE_*} constant to the corresponding {@link C}
{@code
*
{@code
DEFAULT_*_BUFFER_SIZE} constant.
* DEFAULT_*_BUFFER_SIZE} constant.
*
*
* @param trackType The track type.
* @param trackType The track type.
* @return The corresponding default buffer size in bytes.
* @return The corresponding default buffer size in bytes.
* @throws IllegalArgumentException If the track type is an unrecognized or custom track type.
*/
*/
public
static
int
getDefaultBufferSize
(
int
trackType
)
{
public
static
int
getDefaultBufferSize
(
int
trackType
)
{
switch
(
trackType
)
{
switch
(
trackType
)
{
...
@@ -1456,8 +1457,10 @@ public final class Util {
...
@@ -1456,8 +1457,10 @@ public final class Util {
return
C
.
DEFAULT_METADATA_BUFFER_SIZE
;
return
C
.
DEFAULT_METADATA_BUFFER_SIZE
;
case
C
.
TRACK_TYPE_CAMERA_MOTION
:
case
C
.
TRACK_TYPE_CAMERA_MOTION
:
return
C
.
DEFAULT_CAMERA_MOTION_BUFFER_SIZE
;
return
C
.
DEFAULT_CAMERA_MOTION_BUFFER_SIZE
;
case
C
.
TRACK_TYPE_NONE
:
return
0
;
default
:
default
:
throw
new
Illegal
State
Exception
();
throw
new
Illegal
Argument
Exception
();
}
}
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java
View file @
71f72c59
...
@@ -98,7 +98,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
...
@@ -98,7 +98,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
private
final
EventDispatcher
eventDispatcher
;
private
final
EventDispatcher
eventDispatcher
;
private
final
long
allowedJoiningTimeMs
;
private
final
long
allowedJoiningTimeMs
;
private
final
int
maxDroppedFramesToNotify
;
private
final
int
maxDroppedFramesToNotify
;
private
final
boolean
deviceNeeds
AutoFrc
Workaround
;
private
final
boolean
deviceNeeds
NoPostProcess
Workaround
;
private
final
long
[]
pendingOutputStreamOffsetsUs
;
private
final
long
[]
pendingOutputStreamOffsetsUs
;
private
final
long
[]
pendingOutputStreamSwitchTimesUs
;
private
final
long
[]
pendingOutputStreamSwitchTimesUs
;
...
@@ -226,7 +226,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
...
@@ -226,7 +226,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
this
.
context
=
context
.
getApplicationContext
();
this
.
context
=
context
.
getApplicationContext
();
frameReleaseTimeHelper
=
new
VideoFrameReleaseTimeHelper
(
this
.
context
);
frameReleaseTimeHelper
=
new
VideoFrameReleaseTimeHelper
(
this
.
context
);
eventDispatcher
=
new
EventDispatcher
(
eventHandler
,
eventListener
);
eventDispatcher
=
new
EventDispatcher
(
eventHandler
,
eventListener
);
deviceNeeds
AutoFrcWorkaround
=
deviceNeedsAutoFrc
Workaround
();
deviceNeeds
NoPostProcessWorkaround
=
deviceNeedsNoPostProcess
Workaround
();
pendingOutputStreamOffsetsUs
=
new
long
[
MAX_PENDING_OUTPUT_STREAM_OFFSET_COUNT
];
pendingOutputStreamOffsetsUs
=
new
long
[
MAX_PENDING_OUTPUT_STREAM_OFFSET_COUNT
];
pendingOutputStreamSwitchTimesUs
=
new
long
[
MAX_PENDING_OUTPUT_STREAM_OFFSET_COUNT
];
pendingOutputStreamSwitchTimesUs
=
new
long
[
MAX_PENDING_OUTPUT_STREAM_OFFSET_COUNT
];
outputStreamOffsetUs
=
C
.
TIME_UNSET
;
outputStreamOffsetUs
=
C
.
TIME_UNSET
;
...
@@ -471,7 +471,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
...
@@ -471,7 +471,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
format
,
format
,
codecMaxValues
,
codecMaxValues
,
codecOperatingRate
,
codecOperatingRate
,
deviceNeeds
AutoFrc
Workaround
,
deviceNeeds
NoPostProcess
Workaround
,
tunnelingAudioSessionId
);
tunnelingAudioSessionId
);
if
(
surface
==
null
)
{
if
(
surface
==
null
)
{
Assertions
.
checkState
(
shouldUseDummySurface
(
codecInfo
));
Assertions
.
checkState
(
shouldUseDummySurface
(
codecInfo
));
...
@@ -1027,8 +1027,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
...
@@ -1027,8 +1027,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
* @param codecMaxValues Codec max values that should be used when configuring the decoder.
* @param codecMaxValues Codec max values that should be used when configuring the decoder.
* @param codecOperatingRate The codec operating rate, or {@link #CODEC_OPERATING_RATE_UNSET} if
* @param codecOperatingRate The codec operating rate, or {@link #CODEC_OPERATING_RATE_UNSET} if
* no codec operating rate should be set.
* no codec operating rate should be set.
* @param deviceNeeds
AutoFrcWorkaround Whether the device is known to enable frame-rate conversion
* @param deviceNeeds
NoPostProcessWorkaround Whether the device is known to do post processing by
*
logic that negatively impacts
ExoPlayer.
*
default that isn't compatible with
ExoPlayer.
* @param tunnelingAudioSessionId The audio session id to use for tunneling, or {@link
* @param tunnelingAudioSessionId The audio session id to use for tunneling, or {@link
* C#AUDIO_SESSION_ID_UNSET} if tunneling should not be enabled.
* C#AUDIO_SESSION_ID_UNSET} if tunneling should not be enabled.
* @return The framework {@link MediaFormat} that should be used to configure the decoder.
* @return The framework {@link MediaFormat} that should be used to configure the decoder.
...
@@ -1038,7 +1038,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
...
@@ -1038,7 +1038,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
Format
format
,
Format
format
,
CodecMaxValues
codecMaxValues
,
CodecMaxValues
codecMaxValues
,
float
codecOperatingRate
,
float
codecOperatingRate
,
boolean
deviceNeeds
AutoFrc
Workaround
,
boolean
deviceNeeds
NoPostProcess
Workaround
,
int
tunnelingAudioSessionId
)
{
int
tunnelingAudioSessionId
)
{
MediaFormat
mediaFormat
=
new
MediaFormat
();
MediaFormat
mediaFormat
=
new
MediaFormat
();
// Set format parameters that should always be set.
// Set format parameters that should always be set.
...
@@ -1062,7 +1062,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
...
@@ -1062,7 +1062,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
mediaFormat
.
setFloat
(
MediaFormat
.
KEY_OPERATING_RATE
,
codecOperatingRate
);
mediaFormat
.
setFloat
(
MediaFormat
.
KEY_OPERATING_RATE
,
codecOperatingRate
);
}
}
}
}
if
(
deviceNeedsAutoFrcWorkaround
)
{
if
(
deviceNeedsNoPostProcessWorkaround
)
{
mediaFormat
.
setInteger
(
"no-post-process"
,
1
);
mediaFormat
.
setInteger
(
"auto-frc"
,
0
);
mediaFormat
.
setInteger
(
"auto-frc"
,
0
);
}
}
if
(
tunnelingAudioSessionId
!=
C
.
AUDIO_SESSION_ID_UNSET
)
{
if
(
tunnelingAudioSessionId
!=
C
.
AUDIO_SESSION_ID_UNSET
)
{
...
@@ -1256,21 +1257,21 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
...
@@ -1256,21 +1257,21 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
}
}
/**
/**
* Returns whether the device is known to enable frame-rate conversion logic that negatively
* Returns whether the device is known to do post processing by default that isn't compatible with
* impacts ExoPlayer.
* ExoPlayer.
* <p>
* If true is returned then we explicitly disable the feature.
*
*
* @return
True if the device is known to enable frame-rate conversion logic that negatively
* @return
Whether the device is known to do post processing by default that isn't compatible with
*
impacts ExoPlayer. False otherwise
.
*
ExoPlayer
.
*/
*/
private
static
boolean
deviceNeeds
AutoFrc
Workaround
()
{
private
static
boolean
deviceNeeds
NoPostProcess
Workaround
()
{
//
nVidia Shield prior to M tries
to adjust the playback rate to better map the frame-rate of
//
Nvidia devices prior to M try
to adjust the playback rate to better map the frame-rate of
// content to the refresh rate of the display. For example playback of 23.976fps content is
// content to the refresh rate of the display. For example playback of 23.976fps content is
// adjusted to play at 1.001x speed when the output display is 60Hz. Unfortunately the
// adjusted to play at 1.001x speed when the output display is 60Hz. Unfortunately the
// implementation causes ExoPlayer's reported playback position to drift out of sync. Captions
// implementation causes ExoPlayer's reported playback position to drift out of sync. Captions
// also lose sync [Internal: b/26453592].
// also lose sync [Internal: b/26453592]. Even after M, the devices may apply post processing
return
Util
.
SDK_INT
<=
22
&&
"foster"
.
equals
(
Util
.
DEVICE
)
&&
"NVIDIA"
.
equals
(
Util
.
MANUFACTURER
);
// operations that can modify frame output timestamps, which is incompatible with ExoPlayer's
// logic for skipping decode-only frames.
return
"NVIDIA"
.
equals
(
Util
.
MANUFACTURER
);
}
}
/*
/*
...
@@ -1296,12 +1297,19 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
...
@@ -1296,12 +1297,19 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
* incorrectly.
* incorrectly.
*/
*/
protected
boolean
codecNeedsSetOutputSurfaceWorkaround
(
String
name
)
{
protected
boolean
codecNeedsSetOutputSurfaceWorkaround
(
String
name
)
{
if
(
Util
.
SDK_INT
>=
27
||
name
.
startsWith
(
"OMX.google"
))
{
if
(
name
.
startsWith
(
"OMX.google"
))
{
// Devices running API level 27 or later should also be unaffected. Google OMX decoders are
// Google OMX decoders are not known to have this issue on any API level.
// not known to have this issue on any API level.
return
false
;
return
false
;
}
}
// Work around:
synchronized
(
MediaCodecVideoRenderer
.
class
)
{
if
(!
evaluatedDeviceNeedsSetOutputSurfaceWorkaround
)
{
if
(
Util
.
SDK_INT
<=
27
&&
"dangal"
.
equals
(
Util
.
DEVICE
))
{
// Dangal is affected on API level 27: https://github.com/google/ExoPlayer/issues/5169.
deviceNeedsSetOutputSurfaceWorkaround
=
true
;
}
else
if
(
Util
.
SDK_INT
>=
27
)
{
// In general, devices running API level 27 or later should be unaffected. Do nothing.
}
else
{
// Enable the workaround on a per-device basis. Works around:
// https://github.com/google/ExoPlayer/issues/3236,
// https://github.com/google/ExoPlayer/issues/3236,
// https://github.com/google/ExoPlayer/issues/3355,
// https://github.com/google/ExoPlayer/issues/3355,
// https://github.com/google/ExoPlayer/issues/3439,
// https://github.com/google/ExoPlayer/issues/3439,
...
@@ -1315,8 +1323,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
...
@@ -1315,8 +1323,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
// https://github.com/google/ExoPlayer/issues/4419,
// https://github.com/google/ExoPlayer/issues/4419,
// https://github.com/google/ExoPlayer/issues/4460,
// https://github.com/google/ExoPlayer/issues/4460,
// https://github.com/google/ExoPlayer/issues/4468.
// https://github.com/google/ExoPlayer/issues/4468.
synchronized
(
MediaCodecVideoRenderer
.
class
)
{
if
(!
evaluatedDeviceNeedsSetOutputSurfaceWorkaround
)
{
switch
(
Util
.
DEVICE
)
{
switch
(
Util
.
DEVICE
)
{
case
"1601"
:
case
"1601"
:
case
"1713"
:
case
"1713"
:
...
@@ -1333,6 +1339,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
...
@@ -1333,6 +1339,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
case
"Aura_Note_2"
:
case
"Aura_Note_2"
:
case
"BLACK-1X"
:
case
"BLACK-1X"
:
case
"BRAVIA_ATV2"
:
case
"BRAVIA_ATV2"
:
case
"BRAVIA_ATV3_4K"
:
case
"C1"
:
case
"C1"
:
case
"ComioS1"
:
case
"ComioS1"
:
case
"CP8676_I02"
:
case
"CP8676_I02"
:
...
@@ -1355,6 +1362,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
...
@@ -1355,6 +1362,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
case
"F3215"
:
case
"F3215"
:
case
"F3311"
:
case
"F3311"
:
case
"flo"
:
case
"flo"
:
case
"fugu"
:
case
"GiONEE_CBL7513"
:
case
"GiONEE_CBL7513"
:
case
"GiONEE_GBL7319"
:
case
"GiONEE_GBL7319"
:
case
"GIONEE_GBL7360"
:
case
"GIONEE_GBL7360"
:
...
@@ -1454,6 +1462,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
...
@@ -1454,6 +1462,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
// Do nothing.
// Do nothing.
break
;
break
;
}
}
}
evaluatedDeviceNeedsSetOutputSurfaceWorkaround
=
true
;
evaluatedDeviceNeedsSetOutputSurfaceWorkaround
=
true
;
}
}
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/video/VideoRendererEventListener.java
View file @
71f72c59
...
@@ -26,7 +26,8 @@ import com.google.android.exoplayer2.decoder.DecoderCounters;
...
@@ -26,7 +26,8 @@ import com.google.android.exoplayer2.decoder.DecoderCounters;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.Assertions
;
/**
/**
* Listener of video {@link Renderer} events.
* Listener of video {@link Renderer} events. All methods have no-op default implementations to
* allow selective overrides.
*/
*/
public
interface
VideoRendererEventListener
{
public
interface
VideoRendererEventListener
{
...
@@ -36,7 +37,7 @@ public interface VideoRendererEventListener {
...
@@ -36,7 +37,7 @@ public interface VideoRendererEventListener {
* @param counters {@link DecoderCounters} that will be updated by the renderer for as long as it
* @param counters {@link DecoderCounters} that will be updated by the renderer for as long as it
* remains enabled.
* remains enabled.
*/
*/
void
onVideoEnabled
(
DecoderCounters
counters
);
default
void
onVideoEnabled
(
DecoderCounters
counters
)
{}
/**
/**
* Called when a decoder is created.
* Called when a decoder is created.
...
@@ -46,15 +47,15 @@ public interface VideoRendererEventListener {
...
@@ -46,15 +47,15 @@ public interface VideoRendererEventListener {
* finished.
* finished.
* @param initializationDurationMs The time taken to initialize the decoder in milliseconds.
* @param initializationDurationMs The time taken to initialize the decoder in milliseconds.
*/
*/
void
onVideoDecoderInitialized
(
String
decoderName
,
long
initializedTimestampMs
,
default
void
onVideoDecoderInitialized
(
long
initializationDurationMs
);
String
decoderName
,
long
initializedTimestampMs
,
long
initializationDurationMs
)
{}
/**
/**
* Called when the format of the media being consumed by the renderer changes.
* Called when the format of the media being consumed by the renderer changes.
*
*
* @param format The new format.
* @param format The new format.
*/
*/
void
onVideoInputFormatChanged
(
Format
format
);
default
void
onVideoInputFormatChanged
(
Format
format
)
{}
/**
/**
* Called to report the number of frames dropped by the renderer. Dropped frames are reported
* Called to report the number of frames dropped by the renderer. Dropped frames are reported
...
@@ -62,12 +63,11 @@ public interface VideoRendererEventListener {
...
@@ -62,12 +63,11 @@ public interface VideoRendererEventListener {
* reaches a specified threshold whilst the renderer is started.
* reaches a specified threshold whilst the renderer is started.
*
*
* @param count The number of dropped frames.
* @param count The number of dropped frames.
* @param elapsedMs The duration in milliseconds over which the frames were dropped. This
* @param elapsedMs The duration in milliseconds over which the frames were dropped. This duration
* duration is timed from when the renderer was started or from when dropped frames were
* is timed from when the renderer was started or from when dropped frames were last reported
* last reported (whichever was more recent), and not from when the first of the reported
* (whichever was more recent), and not from when the first of the reported drops occurred.
* drops occurred.
*/
*/
void
onDroppedFrames
(
int
count
,
long
elapsedMs
);
default
void
onDroppedFrames
(
int
count
,
long
elapsedMs
)
{}
/**
/**
* Called before a frame is rendered for the first time since setting the surface, and each time
* Called before a frame is rendered for the first time since setting the surface, and each time
...
@@ -82,12 +82,12 @@ public interface VideoRendererEventListener {
...
@@ -82,12 +82,12 @@ public interface VideoRendererEventListener {
* this is not possible. Applications that use {@link TextureView} can apply the rotation by
* this is not possible. Applications that use {@link TextureView} can apply the rotation by
* calling {@link TextureView#setTransform}. Applications that do not expect to encounter
* calling {@link TextureView#setTransform}. Applications that do not expect to encounter
* rotated videos can safely ignore this parameter.
* rotated videos can safely ignore this parameter.
* @param pixelWidthHeightRatio The width to height ratio of each pixel. For the normal case
* @param pixelWidthHeightRatio The width to height ratio of each pixel. For the normal case
of
*
of
square pixels this will be equal to 1.0. Different values are indicative of anamorphic
* square pixels this will be equal to 1.0. Different values are indicative of anamorphic
* content.
* content.
*/
*/
void
onVideoSizeChanged
(
int
width
,
int
height
,
int
unappliedRotationDegrees
,
default
void
onVideoSizeChanged
(
float
pixelWidthHeightRatio
);
int
width
,
int
height
,
int
unappliedRotationDegrees
,
float
pixelWidthHeightRatio
)
{}
/**
/**
* Called when a frame is rendered for the first time since setting the surface, and when a frame
* Called when a frame is rendered for the first time since setting the surface, and when a frame
...
@@ -96,14 +96,14 @@ public interface VideoRendererEventListener {
...
@@ -96,14 +96,14 @@ public interface VideoRendererEventListener {
* @param surface The {@link Surface} to which a first frame has been rendered, or {@code null} if
* @param surface The {@link Surface} to which a first frame has been rendered, or {@code null} if
* the renderer renders to something that isn't a {@link Surface}.
* the renderer renders to something that isn't a {@link Surface}.
*/
*/
void
onRenderedFirstFrame
(
@Nullable
Surface
surface
);
default
void
onRenderedFirstFrame
(
@Nullable
Surface
surface
)
{}
/**
/**
* Called when the renderer is disabled.
* Called when the renderer is disabled.
*
*
* @param counters {@link DecoderCounters} that were updated by the renderer.
* @param counters {@link DecoderCounters} that were updated by the renderer.
*/
*/
void
onVideoDisabled
(
DecoderCounters
counters
);
default
void
onVideoDisabled
(
DecoderCounters
counters
)
{}
/**
/**
* Dispatches events to a {@link VideoRendererEventListener}.
* Dispatches events to a {@link VideoRendererEventListener}.
...
...
library/core/src/test/assets/mp3/play-trimmed.mp3.0.dump
View file @
71f72c59
seekMap:
seekMap:
isSeekable = true
isSeekable = true
duration = 2612
5
duration = 2612
2
getPosition(0) = [[timeUs=0, position=0]]
getPosition(0) = [[timeUs=0, position=0]]
numberOfTracks = 1
numberOfTracks = 1
track 0:
track 0:
...
...
library/core/src/test/assets/mp3/play-trimmed.mp3.1.dump
View file @
71f72c59
seekMap:
seekMap:
isSeekable = true
isSeekable = true
duration = 2612
5
duration = 2612
2
getPosition(0) = [[timeUs=0, position=0]]
getPosition(0) = [[timeUs=0, position=0]]
numberOfTracks = 1
numberOfTracks = 1
track 0:
track 0:
...
...
library/core/src/test/assets/mp3/play-trimmed.mp3.2.dump
View file @
71f72c59
seekMap:
seekMap:
isSeekable = true
isSeekable = true
duration = 2612
5
duration = 2612
2
getPosition(0) = [[timeUs=0, position=0]]
getPosition(0) = [[timeUs=0, position=0]]
numberOfTracks = 1
numberOfTracks = 1
track 0:
track 0:
...
...
library/core/src/test/assets/mp3/play-trimmed.mp3.3.dump
View file @
71f72c59
seekMap:
seekMap:
isSeekable = true
isSeekable = true
duration = 2612
5
duration = 2612
2
getPosition(0) = [[timeUs=0, position=0]]
getPosition(0) = [[timeUs=0, position=0]]
numberOfTracks = 1
numberOfTracks = 1
track 0:
track 0:
...
...
library/core/src/test/assets/ttml/bitmap_percentage_region.xml
0 → 100644
View file @
71f72c59
<tt
xmlns=
"http://www.w3.org/ns/ttml"
xmlns:ttm=
"http://www.w3.org/ns/ttml#metadata"
xmlns:tts=
"http://www.w3.org/ns/ttml#styling"
xmlns:smpte=
"http://www.smpte-ra.org/schemas/2052-1/2010/smpte-tt"
xml:lang=
"eng"
>
<head>
<metadata>
<smpte:image
imagetype=
"PNG"
encoding=
"Base64"
xml:id=
"img_0"
>
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
</smpte:image>
<smpte:image
imagetype=
"PNG"
encoding=
"Base64"
xml:id=
"img_1"
>
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
</smpte:image>
</metadata>
<styling>
<style/>
</styling>
<layout>
<region
xml:id=
"region_0"
tts:extent=
"51% 12%"
tts:origin=
"24% 78%"
/>
<region
xml:id=
"region_1"
tts:extent=
"57% 6%"
tts:origin=
"21% 85%"
/>
<region
xml:id=
"region_2"
tts:extent=
"51% 12%"
tts:origin=
"24% 28%"
/>
<region
xml:id=
"region_3"
tts:extent=
"57% 6%"
tts:origin=
"21% 35%"
/>
</layout>
</head>
<body>
<div
begin=
"00:00:00.200"
end=
"00:00:03.000"
region=
"region_2"
smpte:backgroundImage=
"#img_0"
/>
<div
begin=
"00:00:03.200"
end=
"00:00:06.937"
region=
"region_3"
smpte:backgroundImage=
"#img_1"
/>
<div
begin=
"00:00:07.200"
end=
"00:59:03.000"
region=
"region_2"
smpte:backgroundImage=
"#img_0"
/>
</body>
</tt>
library/core/src/test/assets/ttml/bitmap_pixel_region.xml
0 → 100644
View file @
71f72c59
<tt
xmlns=
"http://www.w3.org/ns/ttml"
xmlns:ttm=
"http://www.w3.org/ns/ttml#metadata"
xmlns:tts=
"http://www.w3.org/ns/ttml#styling"
xmlns:smpte=
"http://www.smpte-ra.org/schemas/2052-1/2010/smpte-tt"
xml:lang=
"eng"
tts:extent=
"1280px 720px"
>
<head>
<metadata>
<smpte:image
imagetype=
"PNG"
encoding=
"Base64"
xml:id=
"img_0"
>
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
</smpte:image>
<smpte:image
imagetype=
"PNG"
encoding=
"Base64"
xml:id=
"img_1"
>
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
</smpte:image>
</metadata>
<styling>
<style/>
</styling>
<layout>
<region
xml:id=
"region_0"
tts:extent=
"653px 86px"
tts:origin=
"307px 562px"
/>
<region
xml:id=
"region_1"
tts:extent=
"730px 43px"
tts:origin=
"269px 612px"
/>
</layout>
</head>
<body>
<div
begin=
"00:00:00.200"
end=
"00:00:03.000"
region=
"region_0"
smpte:backgroundImage=
"#img_0"
/>
<div
begin=
"00:00:03.200"
end=
"00:00:06.937"
region=
"region_1"
smpte:backgroundImage=
"#img_1"
/>
</body>
</tt>
library/core/src/test/assets/ttml/bitmap_unsupported_region.xml
0 → 100644
View file @
71f72c59
<tt
xmlns=
"http://www.w3.org/ns/ttml"
xmlns:ttm=
"http://www.w3.org/ns/ttml#metadata"
xmlns:tts=
"http://www.w3.org/ns/ttml#styling"
xmlns:smpte=
"http://www.smpte-ra.org/schemas/2052-1/2010/smpte-tt"
xml:lang=
"eng"
>
<head>
<metadata>
<smpte:image
imagetype=
"PNG"
encoding=
"Base64"
xml:id=
"img_0"
>
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
</smpte:image>
<smpte:image
imagetype=
"PNG"
encoding=
"Base64"
xml:id=
"img_1"
>
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
</smpte:image>
</metadata>
<styling>
<style/>
</styling>
<layout>
<region
xml:id=
"region_0"
tts:extent=
"653px 86px"
tts:origin=
"307px 562px"
/>
<region
xml:id=
"region_1"
tts:extent=
"730px 43px"
tts:origin=
"269px 612px"
/>
</layout>
</head>
<body>
<div
begin=
"00:00:00.200"
end=
"00:00:03.000"
region=
"region_0"
smpte:backgroundImage=
"#img_0"
/>
<div
begin=
"00:00:03.200"
end=
"00:00:06.937"
region=
"region_1"
smpte:backgroundImage=
"#img_1"
/>
</body>
</tt>
library/core/src/test/java/com/google/android/exoplayer2/extractor/ts/AdtsReaderTest.java
View file @
71f72c59
...
@@ -15,6 +15,8 @@
...
@@ -15,6 +15,8 @@
*/
*/
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
ts
;
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
ts
;
import
static
com
.
google
.
android
.
exoplayer2
.
extractor
.
ts
.
TsPayloadReader
.
FLAG_DATA_ALIGNMENT_INDICATOR
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.ParserException
;
import
com.google.android.exoplayer2.ParserException
;
import
com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator
;
import
com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator
;
...
@@ -198,7 +200,7 @@ public class AdtsReaderTest {
...
@@ -198,7 +200,7 @@ public class AdtsReaderTest {
private
void
maybeStartPacket
()
{
private
void
maybeStartPacket
()
{
if
(
firstFeed
)
{
if
(
firstFeed
)
{
adtsReader
.
packetStarted
(
0
,
true
);
adtsReader
.
packetStarted
(
0
,
FLAG_DATA_ALIGNMENT_INDICATOR
);
firstFeed
=
false
;
firstFeed
=
false
;
}
}
}
}
...
...
library/core/src/test/java/com/google/android/exoplayer2/extractor/ts/SectionReaderTest.java
View file @
71f72c59
...
@@ -15,6 +15,7 @@
...
@@ -15,6 +15,7 @@
*/
*/
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
ts
;
package
com
.
google
.
android
.
exoplayer2
.
extractor
.
ts
;
import
static
com
.
google
.
android
.
exoplayer2
.
extractor
.
ts
.
TsPayloadReader
.
FLAG_PAYLOAD_UNIT_START_INDICATOR
;
import
static
com
.
google
.
common
.
truth
.
Truth
.
assertThat
;
import
static
com
.
google
.
common
.
truth
.
Truth
.
assertThat
;
import
static
java
.
util
.
Arrays
.
asList
;
import
static
java
.
util
.
Arrays
.
asList
;
import
static
java
.
util
.
Collections
.
singletonList
;
import
static
java
.
util
.
Collections
.
singletonList
;
...
@@ -55,7 +56,7 @@ public final class SectionReaderTest {
...
@@ -55,7 +56,7 @@ public final class SectionReaderTest {
public
void
testSingleOnePacketSection
()
{
public
void
testSingleOnePacketSection
()
{
packetPayload
[
0
]
=
3
;
packetPayload
[
0
]
=
3
;
insertTableSection
(
4
,
(
byte
)
99
,
3
);
insertTableSection
(
4
,
(
byte
)
99
,
3
);
reader
.
consume
(
new
ParsableByteArray
(
packetPayload
),
true
);
reader
.
consume
(
new
ParsableByteArray
(
packetPayload
),
FLAG_PAYLOAD_UNIT_START_INDICATOR
);
assertThat
(
payloadReader
.
parsedTableIds
).
isEqualTo
(
singletonList
(
99
));
assertThat
(
payloadReader
.
parsedTableIds
).
isEqualTo
(
singletonList
(
99
));
}
}
...
@@ -65,12 +66,12 @@ public final class SectionReaderTest {
...
@@ -65,12 +66,12 @@ public final class SectionReaderTest {
insertTableSection
(
4
,
(
byte
)
100
,
3
);
// This section header spreads across both packets.
insertTableSection
(
4
,
(
byte
)
100
,
3
);
// This section header spreads across both packets.
ParsableByteArray
firstPacket
=
new
ParsableByteArray
(
packetPayload
,
5
);
ParsableByteArray
firstPacket
=
new
ParsableByteArray
(
packetPayload
,
5
);
reader
.
consume
(
firstPacket
,
true
);
reader
.
consume
(
firstPacket
,
FLAG_PAYLOAD_UNIT_START_INDICATOR
);
assertThat
(
payloadReader
.
parsedTableIds
).
isEmpty
();
assertThat
(
payloadReader
.
parsedTableIds
).
isEmpty
();
ParsableByteArray
secondPacket
=
new
ParsableByteArray
(
packetPayload
);
ParsableByteArray
secondPacket
=
new
ParsableByteArray
(
packetPayload
);
secondPacket
.
setPosition
(
5
);
secondPacket
.
setPosition
(
5
);
reader
.
consume
(
secondPacket
,
false
);
reader
.
consume
(
secondPacket
,
/* flags= */
0
);
assertThat
(
payloadReader
.
parsedTableIds
).
isEqualTo
(
singletonList
(
100
));
assertThat
(
payloadReader
.
parsedTableIds
).
isEqualTo
(
singletonList
(
100
));
}
}
...
@@ -85,12 +86,12 @@ public final class SectionReaderTest {
...
@@ -85,12 +86,12 @@ public final class SectionReaderTest {
insertTableSection
(
54
,
(
byte
)
105
,
10
);
insertTableSection
(
54
,
(
byte
)
105
,
10
);
ParsableByteArray
firstPacket
=
new
ParsableByteArray
(
packetPayload
,
40
);
ParsableByteArray
firstPacket
=
new
ParsableByteArray
(
packetPayload
,
40
);
reader
.
consume
(
firstPacket
,
true
);
reader
.
consume
(
firstPacket
,
FLAG_PAYLOAD_UNIT_START_INDICATOR
);
assertThat
(
payloadReader
.
parsedTableIds
).
isEqualTo
(
asList
(
101
,
102
,
103
));
assertThat
(
payloadReader
.
parsedTableIds
).
isEqualTo
(
asList
(
101
,
102
,
103
));
ParsableByteArray
secondPacket
=
new
ParsableByteArray
(
packetPayload
);
ParsableByteArray
secondPacket
=
new
ParsableByteArray
(
packetPayload
);
secondPacket
.
setPosition
(
40
);
secondPacket
.
setPosition
(
40
);
reader
.
consume
(
secondPacket
,
true
);
reader
.
consume
(
secondPacket
,
FLAG_PAYLOAD_UNIT_START_INDICATOR
);
assertThat
(
payloadReader
.
parsedTableIds
).
isEqualTo
(
asList
(
101
,
102
,
103
,
104
,
105
));
assertThat
(
payloadReader
.
parsedTableIds
).
isEqualTo
(
asList
(
101
,
102
,
103
,
104
,
105
));
}
}
...
@@ -105,22 +106,22 @@ public final class SectionReaderTest {
...
@@ -105,22 +106,22 @@ public final class SectionReaderTest {
insertTableSection
(
318
,
(
byte
)
108
,
10
);
insertTableSection
(
318
,
(
byte
)
108
,
10
);
ParsableByteArray
firstPacket
=
new
ParsableByteArray
(
packetPayload
,
100
);
ParsableByteArray
firstPacket
=
new
ParsableByteArray
(
packetPayload
,
100
);
reader
.
consume
(
firstPacket
,
true
);
reader
.
consume
(
firstPacket
,
FLAG_PAYLOAD_UNIT_START_INDICATOR
);
assertThat
(
payloadReader
.
parsedTableIds
).
isEmpty
();
assertThat
(
payloadReader
.
parsedTableIds
).
isEmpty
();
ParsableByteArray
secondPacket
=
new
ParsableByteArray
(
packetPayload
,
200
);
ParsableByteArray
secondPacket
=
new
ParsableByteArray
(
packetPayload
,
200
);
secondPacket
.
setPosition
(
100
);
secondPacket
.
setPosition
(
100
);
reader
.
consume
(
secondPacket
,
false
);
reader
.
consume
(
secondPacket
,
/* flags= */
0
);
assertThat
(
payloadReader
.
parsedTableIds
).
isEmpty
();
assertThat
(
payloadReader
.
parsedTableIds
).
isEmpty
();
ParsableByteArray
thirdPacket
=
new
ParsableByteArray
(
packetPayload
,
300
);
ParsableByteArray
thirdPacket
=
new
ParsableByteArray
(
packetPayload
,
300
);
thirdPacket
.
setPosition
(
200
);
thirdPacket
.
setPosition
(
200
);
reader
.
consume
(
thirdPacket
,
false
);
reader
.
consume
(
thirdPacket
,
/* flags= */
0
);
assertThat
(
payloadReader
.
parsedTableIds
).
isEmpty
();
assertThat
(
payloadReader
.
parsedTableIds
).
isEmpty
();
ParsableByteArray
fourthPacket
=
new
ParsableByteArray
(
packetPayload
);
ParsableByteArray
fourthPacket
=
new
ParsableByteArray
(
packetPayload
);
fourthPacket
.
setPosition
(
300
);
fourthPacket
.
setPosition
(
300
);
reader
.
consume
(
fourthPacket
,
true
);
reader
.
consume
(
fourthPacket
,
FLAG_PAYLOAD_UNIT_START_INDICATOR
);
assertThat
(
payloadReader
.
parsedTableIds
).
isEqualTo
(
asList
(
107
,
108
));
assertThat
(
payloadReader
.
parsedTableIds
).
isEqualTo
(
asList
(
107
,
108
));
}
}
...
@@ -135,24 +136,24 @@ public final class SectionReaderTest {
...
@@ -135,24 +136,24 @@ public final class SectionReaderTest {
insertTableSection
(
318
,
(
byte
)
111
,
10
);
insertTableSection
(
318
,
(
byte
)
111
,
10
);
ParsableByteArray
firstPacket
=
new
ParsableByteArray
(
packetPayload
,
100
);
ParsableByteArray
firstPacket
=
new
ParsableByteArray
(
packetPayload
,
100
);
reader
.
consume
(
firstPacket
,
true
);
reader
.
consume
(
firstPacket
,
FLAG_PAYLOAD_UNIT_START_INDICATOR
);
assertThat
(
payloadReader
.
parsedTableIds
).
isEmpty
();
assertThat
(
payloadReader
.
parsedTableIds
).
isEmpty
();
ParsableByteArray
secondPacket
=
new
ParsableByteArray
(
packetPayload
,
200
);
ParsableByteArray
secondPacket
=
new
ParsableByteArray
(
packetPayload
,
200
);
secondPacket
.
setPosition
(
100
);
secondPacket
.
setPosition
(
100
);
reader
.
consume
(
secondPacket
,
false
);
reader
.
consume
(
secondPacket
,
/* flags= */
0
);
assertThat
(
payloadReader
.
parsedTableIds
).
isEmpty
();
assertThat
(
payloadReader
.
parsedTableIds
).
isEmpty
();
ParsableByteArray
thirdPacket
=
new
ParsableByteArray
(
packetPayload
,
300
);
ParsableByteArray
thirdPacket
=
new
ParsableByteArray
(
packetPayload
,
300
);
thirdPacket
.
setPosition
(
200
);
thirdPacket
.
setPosition
(
200
);
reader
.
consume
(
thirdPacket
,
false
);
reader
.
consume
(
thirdPacket
,
/* flags= */
0
);
assertThat
(
payloadReader
.
parsedTableIds
).
isEmpty
();
assertThat
(
payloadReader
.
parsedTableIds
).
isEmpty
();
reader
.
seek
();
reader
.
seek
();
ParsableByteArray
fourthPacket
=
new
ParsableByteArray
(
packetPayload
);
ParsableByteArray
fourthPacket
=
new
ParsableByteArray
(
packetPayload
);
fourthPacket
.
setPosition
(
300
);
fourthPacket
.
setPosition
(
300
);
reader
.
consume
(
fourthPacket
,
true
);
reader
.
consume
(
fourthPacket
,
FLAG_PAYLOAD_UNIT_START_INDICATOR
);
assertThat
(
payloadReader
.
parsedTableIds
).
isEqualTo
(
singletonList
(
111
));
assertThat
(
payloadReader
.
parsedTableIds
).
isEqualTo
(
singletonList
(
111
));
}
}
...
@@ -165,9 +166,9 @@ public final class SectionReaderTest {
...
@@ -165,9 +166,9 @@ public final class SectionReaderTest {
byte
[]
incorrectCrcPat
=
Arrays
.
copyOf
(
correctCrcPat
,
correctCrcPat
.
length
);
byte
[]
incorrectCrcPat
=
Arrays
.
copyOf
(
correctCrcPat
,
correctCrcPat
.
length
);
// Crc field is incorrect, and should not be passed to the payload reader.
// Crc field is incorrect, and should not be passed to the payload reader.
incorrectCrcPat
[
16
]--;
incorrectCrcPat
[
16
]--;
reader
.
consume
(
new
ParsableByteArray
(
correctCrcPat
),
true
);
reader
.
consume
(
new
ParsableByteArray
(
correctCrcPat
),
FLAG_PAYLOAD_UNIT_START_INDICATOR
);
assertThat
(
payloadReader
.
parsedTableIds
).
isEqualTo
(
singletonList
(
0
));
assertThat
(
payloadReader
.
parsedTableIds
).
isEqualTo
(
singletonList
(
0
));
reader
.
consume
(
new
ParsableByteArray
(
incorrectCrcPat
),
true
);
reader
.
consume
(
new
ParsableByteArray
(
incorrectCrcPat
),
FLAG_PAYLOAD_UNIT_START_INDICATOR
);
assertThat
(
payloadReader
.
parsedTableIds
).
isEqualTo
(
singletonList
(
0
));
assertThat
(
payloadReader
.
parsedTableIds
).
isEqualTo
(
singletonList
(
0
));
}
}
...
...
library/core/src/test/java/com/google/android/exoplayer2/extractor/ts/TsExtractorTest.java
View file @
71f72c59
...
@@ -202,7 +202,7 @@ public final class TsExtractorTest {
...
@@ -202,7 +202,7 @@ public final class TsExtractorTest {
}
}
@Override
@Override
public
void
packetStarted
(
long
pesTimeUs
,
boolean
dataAlignmentIndicator
)
{}
public
void
packetStarted
(
long
pesTimeUs
,
@TsPayloadReader
.
Flags
int
flags
)
{}
@Override
@Override
public
void
consume
(
ParsableByteArray
data
)
{}
public
void
consume
(
ParsableByteArray
data
)
{}
...
...
library/core/src/test/java/com/google/android/exoplayer2/text/ttml/TtmlDecoderTest.java
View file @
71f72c59
...
@@ -63,6 +63,9 @@ public final class TtmlDecoderTest {
...
@@ -63,6 +63,9 @@ public final class TtmlDecoderTest {
private
static
final
String
FONT_SIZE_INVALID_TTML_FILE
=
"ttml/font_size_invalid.xml"
;
private
static
final
String
FONT_SIZE_INVALID_TTML_FILE
=
"ttml/font_size_invalid.xml"
;
private
static
final
String
FONT_SIZE_EMPTY_TTML_FILE
=
"ttml/font_size_empty.xml"
;
private
static
final
String
FONT_SIZE_EMPTY_TTML_FILE
=
"ttml/font_size_empty.xml"
;
private
static
final
String
FRAME_RATE_TTML_FILE
=
"ttml/frame_rate.xml"
;
private
static
final
String
FRAME_RATE_TTML_FILE
=
"ttml/frame_rate.xml"
;
private
static
final
String
BITMAP_REGION_FILE
=
"ttml/bitmap_percentage_region.xml"
;
private
static
final
String
BITMAP_PIXEL_REGION_FILE
=
"ttml/bitmap_pixel_region.xml"
;
private
static
final
String
BITMAP_UNSUPPORTED_REGION_FILE
=
"ttml/bitmap_unsupported_region.xml"
;
@Test
@Test
public
void
testInlineAttributes
()
throws
IOException
,
SubtitleDecoderException
{
public
void
testInlineAttributes
()
throws
IOException
,
SubtitleDecoderException
{
...
@@ -259,56 +262,56 @@ public final class TtmlDecoderTest {
...
@@ -259,56 +262,56 @@ public final class TtmlDecoderTest {
@Test
@Test
public
void
testMultipleRegions
()
throws
IOException
,
SubtitleDecoderException
{
public
void
testMultipleRegions
()
throws
IOException
,
SubtitleDecoderException
{
TtmlSubtitle
subtitle
=
getSubtitle
(
MULTIPLE_REGIONS_TTML_FILE
);
TtmlSubtitle
subtitle
=
getSubtitle
(
MULTIPLE_REGIONS_TTML_FILE
);
List
<
Cue
>
output
=
subtitle
.
getCues
(
1000000
);
List
<
Cue
>
cues
=
subtitle
.
getCues
(
1000000
);
assertThat
(
output
).
hasSize
(
2
);
assertThat
(
cues
).
hasSize
(
2
);
Cue
ttmlCue
=
output
.
get
(
0
);
Cue
cue
=
cues
.
get
(
0
);
assertThat
(
ttmlC
ue
.
text
.
toString
()).
isEqualTo
(
"lorem"
);
assertThat
(
c
ue
.
text
.
toString
()).
isEqualTo
(
"lorem"
);
assertThat
(
ttmlC
ue
.
position
).
isEqualTo
(
10
f
/
100
f
);
assertThat
(
c
ue
.
position
).
isEqualTo
(
10
f
/
100
f
);
assertThat
(
ttmlC
ue
.
line
).
isEqualTo
(
10
f
/
100
f
);
assertThat
(
c
ue
.
line
).
isEqualTo
(
10
f
/
100
f
);
assertThat
(
ttmlC
ue
.
size
).
isEqualTo
(
20
f
/
100
f
);
assertThat
(
c
ue
.
size
).
isEqualTo
(
20
f
/
100
f
);
ttmlCue
=
output
.
get
(
1
);
cue
=
cues
.
get
(
1
);
assertThat
(
ttmlC
ue
.
text
.
toString
()).
isEqualTo
(
"amet"
);
assertThat
(
c
ue
.
text
.
toString
()).
isEqualTo
(
"amet"
);
assertThat
(
ttmlC
ue
.
position
).
isEqualTo
(
60
f
/
100
f
);
assertThat
(
c
ue
.
position
).
isEqualTo
(
60
f
/
100
f
);
assertThat
(
ttmlC
ue
.
line
).
isEqualTo
(
10
f
/
100
f
);
assertThat
(
c
ue
.
line
).
isEqualTo
(
10
f
/
100
f
);
assertThat
(
ttmlC
ue
.
size
).
isEqualTo
(
20
f
/
100
f
);
assertThat
(
c
ue
.
size
).
isEqualTo
(
20
f
/
100
f
);
output
=
subtitle
.
getCues
(
5000000
);
cues
=
subtitle
.
getCues
(
5000000
);
assertThat
(
output
).
hasSize
(
1
);
assertThat
(
cues
).
hasSize
(
1
);
ttmlCue
=
output
.
get
(
0
);
cue
=
cues
.
get
(
0
);
assertThat
(
ttmlC
ue
.
text
.
toString
()).
isEqualTo
(
"ipsum"
);
assertThat
(
c
ue
.
text
.
toString
()).
isEqualTo
(
"ipsum"
);
assertThat
(
ttmlC
ue
.
position
).
isEqualTo
(
40
f
/
100
f
);
assertThat
(
c
ue
.
position
).
isEqualTo
(
40
f
/
100
f
);
assertThat
(
ttmlC
ue
.
line
).
isEqualTo
(
40
f
/
100
f
);
assertThat
(
c
ue
.
line
).
isEqualTo
(
40
f
/
100
f
);
assertThat
(
ttmlC
ue
.
size
).
isEqualTo
(
20
f
/
100
f
);
assertThat
(
c
ue
.
size
).
isEqualTo
(
20
f
/
100
f
);
output
=
subtitle
.
getCues
(
9000000
);
cues
=
subtitle
.
getCues
(
9000000
);
assertThat
(
output
).
hasSize
(
1
);
assertThat
(
cues
).
hasSize
(
1
);
ttmlCue
=
output
.
get
(
0
);
cue
=
cues
.
get
(
0
);
assertThat
(
ttmlC
ue
.
text
.
toString
()).
isEqualTo
(
"dolor"
);
assertThat
(
c
ue
.
text
.
toString
()).
isEqualTo
(
"dolor"
);
assertThat
(
ttmlC
ue
.
position
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
assertThat
(
c
ue
.
position
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
assertThat
(
ttmlC
ue
.
line
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
assertThat
(
c
ue
.
line
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
assertThat
(
ttmlC
ue
.
size
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
assertThat
(
c
ue
.
size
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
// TODO: Should be as below, once https://github.com/google/ExoPlayer/issues/2953 is fixed.
// TODO: Should be as below, once https://github.com/google/ExoPlayer/issues/2953 is fixed.
// assertEquals(10f / 100f,
ttmlC
ue.position);
// assertEquals(10f / 100f,
c
ue.position);
// assertEquals(80f / 100f,
ttmlC
ue.line);
// assertEquals(80f / 100f,
c
ue.line);
// assertEquals(1f,
ttmlC
ue.size);
// assertEquals(1f,
c
ue.size);
output
=
subtitle
.
getCues
(
21000000
);
cues
=
subtitle
.
getCues
(
21000000
);
assertThat
(
output
).
hasSize
(
1
);
assertThat
(
cues
).
hasSize
(
1
);
ttmlCue
=
output
.
get
(
0
);
cue
=
cues
.
get
(
0
);
assertThat
(
ttmlC
ue
.
text
.
toString
()).
isEqualTo
(
"She first said this"
);
assertThat
(
c
ue
.
text
.
toString
()).
isEqualTo
(
"She first said this"
);
assertThat
(
ttmlC
ue
.
position
).
isEqualTo
(
45
f
/
100
f
);
assertThat
(
c
ue
.
position
).
isEqualTo
(
45
f
/
100
f
);
assertThat
(
ttmlC
ue
.
line
).
isEqualTo
(
45
f
/
100
f
);
assertThat
(
c
ue
.
line
).
isEqualTo
(
45
f
/
100
f
);
assertThat
(
ttmlC
ue
.
size
).
isEqualTo
(
35
f
/
100
f
);
assertThat
(
c
ue
.
size
).
isEqualTo
(
35
f
/
100
f
);
output
=
subtitle
.
getCues
(
25000000
);
cues
=
subtitle
.
getCues
(
25000000
);
ttmlCue
=
output
.
get
(
0
);
cue
=
cues
.
get
(
0
);
assertThat
(
ttmlC
ue
.
text
.
toString
()).
isEqualTo
(
"She first said this\nThen this"
);
assertThat
(
c
ue
.
text
.
toString
()).
isEqualTo
(
"She first said this\nThen this"
);
output
=
subtitle
.
getCues
(
29000000
);
cues
=
subtitle
.
getCues
(
29000000
);
assertThat
(
output
).
hasSize
(
1
);
assertThat
(
cues
).
hasSize
(
1
);
ttmlCue
=
output
.
get
(
0
);
cue
=
cues
.
get
(
0
);
assertThat
(
ttmlC
ue
.
text
.
toString
()).
isEqualTo
(
"She first said this\nThen this\nFinally this"
);
assertThat
(
c
ue
.
text
.
toString
()).
isEqualTo
(
"She first said this\nThen this\nFinally this"
);
assertThat
(
ttmlC
ue
.
position
).
isEqualTo
(
45
f
/
100
f
);
assertThat
(
c
ue
.
position
).
isEqualTo
(
45
f
/
100
f
);
assertThat
(
ttmlC
ue
.
line
).
isEqualTo
(
45
f
/
100
f
);
assertThat
(
c
ue
.
line
).
isEqualTo
(
45
f
/
100
f
);
}
}
@Test
@Test
...
@@ -499,6 +502,91 @@ public final class TtmlDecoderTest {
...
@@ -499,6 +502,91 @@ public final class TtmlDecoderTest {
assertThat
((
double
)
subtitle
.
getEventTime
(
3
)).
isWithin
(
2000
).
of
(
2_002_000_000
);
assertThat
((
double
)
subtitle
.
getEventTime
(
3
)).
isWithin
(
2000
).
of
(
2_002_000_000
);
}
}
@Test
public
void
testBitmapPercentageRegion
()
throws
IOException
,
SubtitleDecoderException
{
TtmlSubtitle
subtitle
=
getSubtitle
(
BITMAP_REGION_FILE
);
List
<
Cue
>
cues
=
subtitle
.
getCues
(
1000000
);
assertThat
(
cues
).
hasSize
(
1
);
Cue
cue
=
cues
.
get
(
0
);
assertThat
(
cue
.
text
).
isNull
();
assertThat
(
cue
.
bitmap
).
isNotNull
();
assertThat
(
cue
.
position
).
isEqualTo
(
24
f
/
100
f
);
assertThat
(
cue
.
line
).
isEqualTo
(
28
f
/
100
f
);
assertThat
(
cue
.
size
).
isEqualTo
(
51
f
/
100
f
);
assertThat
(
cue
.
bitmapHeight
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
cues
=
subtitle
.
getCues
(
4000000
);
assertThat
(
cues
).
hasSize
(
1
);
cue
=
cues
.
get
(
0
);
assertThat
(
cue
.
text
).
isNull
();
assertThat
(
cue
.
bitmap
).
isNotNull
();
assertThat
(
cue
.
position
).
isEqualTo
(
21
f
/
100
f
);
assertThat
(
cue
.
line
).
isEqualTo
(
35
f
/
100
f
);
assertThat
(
cue
.
size
).
isEqualTo
(
57
f
/
100
f
);
assertThat
(
cue
.
bitmapHeight
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
cues
=
subtitle
.
getCues
(
7500000
);
assertThat
(
cues
).
hasSize
(
1
);
cue
=
cues
.
get
(
0
);
assertThat
(
cue
.
text
).
isNull
();
assertThat
(
cue
.
bitmap
).
isNotNull
();
assertThat
(
cue
.
position
).
isEqualTo
(
24
f
/
100
f
);
assertThat
(
cue
.
line
).
isEqualTo
(
28
f
/
100
f
);
assertThat
(
cue
.
size
).
isEqualTo
(
51
f
/
100
f
);
assertThat
(
cue
.
bitmapHeight
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
}
@Test
public
void
testBitmapPixelRegion
()
throws
IOException
,
SubtitleDecoderException
{
TtmlSubtitle
subtitle
=
getSubtitle
(
BITMAP_PIXEL_REGION_FILE
);
List
<
Cue
>
cues
=
subtitle
.
getCues
(
1000000
);
assertThat
(
cues
).
hasSize
(
1
);
Cue
cue
=
cues
.
get
(
0
);
assertThat
(
cue
.
text
).
isNull
();
assertThat
(
cue
.
bitmap
).
isNotNull
();
assertThat
(
cue
.
position
).
isEqualTo
(
307
f
/
1280
f
);
assertThat
(
cue
.
line
).
isEqualTo
(
562
f
/
720
f
);
assertThat
(
cue
.
size
).
isEqualTo
(
653
f
/
1280
f
);
assertThat
(
cue
.
bitmapHeight
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
cues
=
subtitle
.
getCues
(
4000000
);
assertThat
(
cues
).
hasSize
(
1
);
cue
=
cues
.
get
(
0
);
assertThat
(
cue
.
text
).
isNull
();
assertThat
(
cue
.
bitmap
).
isNotNull
();
assertThat
(
cue
.
position
).
isEqualTo
(
269
f
/
1280
f
);
assertThat
(
cue
.
line
).
isEqualTo
(
612
f
/
720
f
);
assertThat
(
cue
.
size
).
isEqualTo
(
730
f
/
1280
f
);
assertThat
(
cue
.
bitmapHeight
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
}
@Test
public
void
testBitmapUnsupportedRegion
()
throws
IOException
,
SubtitleDecoderException
{
TtmlSubtitle
subtitle
=
getSubtitle
(
BITMAP_UNSUPPORTED_REGION_FILE
);
List
<
Cue
>
cues
=
subtitle
.
getCues
(
1000000
);
assertThat
(
cues
).
hasSize
(
1
);
Cue
cue
=
cues
.
get
(
0
);
assertThat
(
cue
.
text
).
isNull
();
assertThat
(
cue
.
bitmap
).
isNotNull
();
assertThat
(
cue
.
position
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
assertThat
(
cue
.
line
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
assertThat
(
cue
.
size
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
assertThat
(
cue
.
bitmapHeight
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
cues
=
subtitle
.
getCues
(
4000000
);
assertThat
(
cues
).
hasSize
(
1
);
cue
=
cues
.
get
(
0
);
assertThat
(
cue
.
text
).
isNull
();
assertThat
(
cue
.
bitmap
).
isNotNull
();
assertThat
(
cue
.
position
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
assertThat
(
cue
.
line
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
assertThat
(
cue
.
size
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
assertThat
(
cue
.
bitmapHeight
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
}
private
void
assertSpans
(
private
void
assertSpans
(
TtmlSubtitle
subtitle
,
TtmlSubtitle
subtitle
,
int
second
,
int
second
,
...
...
library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java
View file @
71f72c59
...
@@ -489,11 +489,7 @@ public final class CacheDataSourceTest {
...
@@ -489,11 +489,7 @@ public final class CacheDataSourceTest {
NavigableSet
<
CacheSpan
>
cachedSpans
=
cache
.
getCachedSpans
(
expectedCacheKey
);
NavigableSet
<
CacheSpan
>
cachedSpans
=
cache
.
getCachedSpans
(
expectedCacheKey
);
for
(
CacheSpan
cachedSpan
:
cachedSpans
)
{
for
(
CacheSpan
cachedSpan
:
cachedSpans
)
{
if
(
cachedSpan
.
position
>=
halfDataLength
)
{
if
(
cachedSpan
.
position
>=
halfDataLength
)
{
try
{
cache
.
removeSpan
(
cachedSpan
);
cache
.
removeSpan
(
cachedSpan
);
}
catch
(
Cache
.
CacheException
e
)
{
// do nothing
}
}
}
}
}
...
...
library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/SimpleCacheTest.java
View file @
71f72c59
...
@@ -47,6 +47,7 @@ import org.robolectric.RuntimeEnvironment;
...
@@ -47,6 +47,7 @@ import org.robolectric.RuntimeEnvironment;
public
class
SimpleCacheTest
{
public
class
SimpleCacheTest
{
private
static
final
String
KEY_1
=
"key1"
;
private
static
final
String
KEY_1
=
"key1"
;
private
static
final
String
KEY_2
=
"key2"
;
private
File
cacheDir
;
private
File
cacheDir
;
...
@@ -153,6 +154,40 @@ public class SimpleCacheTest {
...
@@ -153,6 +154,40 @@ public class SimpleCacheTest {
}
}
@Test
@Test
public
void
testReloadCacheWithoutRelease
()
throws
Exception
{
SimpleCache
simpleCache
=
getSimpleCache
();
// Write data for KEY_1.
CacheSpan
cacheSpan1
=
simpleCache
.
startReadWrite
(
KEY_1
,
0
);
addCache
(
simpleCache
,
KEY_1
,
0
,
15
);
simpleCache
.
releaseHoleSpan
(
cacheSpan1
);
// Write and remove data for KEY_2.
CacheSpan
cacheSpan2
=
simpleCache
.
startReadWrite
(
KEY_2
,
0
);
addCache
(
simpleCache
,
KEY_2
,
0
,
15
);
simpleCache
.
releaseHoleSpan
(
cacheSpan2
);
simpleCache
.
removeSpan
(
simpleCache
.
getCachedSpans
(
KEY_2
).
first
());
// Don't release the cache. This means the index file wont have been written to disk after the
// data for KEY_2 was removed. Move the cache instead, so we can reload it without failing the
// folder locking check.
File
cacheDir2
=
Util
.
createTempFile
(
RuntimeEnvironment
.
application
,
"ExoPlayerTest"
);
cacheDir2
.
delete
();
cacheDir
.
renameTo
(
cacheDir2
);
// Reload the cache from its new location.
simpleCache
=
new
SimpleCache
(
cacheDir2
,
new
NoOpCacheEvictor
());
// Read data back for KEY_1.
CacheSpan
cacheSpan3
=
simpleCache
.
startReadWrite
(
KEY_1
,
0
);
assertCachedDataReadCorrect
(
cacheSpan3
);
// Check the entry for KEY_2 was removed when the cache was reloaded.
assertThat
(
simpleCache
.
getCachedSpans
(
KEY_2
)).
isEmpty
();
Util
.
recursiveDelete
(
cacheDir2
);
}
@Test
public
void
testEncryptedIndex
()
throws
Exception
{
public
void
testEncryptedIndex
()
throws
Exception
{
byte
[]
key
=
"Bar12345Bar12345"
.
getBytes
(
C
.
UTF8_NAME
);
// 128 bit key
byte
[]
key
=
"Bar12345Bar12345"
.
getBytes
(
C
.
UTF8_NAME
);
// 128 bit key
SimpleCache
simpleCache
=
getEncryptedSimpleCache
(
key
);
SimpleCache
simpleCache
=
getEncryptedSimpleCache
(
key
);
...
...
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java
View file @
71f72c59
...
@@ -608,6 +608,12 @@ public final class DashMediaSource extends BaseMediaSource {
...
@@ -608,6 +608,12 @@ public final class DashMediaSource extends BaseMediaSource {
// MediaSource implementation.
// MediaSource implementation.
@Override
@Override
@Nullable
public
Object
getTag
()
{
return
tag
;
}
@Override
public
void
prepareSourceInternal
(
public
void
prepareSourceInternal
(
ExoPlayer
player
,
ExoPlayer
player
,
boolean
isTopLevelSource
,
boolean
isTopLevelSource
,
...
...
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java
View file @
71f72c59
...
@@ -391,6 +391,12 @@ public final class HlsMediaSource extends BaseMediaSource
...
@@ -391,6 +391,12 @@ public final class HlsMediaSource extends BaseMediaSource
}
}
@Override
@Override
@Nullable
public
Object
getTag
()
{
return
tag
;
}
@Override
public
void
prepareSourceInternal
(
public
void
prepareSourceInternal
(
ExoPlayer
player
,
ExoPlayer
player
,
boolean
isTopLevelSource
,
boolean
isTopLevelSource
,
...
...
library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java
View file @
71f72c59
...
@@ -504,6 +504,12 @@ public final class SsMediaSource extends BaseMediaSource
...
@@ -504,6 +504,12 @@ public final class SsMediaSource extends BaseMediaSource
// MediaSource implementation.
// MediaSource implementation.
@Override
@Override
@Nullable
public
Object
getTag
()
{
return
tag
;
}
@Override
public
void
prepareSourceInternal
(
public
void
prepareSourceInternal
(
ExoPlayer
player
,
ExoPlayer
player
,
boolean
isTopLevelSource
,
boolean
isTopLevelSource
,
...
...
library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerView.java
View file @
71f72c59
...
@@ -29,7 +29,6 @@ import android.graphics.drawable.BitmapDrawable;
...
@@ -29,7 +29,6 @@ import android.graphics.drawable.BitmapDrawable;
import
android.graphics.drawable.Drawable
;
import
android.graphics.drawable.Drawable
;
import
android.os.Looper
;
import
android.os.Looper
;
import
android.support.annotation.IntDef
;
import
android.support.annotation.IntDef
;
import
android.support.annotation.NonNull
;
import
android.support.annotation.Nullable
;
import
android.support.annotation.Nullable
;
import
android.support.v4.content.ContextCompat
;
import
android.support.v4.content.ContextCompat
;
import
android.util.AttributeSet
;
import
android.util.AttributeSet
;
...
@@ -187,8 +186,9 @@ import java.util.List;
...
@@ -187,8 +186,9 @@ import java.util.List;
* <li>Type: {@link AspectRatioFrameLayout}
* <li>Type: {@link AspectRatioFrameLayout}
* </ul>
* </ul>
* <li><b>{@code exo_shutter}</b> - A view that's made visible when video should be hidden. This
* <li><b>{@code exo_shutter}</b> - A view that's made visible when video should be hidden. This
* view is typically an opaque view that covers the video surface view, thereby obscuring it
* view is typically an opaque view that covers the video surface, thereby obscuring it when
* when visible.
* visible. Obscuring the surface in this way also helps to prevent flicker at the start of
* playback when {@code surface_type="surface_view"}.
* <ul>
* <ul>
* <li>Type: {@link View}
* <li>Type: {@link View}
* </ul>
* </ul>
...
@@ -271,13 +271,13 @@ public class PlayerView extends FrameLayout {
...
@@ -271,13 +271,13 @@ public class PlayerView extends FrameLayout {
private
static
final
int
SURFACE_TYPE_MONO360_VIEW
=
3
;
private
static
final
int
SURFACE_TYPE_MONO360_VIEW
=
3
;
// LINT.ThenChange(../../../../../../res/values/attrs.xml)
// LINT.ThenChange(../../../../../../res/values/attrs.xml)
private
final
AspectRatioFrameLayout
contentFrame
;
@Nullable
private
final
AspectRatioFrameLayout
contentFrame
;
private
final
View
shutterView
;
private
final
View
shutterView
;
private
final
View
surfaceView
;
@Nullable
private
final
View
surfaceView
;
private
final
ImageView
artworkView
;
private
final
ImageView
artworkView
;
private
final
SubtitleView
subtitleView
;
private
final
SubtitleView
subtitleView
;
private
final
@Nullable
View
bufferingView
;
@Nullable
private
final
View
bufferingView
;
private
final
@Nullable
TextView
errorMessageView
;
@Nullable
private
final
TextView
errorMessageView
;
private
final
PlayerControlView
controller
;
private
final
PlayerControlView
controller
;
private
final
ComponentListener
componentListener
;
private
final
ComponentListener
componentListener
;
private
final
FrameLayout
overlayFrameLayout
;
private
final
FrameLayout
overlayFrameLayout
;
...
@@ -285,11 +285,11 @@ public class PlayerView extends FrameLayout {
...
@@ -285,11 +285,11 @@ public class PlayerView extends FrameLayout {
private
Player
player
;
private
Player
player
;
private
boolean
useController
;
private
boolean
useController
;
private
boolean
useArtwork
;
private
boolean
useArtwork
;
private
@Nullabl
e
Drawable
defaultArtwork
;
@Nullable
privat
e
Drawable
defaultArtwork
;
private
@ShowBuffering
int
showBuffering
;
private
@ShowBuffering
int
showBuffering
;
private
boolean
keepContentOnPlayerReset
;
private
boolean
keepContentOnPlayerReset
;
private
@Nullabl
e
ErrorMessageProvider
<?
super
ExoPlaybackException
>
errorMessageProvider
;
@Nullable
privat
e
ErrorMessageProvider
<?
super
ExoPlaybackException
>
errorMessageProvider
;
private
@Nullabl
e
CharSequence
customErrorMessage
;
@Nullable
privat
e
CharSequence
customErrorMessage
;
private
int
controllerShowTimeoutMs
;
private
int
controllerShowTimeoutMs
;
private
boolean
controllerAutoShow
;
private
boolean
controllerAutoShow
;
private
boolean
controllerHideDuringAds
;
private
boolean
controllerHideDuringAds
;
...
@@ -474,9 +474,7 @@ public class PlayerView extends FrameLayout {
...
@@ -474,9 +474,7 @@ public class PlayerView extends FrameLayout {
* @param newPlayerView The new view to attach to the player.
* @param newPlayerView The new view to attach to the player.
*/
*/
public
static
void
switchTargetView
(
public
static
void
switchTargetView
(
@NonNull
Player
player
,
Player
player
,
@Nullable
PlayerView
oldPlayerView
,
@Nullable
PlayerView
newPlayerView
)
{
@Nullable
PlayerView
oldPlayerView
,
@Nullable
PlayerView
newPlayerView
)
{
if
(
oldPlayerView
==
newPlayerView
)
{
if
(
oldPlayerView
==
newPlayerView
)
{
return
;
return
;
}
}
...
@@ -1074,6 +1072,26 @@ public class PlayerView extends FrameLayout {
...
@@ -1074,6 +1072,26 @@ public class PlayerView extends FrameLayout {
}
}
}
}
/**
* Called when there's a change in the aspect ratio of the content being displayed. The default
* implementation sets the aspect ratio of the content frame to that of the content, unless the
* content view is a {@link SphericalSurfaceView} in which case the frame's aspect ratio is
* cleared.
*
* @param contentAspectRatio The aspect ratio of the content.
* @param contentFrame The content frame, or {@code null}.
* @param contentView The view that holds the content being displayed, or {@code null}.
*/
protected
void
onContentAspectRatioChanged
(
float
contentAspectRatio
,
@Nullable
AspectRatioFrameLayout
contentFrame
,
@Nullable
View
contentView
)
{
if
(
contentFrame
!=
null
)
{
contentFrame
.
setAspectRatio
(
contentView
instanceof
SphericalSurfaceView
?
0
:
contentAspectRatio
);
}
}
private
boolean
toggleControllerVisibility
()
{
private
boolean
toggleControllerVisibility
()
{
if
(!
useController
||
player
==
null
)
{
if
(!
useController
||
player
==
null
)
{
return
false
;
return
false
;
...
@@ -1187,9 +1205,8 @@ public class PlayerView extends FrameLayout {
...
@@ -1187,9 +1205,8 @@ public class PlayerView extends FrameLayout {
int
drawableWidth
=
drawable
.
getIntrinsicWidth
();
int
drawableWidth
=
drawable
.
getIntrinsicWidth
();
int
drawableHeight
=
drawable
.
getIntrinsicHeight
();
int
drawableHeight
=
drawable
.
getIntrinsicHeight
();
if
(
drawableWidth
>
0
&&
drawableHeight
>
0
)
{
if
(
drawableWidth
>
0
&&
drawableHeight
>
0
)
{
if
(
contentFrame
!=
null
)
{
float
artworkAspectRatio
=
(
float
)
drawableWidth
/
drawableHeight
;
contentFrame
.
setAspectRatio
((
float
)
drawableWidth
/
drawableHeight
);
onContentAspectRatioChanged
(
artworkAspectRatio
,
contentFrame
,
artworkView
);
}
artworkView
.
setImageDrawable
(
drawable
);
artworkView
.
setImageDrawable
(
drawable
);
artworkView
.
setVisibility
(
VISIBLE
);
artworkView
.
setVisibility
(
VISIBLE
);
return
true
;
return
true
;
...
@@ -1322,9 +1339,6 @@ public class PlayerView extends FrameLayout {
...
@@ -1322,9 +1339,6 @@ public class PlayerView extends FrameLayout {
@Override
@Override
public
void
onVideoSizeChanged
(
public
void
onVideoSizeChanged
(
int
width
,
int
height
,
int
unappliedRotationDegrees
,
float
pixelWidthHeightRatio
)
{
int
width
,
int
height
,
int
unappliedRotationDegrees
,
float
pixelWidthHeightRatio
)
{
if
(
contentFrame
==
null
)
{
return
;
}
float
videoAspectRatio
=
float
videoAspectRatio
=
(
height
==
0
||
width
==
0
)
?
1
:
(
width
*
pixelWidthHeightRatio
)
/
height
;
(
height
==
0
||
width
==
0
)
?
1
:
(
width
*
pixelWidthHeightRatio
)
/
height
;
...
@@ -1345,11 +1359,9 @@ public class PlayerView extends FrameLayout {
...
@@ -1345,11 +1359,9 @@ public class PlayerView extends FrameLayout {
surfaceView
.
addOnLayoutChangeListener
(
this
);
surfaceView
.
addOnLayoutChangeListener
(
this
);
}
}
applyTextureViewRotation
((
TextureView
)
surfaceView
,
textureViewRotation
);
applyTextureViewRotation
((
TextureView
)
surfaceView
,
textureViewRotation
);
}
else
if
(
surfaceView
instanceof
SphericalSurfaceView
)
{
videoAspectRatio
=
0
;
}
}
contentFrame
.
setAspectRatio
(
videoAspectRatio
);
onContentAspectRatioChanged
(
videoAspectRatio
,
contentFrame
,
surfaceView
);
}
}
@Override
@Override
...
...
testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaSource.java
View file @
71f72c59
...
@@ -89,6 +89,13 @@ public class FakeMediaSource extends BaseMediaSource {
...
@@ -89,6 +89,13 @@ public class FakeMediaSource extends BaseMediaSource {
}
}
@Override
@Override
@Nullable
public
Object
getTag
()
{
boolean
hasTimeline
=
timeline
!=
null
&&
!
timeline
.
isEmpty
();
return
hasTimeline
?
timeline
.
getWindow
(
0
,
new
Timeline
.
Window
()).
tag
:
null
;
}
@Override
public
synchronized
void
prepareSourceInternal
(
public
synchronized
void
prepareSourceInternal
(
ExoPlayer
player
,
ExoPlayer
player
,
boolean
isTopLevelSource
,
boolean
isTopLevelSource
,
...
...
testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java
View file @
71f72c59
...
@@ -50,6 +50,11 @@ public abstract class StubExoPlayer extends BasePlayer implements ExoPlayer {
...
@@ -50,6 +50,11 @@ public abstract class StubExoPlayer extends BasePlayer implements ExoPlayer {
}
}
@Override
@Override
public
MetadataComponent
getMetadataComponent
()
{
throw
new
UnsupportedOperationException
();
}
@Override
public
Looper
getPlaybackLooper
()
{
public
Looper
getPlaybackLooper
()
{
throw
new
UnsupportedOperationException
();
throw
new
UnsupportedOperationException
();
}
}
...
...
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