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
ab6f9aea
authored
Oct 20, 2017
by
ojw28
Committed by
GitHub
Oct 20, 2017
Browse files
Options
_('Browse Files')
Download
Plain Diff
Merge pull request #3381 from google/dev-v2-r2.5.4
r2.5.4
parents
1fdc11f2
04862bcc
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
290 additions
and
114 deletions
RELEASENOTES.md
constants.gradle
demo/src/main/AndroidManifest.xml
demo/src/main/assets/media.exolist.json
library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mp4/AtomParsersTest.java
library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java
library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java
library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java
library/core/src/main/java/com/google/android/exoplayer2/drm/FrameworkMediaCrypto.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultExtractorsFactory.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/Mp4Extractor.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/Track.java
library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java
library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java
library/hls/src/androidTest/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylistParserTest.java
library/hls/src/androidTest/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylistParserTest.java
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylist.java
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistTracker.java
testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaSource.java
RELEASENOTES.md
View file @
ab6f9aea
# Release notes #
# Release notes #
### r2.5.4 ###
*
Remove unnecessary media playlist fetches during playback of live HLS streams.
*
Add the ability to inject a HLS playlist parser through
`HlsMediaSource`
.
*
Fix potential
`IndexOutOfBoundsException`
when using
`ImaMediaSource`
(
[
#3334
](
https://github.com/google/ExoPlayer/issues/3334
)
).
*
Fix an issue parsing MP4 content containing non-CENC sinf boxes.
*
Fix memory leak when seeking with repeated periods.
*
Fix playback position when
`ExoPlayer.prepare`
is called with
`resetPosition`
set to false.
*
Ignore MP4 edit lists that seem invalid
(
[
#3351
](
https://github.com/google/ExoPlayer/issues/3351
)
).
*
Add extractor flag for ignoring all MP4 edit lists
(
[
#3358
](
https://github.com/google/ExoPlayer/issues/3358
)
).
*
Improve extensibility by exposing public constructors for
`FrameworkMediaCrypto`
and by making
`DefaultDashChunkSource.getNextChunk`
non-final.
### r2.5.3 ###
### r2.5.3 ###
*
IMA extension: Support skipping of skippable ads on AndroidTV and other
*
IMA extension: Support skipping of skippable ads on AndroidTV and other
...
...
constants.gradle
View file @
ab6f9aea
...
@@ -24,7 +24,7 @@ project.ext {
...
@@ -24,7 +24,7 @@ project.ext {
supportLibraryVersion
=
'25.4.0'
supportLibraryVersion
=
'25.4.0'
dexmakerVersion
=
'1.2'
dexmakerVersion
=
'1.2'
mockitoVersion
=
'1.9.5'
mockitoVersion
=
'1.9.5'
releaseVersion
=
'r2.5.
3
'
releaseVersion
=
'r2.5.
4
'
modulePrefix
=
':'
modulePrefix
=
':'
if
(
gradle
.
ext
.
has
(
'exoplayerModulePrefix'
))
{
if
(
gradle
.
ext
.
has
(
'exoplayerModulePrefix'
))
{
modulePrefix
+=
gradle
.
ext
.
exoplayerModulePrefix
modulePrefix
+=
gradle
.
ext
.
exoplayerModulePrefix
...
...
demo/src/main/AndroidManifest.xml
View file @
ab6f9aea
...
@@ -16,8 +16,8 @@
...
@@ -16,8 +16,8 @@
<manifest
xmlns:android=
"http://schemas.android.com/apk/res/android"
<manifest
xmlns:android=
"http://schemas.android.com/apk/res/android"
package=
"com.google.android.exoplayer2.demo"
package=
"com.google.android.exoplayer2.demo"
android:versionCode=
"250
3
"
android:versionCode=
"250
4
"
android:versionName=
"2.5.
3
"
>
android:versionName=
"2.5.
4
"
>
<uses-permission
android:name=
"android.permission.INTERNET"
/>
<uses-permission
android:name=
"android.permission.INTERNET"
/>
<uses-permission
android:name=
"android.permission.READ_EXTERNAL_STORAGE"
/>
<uses-permission
android:name=
"android.permission.READ_EXTERNAL_STORAGE"
/>
...
...
demo/src/main/assets/media.exolist.json
View file @
ab6f9aea
...
@@ -344,11 +344,11 @@
...
@@ -344,11 +344,11 @@
"samples"
:
[
"samples"
:
[
{
{
"name"
:
"Apple 4x3 basic stream"
,
"name"
:
"Apple 4x3 basic stream"
,
"uri"
:
"https://dev
images.apple.com.edgekey.net
/streaming/examples/bipbop_4x3/bipbop_4x3_variant.m3u8"
"uri"
:
"https://dev
streaming-cdn.apple.com/videos
/streaming/examples/bipbop_4x3/bipbop_4x3_variant.m3u8"
},
},
{
{
"name"
:
"Apple 16x9 basic stream"
,
"name"
:
"Apple 16x9 basic stream"
,
"uri"
:
"https://dev
images.apple.com.edgekey.net
/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8"
"uri"
:
"https://dev
streaming-cdn.apple.com/videos
/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8"
},
},
{
{
"name"
:
"Apple master playlist advanced (TS)"
,
"name"
:
"Apple master playlist advanced (TS)"
,
...
@@ -360,11 +360,11 @@
...
@@ -360,11 +360,11 @@
},
},
{
{
"name"
:
"Apple TS media playlist"
,
"name"
:
"Apple TS media playlist"
,
"uri"
:
"https://dev
images.apple.com.edgekey.net
/streaming/examples/bipbop_4x3/gear1/prog_index.m3u8"
"uri"
:
"https://dev
streaming-cdn.apple.com/videos
/streaming/examples/bipbop_4x3/gear1/prog_index.m3u8"
},
},
{
{
"name"
:
"Apple AAC media playlist"
,
"name"
:
"Apple AAC media playlist"
,
"uri"
:
"https://dev
images.apple.com.edgekey.net
/streaming/examples/bipbop_4x3/gear0/prog_index.m3u8"
"uri"
:
"https://dev
streaming-cdn.apple.com/videos
/streaming/examples/bipbop_4x3/gear0/prog_index.m3u8"
},
},
{
{
"name"
:
"Apple ID3 metadata"
,
"name"
:
"Apple ID3 metadata"
,
...
@@ -381,11 +381,11 @@
...
@@ -381,11 +381,11 @@
},
},
{
{
"name"
:
"Apple AAC 10s"
,
"name"
:
"Apple AAC 10s"
,
"uri"
:
"https://dev
images.apple.com.edgekey.net
/streaming/examples/bipbop_4x3/gear0/fileSequence0.aac"
"uri"
:
"https://dev
streaming-cdn.apple.com/videos
/streaming/examples/bipbop_4x3/gear0/fileSequence0.aac"
},
},
{
{
"name"
:
"Apple TS 10s"
,
"name"
:
"Apple TS 10s"
,
"uri"
:
"https://dev
images.apple.com.edgekey.net
/streaming/examples/bipbop_4x3/gear1/fileSequence0.ts"
"uri"
:
"https://dev
streaming-cdn.apple.com/videos
/streaming/examples/bipbop_4x3/gear1/fileSequence0.ts"
},
},
{
{
"name"
:
"Android screens (Matroska)"
,
"name"
:
"Android screens (Matroska)"
,
...
...
library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mp4/AtomParsersTest.java
View file @
ab6f9aea
...
@@ -34,18 +34,18 @@ public final class AtomParsersTest extends TestCase {
...
@@ -34,18 +34,18 @@ public final class AtomParsersTest extends TestCase {
+
SAMPLE_COUNT
+
"0001000200030004"
);
+
SAMPLE_COUNT
+
"0001000200030004"
);
public
void
testStz2Parsing4BitFieldSize
()
{
public
void
testStz2Parsing4BitFieldSize
()
{
verifyParsing
(
new
Atom
.
LeafAtom
(
Atom
.
TYPE_stsz
,
new
ParsableByteArray
(
FOUR_BIT_STZ2
)));
verify
Stz2
Parsing
(
new
Atom
.
LeafAtom
(
Atom
.
TYPE_stsz
,
new
ParsableByteArray
(
FOUR_BIT_STZ2
)));
}
}
public
void
testStz2Parsing8BitFieldSize
()
{
public
void
testStz2Parsing8BitFieldSize
()
{
verifyParsing
(
new
Atom
.
LeafAtom
(
Atom
.
TYPE_stsz
,
new
ParsableByteArray
(
EIGHT_BIT_STZ2
)));
verify
Stz2
Parsing
(
new
Atom
.
LeafAtom
(
Atom
.
TYPE_stsz
,
new
ParsableByteArray
(
EIGHT_BIT_STZ2
)));
}
}
public
void
testStz2Parsing16BitFieldSize
()
{
public
void
testStz2Parsing16BitFieldSize
()
{
verifyParsing
(
new
Atom
.
LeafAtom
(
Atom
.
TYPE_stsz
,
new
ParsableByteArray
(
SIXTEEN_BIT_STZ2
)));
verify
Stz2
Parsing
(
new
Atom
.
LeafAtom
(
Atom
.
TYPE_stsz
,
new
ParsableByteArray
(
SIXTEEN_BIT_STZ2
)));
}
}
private
void
verify
Parsing
(
Atom
.
LeafAtom
stz2Atom
)
{
private
static
void
verifyStz2
Parsing
(
Atom
.
LeafAtom
stz2Atom
)
{
AtomParsers
.
Stz2SampleSizeBox
box
=
new
AtomParsers
.
Stz2SampleSizeBox
(
stz2Atom
);
AtomParsers
.
Stz2SampleSizeBox
box
=
new
AtomParsers
.
Stz2SampleSizeBox
(
stz2Atom
);
assertEquals
(
4
,
box
.
getSampleCount
());
assertEquals
(
4
,
box
.
getSampleCount
());
assertFalse
(
box
.
isFixedSampleSize
());
assertFalse
(
box
.
isFixedSampleSize
());
...
...
library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java
View file @
ab6f9aea
...
@@ -356,17 +356,17 @@ import java.util.concurrent.CopyOnWriteArraySet;
...
@@ -356,17 +356,17 @@ import java.util.concurrent.CopyOnWriteArraySet;
@Override
@Override
public
boolean
isPlayingAd
()
{
public
boolean
isPlayingAd
()
{
return
pendingSeekAcks
==
0
&&
playbackInfo
.
periodId
.
isAd
();
return
!
timeline
.
isEmpty
()
&&
pendingSeekAcks
==
0
&&
playbackInfo
.
periodId
.
isAd
();
}
}
@Override
@Override
public
int
getCurrentAdGroupIndex
()
{
public
int
getCurrentAdGroupIndex
()
{
return
pendingSeekAcks
==
0
?
playbackInfo
.
periodId
.
adGroupIndex
:
C
.
INDEX_UNSET
;
return
isPlayingAd
()
?
playbackInfo
.
periodId
.
adGroupIndex
:
C
.
INDEX_UNSET
;
}
}
@Override
@Override
public
int
getCurrentAdIndexInAdGroup
()
{
public
int
getCurrentAdIndexInAdGroup
()
{
return
pendingSeekAcks
==
0
?
playbackInfo
.
periodId
.
adIndexInAdGroup
:
C
.
INDEX_UNSET
;
return
isPlayingAd
()
?
playbackInfo
.
periodId
.
adIndexInAdGroup
:
C
.
INDEX_UNSET
;
}
}
@Override
@Override
...
...
library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java
View file @
ab6f9aea
...
@@ -430,6 +430,10 @@ import java.io.IOException;
...
@@ -430,6 +430,10 @@ import java.io.IOException;
loadControl
.
onPrepared
();
loadControl
.
onPrepared
();
if
(
resetPosition
)
{
if
(
resetPosition
)
{
playbackInfo
=
new
PlaybackInfo
(
0
,
C
.
TIME_UNSET
);
playbackInfo
=
new
PlaybackInfo
(
0
,
C
.
TIME_UNSET
);
}
else
{
// The new start position is the current playback position.
playbackInfo
=
new
PlaybackInfo
(
playbackInfo
.
periodId
,
playbackInfo
.
positionUs
,
playbackInfo
.
contentPositionUs
);
}
}
this
.
mediaSource
=
mediaSource
;
this
.
mediaSource
=
mediaSource
;
mediaSource
.
prepareSource
(
player
,
true
,
this
);
mediaSource
.
prepareSource
(
player
,
true
,
this
);
...
@@ -719,7 +723,8 @@ import java.io.IOException;
...
@@ -719,7 +723,8 @@ import java.io.IOException;
// Clear the timeline, but keep the requested period if it is already prepared.
// Clear the timeline, but keep the requested period if it is already prepared.
MediaPeriodHolder
periodHolder
=
playingPeriodHolder
;
MediaPeriodHolder
periodHolder
=
playingPeriodHolder
;
while
(
periodHolder
!=
null
)
{
while
(
periodHolder
!=
null
)
{
if
(
shouldKeepPeriodHolder
(
periodId
,
periodPositionUs
,
periodHolder
))
{
if
(
newPlayingPeriodHolder
==
null
&&
shouldKeepPeriodHolder
(
periodId
,
periodPositionUs
,
periodHolder
))
{
newPlayingPeriodHolder
=
periodHolder
;
newPlayingPeriodHolder
=
periodHolder
;
}
else
{
}
else
{
periodHolder
.
release
();
periodHolder
.
release
();
...
...
library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java
View file @
ab6f9aea
...
@@ -31,13 +31,13 @@ public final class ExoPlayerLibraryInfo {
...
@@ -31,13 +31,13 @@ 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.5.
3
"
;
public
static
final
String
VERSION
=
"2.5.
4
"
;
/**
/**
* 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.5.
3
"
;
public
static
final
String
VERSION_SLASHY
=
"ExoPlayerLib/2.5.
4
"
;
/**
/**
* The version of the library expressed as an integer, for example 1002003.
* The version of the library expressed as an integer, for example 1002003.
...
@@ -47,7 +47,7 @@ public final class ExoPlayerLibraryInfo {
...
@@ -47,7 +47,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
=
200500
3
;
public
static
final
int
VERSION_INT
=
200500
4
;
/**
/**
* 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/drm/FrameworkMediaCrypto.java
View file @
ab6f9aea
...
@@ -28,12 +28,29 @@ public final class FrameworkMediaCrypto implements ExoMediaCrypto {
...
@@ -28,12 +28,29 @@ public final class FrameworkMediaCrypto implements ExoMediaCrypto {
private
final
MediaCrypto
mediaCrypto
;
private
final
MediaCrypto
mediaCrypto
;
private
final
boolean
forceAllowInsecureDecoderComponents
;
private
final
boolean
forceAllowInsecureDecoderComponents
;
/* package */
FrameworkMediaCrypto
(
MediaCrypto
mediaCrypto
,
/**
* @param mediaCrypto The {@link MediaCrypto} to wrap.
*/
public
FrameworkMediaCrypto
(
MediaCrypto
mediaCrypto
)
{
this
(
mediaCrypto
,
false
);
}
/**
* @param mediaCrypto The {@link MediaCrypto} to wrap.
* @param forceAllowInsecureDecoderComponents Whether to force
* {@link #requiresSecureDecoderComponent(String)} to return {@code false}, rather than
* {@link MediaCrypto#requiresSecureDecoderComponent(String)} of the wrapped
* {@link MediaCrypto}.
*/
public
FrameworkMediaCrypto
(
MediaCrypto
mediaCrypto
,
boolean
forceAllowInsecureDecoderComponents
)
{
boolean
forceAllowInsecureDecoderComponents
)
{
this
.
mediaCrypto
=
Assertions
.
checkNotNull
(
mediaCrypto
);
this
.
mediaCrypto
=
Assertions
.
checkNotNull
(
mediaCrypto
);
this
.
forceAllowInsecureDecoderComponents
=
forceAllowInsecureDecoderComponents
;
this
.
forceAllowInsecureDecoderComponents
=
forceAllowInsecureDecoderComponents
;
}
}
/**
* Returns the wrapped {@link MediaCrypto}.
*/
public
MediaCrypto
getWrappedMediaCrypto
()
{
public
MediaCrypto
getWrappedMediaCrypto
()
{
return
mediaCrypto
;
return
mediaCrypto
;
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultExtractorsFactory.java
View file @
ab6f9aea
...
@@ -67,6 +67,7 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory {
...
@@ -67,6 +67,7 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory {
}
}
private
@MatroskaExtractor
.
Flags
int
matroskaFlags
;
private
@MatroskaExtractor
.
Flags
int
matroskaFlags
;
private
@Mp4Extractor
.
Flags
int
mp4Flags
;
private
@FragmentedMp4Extractor
.
Flags
int
fragmentedMp4Flags
;
private
@FragmentedMp4Extractor
.
Flags
int
fragmentedMp4Flags
;
private
@Mp3Extractor
.
Flags
int
mp3Flags
;
private
@Mp3Extractor
.
Flags
int
mp3Flags
;
private
@TsExtractor
.
Mode
int
tsMode
;
private
@TsExtractor
.
Mode
int
tsMode
;
...
@@ -90,6 +91,18 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory {
...
@@ -90,6 +91,18 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory {
}
}
/**
/**
* Sets flags for {@link Mp4Extractor} instances created by the factory.
*
* @see Mp4Extractor#Mp4Extractor(int)
* @param flags The flags to use.
* @return The factory, for convenience.
*/
public
synchronized
DefaultExtractorsFactory
setMp4ExtractorFlags
(
@Mp4Extractor
.
Flags
int
flags
)
{
this
.
mp4Flags
=
flags
;
return
this
;
}
/**
* Sets flags for {@link FragmentedMp4Extractor} instances created by the factory.
* Sets flags for {@link FragmentedMp4Extractor} instances created by the factory.
*
*
* @see FragmentedMp4Extractor#FragmentedMp4Extractor(int)
* @see FragmentedMp4Extractor#FragmentedMp4Extractor(int)
...
@@ -145,7 +158,7 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory {
...
@@ -145,7 +158,7 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory {
Extractor
[]
extractors
=
new
Extractor
[
FLAC_EXTRACTOR_CONSTRUCTOR
==
null
?
11
:
12
];
Extractor
[]
extractors
=
new
Extractor
[
FLAC_EXTRACTOR_CONSTRUCTOR
==
null
?
11
:
12
];
extractors
[
0
]
=
new
MatroskaExtractor
(
matroskaFlags
);
extractors
[
0
]
=
new
MatroskaExtractor
(
matroskaFlags
);
extractors
[
1
]
=
new
FragmentedMp4Extractor
(
fragmentedMp4Flags
);
extractors
[
1
]
=
new
FragmentedMp4Extractor
(
fragmentedMp4Flags
);
extractors
[
2
]
=
new
Mp4Extractor
();
extractors
[
2
]
=
new
Mp4Extractor
(
mp4Flags
);
extractors
[
3
]
=
new
Mp3Extractor
(
mp3Flags
);
extractors
[
3
]
=
new
Mp3Extractor
(
mp3Flags
);
extractors
[
4
]
=
new
AdtsExtractor
();
extractors
[
4
]
=
new
AdtsExtractor
();
extractors
[
5
]
=
new
Ac3Extractor
();
extractors
[
5
]
=
new
Ac3Extractor
();
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java
View file @
ab6f9aea
...
@@ -60,11 +60,13 @@ import java.util.List;
...
@@ -60,11 +60,13 @@ import java.util.List;
* @param duration The duration in units of the timescale declared in the mvhd atom, or
* @param duration The duration in units of the timescale declared in the mvhd atom, or
* {@link C#TIME_UNSET} if the duration should be parsed from the tkhd atom.
* {@link C#TIME_UNSET} if the duration should be parsed from the tkhd atom.
* @param drmInitData {@link DrmInitData} to be included in the format.
* @param drmInitData {@link DrmInitData} to be included in the format.
* @param ignoreEditLists Whether to ignore any edit lists in the trak box.
* @param isQuickTime True for QuickTime media. False otherwise.
* @param isQuickTime True for QuickTime media. False otherwise.
* @return A {@link Track} instance, or {@code null} if the track's type isn't supported.
* @return A {@link Track} instance, or {@code null} if the track's type isn't supported.
*/
*/
public
static
Track
parseTrak
(
Atom
.
ContainerAtom
trak
,
Atom
.
LeafAtom
mvhd
,
long
duration
,
public
static
Track
parseTrak
(
Atom
.
ContainerAtom
trak
,
Atom
.
LeafAtom
mvhd
,
long
duration
,
DrmInitData
drmInitData
,
boolean
isQuickTime
)
throws
ParserException
{
DrmInitData
drmInitData
,
boolean
ignoreEditLists
,
boolean
isQuickTime
)
throws
ParserException
{
Atom
.
ContainerAtom
mdia
=
trak
.
getContainerAtomOfType
(
Atom
.
TYPE_mdia
);
Atom
.
ContainerAtom
mdia
=
trak
.
getContainerAtomOfType
(
Atom
.
TYPE_mdia
);
int
trackType
=
parseHdlr
(
mdia
.
getLeafAtomOfType
(
Atom
.
TYPE_hdlr
).
data
);
int
trackType
=
parseHdlr
(
mdia
.
getLeafAtomOfType
(
Atom
.
TYPE_hdlr
).
data
);
if
(
trackType
==
C
.
TRACK_TYPE_UNKNOWN
)
{
if
(
trackType
==
C
.
TRACK_TYPE_UNKNOWN
)
{
...
@@ -88,11 +90,17 @@ import java.util.List;
...
@@ -88,11 +90,17 @@ import java.util.List;
Pair
<
Long
,
String
>
mdhdData
=
parseMdhd
(
mdia
.
getLeafAtomOfType
(
Atom
.
TYPE_mdhd
).
data
);
Pair
<
Long
,
String
>
mdhdData
=
parseMdhd
(
mdia
.
getLeafAtomOfType
(
Atom
.
TYPE_mdhd
).
data
);
StsdData
stsdData
=
parseStsd
(
stbl
.
getLeafAtomOfType
(
Atom
.
TYPE_stsd
).
data
,
tkhdData
.
id
,
StsdData
stsdData
=
parseStsd
(
stbl
.
getLeafAtomOfType
(
Atom
.
TYPE_stsd
).
data
,
tkhdData
.
id
,
tkhdData
.
rotationDegrees
,
mdhdData
.
second
,
drmInitData
,
isQuickTime
);
tkhdData
.
rotationDegrees
,
mdhdData
.
second
,
drmInitData
,
isQuickTime
);
Pair
<
long
[],
long
[]>
edtsData
=
parseEdts
(
trak
.
getContainerAtomOfType
(
Atom
.
TYPE_edts
));
long
[]
editListDurations
=
null
;
long
[]
editListMediaTimes
=
null
;
if
(!
ignoreEditLists
)
{
Pair
<
long
[],
long
[]>
edtsData
=
parseEdts
(
trak
.
getContainerAtomOfType
(
Atom
.
TYPE_edts
));
editListDurations
=
edtsData
.
first
;
editListMediaTimes
=
edtsData
.
second
;
}
return
stsdData
.
format
==
null
?
null
return
stsdData
.
format
==
null
?
null
:
new
Track
(
tkhdData
.
id
,
trackType
,
mdhdData
.
first
,
movieTimescale
,
durationUs
,
:
new
Track
(
tkhdData
.
id
,
trackType
,
mdhdData
.
first
,
movieTimescale
,
durationUs
,
stsdData
.
format
,
stsdData
.
requiredSampleTransformation
,
stsdData
.
trackEncryptionBoxes
,
stsdData
.
format
,
stsdData
.
requiredSampleTransformation
,
stsdData
.
trackEncryptionBoxes
,
stsdData
.
nalUnitLengthFieldLength
,
ed
tsData
.
first
,
edtsData
.
second
);
stsdData
.
nalUnitLengthFieldLength
,
ed
itListDurations
,
editListMediaTimes
);
}
}
/**
/**
...
@@ -395,7 +403,11 @@ import java.util.List;
...
@@ -395,7 +403,11 @@ import java.util.List;
hasSyncSample
|=
(
editedFlags
[
i
]
&
C
.
BUFFER_FLAG_KEY_FRAME
)
!=
0
;
hasSyncSample
|=
(
editedFlags
[
i
]
&
C
.
BUFFER_FLAG_KEY_FRAME
)
!=
0
;
}
}
if
(!
hasSyncSample
)
{
if
(!
hasSyncSample
)
{
throw
new
ParserException
(
"The edited sample sequence does not contain a sync sample."
);
// We don't support edit lists where the edited sample sequence doesn't contain a sync sample.
// Such edit lists are often (although not always) broken, so we ignore it and continue.
Log
.
w
(
TAG
,
"Ignoring edit list: Edited sample sequence does not contain a sync sample."
);
Util
.
scaleLargeTimestampsInPlace
(
timestamps
,
C
.
MICROS_PER_SECOND
,
track
.
timescale
);
return
new
TrackSampleTable
(
offsets
,
sizes
,
maximumSize
,
timestamps
,
flags
);
}
}
return
new
TrackSampleTable
(
editedOffsets
,
editedSizes
,
editedMaximumSize
,
editedTimestamps
,
return
new
TrackSampleTable
(
editedOffsets
,
editedSizes
,
editedMaximumSize
,
editedTimestamps
,
...
@@ -779,7 +791,7 @@ import java.util.List;
...
@@ -779,7 +791,7 @@ import java.util.List;
*
*
* @param edtsAtom edts (edit box) atom to decode.
* @param edtsAtom edts (edit box) atom to decode.
* @return Pair of edit list durations and edit list media times, or a pair of nulls if they are
* @return Pair of edit list durations and edit list media times, or a pair of nulls if they are
* not present.
*
not present.
*/
*/
private
static
Pair
<
long
[],
long
[]>
parseEdts
(
Atom
.
ContainerAtom
edtsAtom
)
{
private
static
Pair
<
long
[],
long
[]>
parseEdts
(
Atom
.
ContainerAtom
edtsAtom
)
{
Atom
.
LeafAtom
elst
;
Atom
.
LeafAtom
elst
;
...
@@ -1060,8 +1072,8 @@ import java.util.List;
...
@@ -1060,8 +1072,8 @@ import java.util.List;
Assertions
.
checkArgument
(
childAtomSize
>
0
,
"childAtomSize should be positive"
);
Assertions
.
checkArgument
(
childAtomSize
>
0
,
"childAtomSize should be positive"
);
int
childAtomType
=
parent
.
readInt
();
int
childAtomType
=
parent
.
readInt
();
if
(
childAtomType
==
Atom
.
TYPE_sinf
)
{
if
(
childAtomType
==
Atom
.
TYPE_sinf
)
{
Pair
<
Integer
,
TrackEncryptionBox
>
result
=
parse
SinfFromParent
(
parent
,
childPosition
,
Pair
<
Integer
,
TrackEncryptionBox
>
result
=
parse
CommonEncryptionSinfFromParent
(
parent
,
childAtomSize
);
child
Position
,
child
AtomSize
);
if
(
result
!=
null
)
{
if
(
result
!=
null
)
{
return
result
;
return
result
;
}
}
...
@@ -1071,8 +1083,8 @@ import java.util.List;
...
@@ -1071,8 +1083,8 @@ import java.util.List;
return
null
;
return
null
;
}
}
private
static
Pair
<
Integer
,
TrackEncryptionBox
>
parseSinfFromParent
(
ParsableByteArray
parent
,
/* package */
static
Pair
<
Integer
,
TrackEncryptionBox
>
parseCommonEncryptionSinfFromParent
(
int
position
,
int
size
)
{
ParsableByteArray
parent
,
int
position
,
int
size
)
{
int
childPosition
=
position
+
Atom
.
HEADER_SIZE
;
int
childPosition
=
position
+
Atom
.
HEADER_SIZE
;
int
schemeInformationBoxPosition
=
C
.
POSITION_UNSET
;
int
schemeInformationBoxPosition
=
C
.
POSITION_UNSET
;
int
schemeInformationBoxSize
=
0
;
int
schemeInformationBoxSize
=
0
;
...
@@ -1086,7 +1098,7 @@ import java.util.List;
...
@@ -1086,7 +1098,7 @@ import java.util.List;
dataFormat
=
parent
.
readInt
();
dataFormat
=
parent
.
readInt
();
}
else
if
(
childAtomType
==
Atom
.
TYPE_schm
)
{
}
else
if
(
childAtomType
==
Atom
.
TYPE_schm
)
{
parent
.
skipBytes
(
4
);
parent
.
skipBytes
(
4
);
//
scheme_type field. D
efined in ISO/IEC 23001-7:2016, section 4.1.
//
Common encryption scheme_type values are d
efined in ISO/IEC 23001-7:2016, section 4.1.
schemeType
=
parent
.
readString
(
4
);
schemeType
=
parent
.
readString
(
4
);
}
else
if
(
childAtomType
==
Atom
.
TYPE_schi
)
{
}
else
if
(
childAtomType
==
Atom
.
TYPE_schi
)
{
schemeInformationBoxPosition
=
childPosition
;
schemeInformationBoxPosition
=
childPosition
;
...
@@ -1095,7 +1107,8 @@ import java.util.List;
...
@@ -1095,7 +1107,8 @@ import java.util.List;
childPosition
+=
childAtomSize
;
childPosition
+=
childAtomSize
;
}
}
if
(
schemeType
!=
null
)
{
if
(
C
.
CENC_TYPE_cenc
.
equals
(
schemeType
)
||
C
.
CENC_TYPE_cbc1
.
equals
(
schemeType
)
||
C
.
CENC_TYPE_cens
.
equals
(
schemeType
)
||
C
.
CENC_TYPE_cbcs
.
equals
(
schemeType
))
{
Assertions
.
checkArgument
(
dataFormat
!=
null
,
"frma atom is mandatory"
);
Assertions
.
checkArgument
(
dataFormat
!=
null
,
"frma atom is mandatory"
);
Assertions
.
checkArgument
(
schemeInformationBoxPosition
!=
C
.
POSITION_UNSET
,
Assertions
.
checkArgument
(
schemeInformationBoxPosition
!=
C
.
POSITION_UNSET
,
"schi atom is mandatory"
);
"schi atom is mandatory"
);
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java
View file @
ab6f9aea
...
@@ -74,7 +74,7 @@ public final class FragmentedMp4Extractor implements Extractor {
...
@@ -74,7 +74,7 @@ public final class FragmentedMp4Extractor implements Extractor {
@Retention
(
RetentionPolicy
.
SOURCE
)
@Retention
(
RetentionPolicy
.
SOURCE
)
@IntDef
(
flag
=
true
,
value
=
{
FLAG_WORKAROUND_EVERY_VIDEO_FRAME_IS_SYNC_FRAME
,
@IntDef
(
flag
=
true
,
value
=
{
FLAG_WORKAROUND_EVERY_VIDEO_FRAME_IS_SYNC_FRAME
,
FLAG_WORKAROUND_IGNORE_TFDT_BOX
,
FLAG_ENABLE_EMSG_TRACK
,
FLAG_ENABLE_CEA608_TRACK
,
FLAG_WORKAROUND_IGNORE_TFDT_BOX
,
FLAG_ENABLE_EMSG_TRACK
,
FLAG_ENABLE_CEA608_TRACK
,
FLAG_SIDELOADED
})
FLAG_SIDELOADED
,
FLAG_WORKAROUND_IGNORE_EDIT_LISTS
})
public
@interface
Flags
{}
public
@interface
Flags
{}
/**
/**
* Flag to work around an issue in some video streams where every frame is marked as a sync frame.
* Flag to work around an issue in some video streams where every frame is marked as a sync frame.
...
@@ -103,6 +103,10 @@ public final class FragmentedMp4Extractor implements Extractor {
...
@@ -103,6 +103,10 @@ public final class FragmentedMp4Extractor implements Extractor {
* container.
* container.
*/
*/
private
static
final
int
FLAG_SIDELOADED
=
16
;
private
static
final
int
FLAG_SIDELOADED
=
16
;
/**
* Flag to ignore any edit lists in the stream.
*/
public
static
final
int
FLAG_WORKAROUND_IGNORE_EDIT_LISTS
=
32
;
private
static
final
String
TAG
=
"FragmentedMp4Extractor"
;
private
static
final
String
TAG
=
"FragmentedMp4Extractor"
;
private
static
final
int
SAMPLE_GROUP_TYPE_seig
=
Util
.
getIntegerCodeForString
(
"seig"
);
private
static
final
int
SAMPLE_GROUP_TYPE_seig
=
Util
.
getIntegerCodeForString
(
"seig"
);
...
@@ -426,7 +430,7 @@ public final class FragmentedMp4Extractor implements Extractor {
...
@@ -426,7 +430,7 @@ public final class FragmentedMp4Extractor implements Extractor {
Atom
.
ContainerAtom
atom
=
moov
.
containerChildren
.
get
(
i
);
Atom
.
ContainerAtom
atom
=
moov
.
containerChildren
.
get
(
i
);
if
(
atom
.
type
==
Atom
.
TYPE_trak
)
{
if
(
atom
.
type
==
Atom
.
TYPE_trak
)
{
Track
track
=
AtomParsers
.
parseTrak
(
atom
,
moov
.
getLeafAtomOfType
(
Atom
.
TYPE_mvhd
),
duration
,
Track
track
=
AtomParsers
.
parseTrak
(
atom
,
moov
.
getLeafAtomOfType
(
Atom
.
TYPE_mvhd
),
duration
,
drmInitData
,
false
);
drmInitData
,
(
flags
&
FLAG_WORKAROUND_IGNORE_EDIT_LISTS
)
!=
0
,
false
);
if
(
track
!=
null
)
{
if
(
track
!=
null
)
{
tracks
.
put
(
track
.
id
,
track
);
tracks
.
put
(
track
.
id
,
track
);
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/Mp4Extractor.java
View file @
ab6f9aea
...
@@ -28,6 +28,7 @@ import com.google.android.exoplayer2.extractor.PositionHolder;
...
@@ -28,6 +28,7 @@ import com.google.android.exoplayer2.extractor.PositionHolder;
import
com.google.android.exoplayer2.extractor.SeekMap
;
import
com.google.android.exoplayer2.extractor.SeekMap
;
import
com.google.android.exoplayer2.extractor.TrackOutput
;
import
com.google.android.exoplayer2.extractor.TrackOutput
;
import
com.google.android.exoplayer2.extractor.mp4.Atom.ContainerAtom
;
import
com.google.android.exoplayer2.extractor.mp4.Atom.ContainerAtom
;
import
com.google.android.exoplayer2.extractor.mp4.FragmentedMp4Extractor.Flags
;
import
com.google.android.exoplayer2.metadata.Metadata
;
import
com.google.android.exoplayer2.metadata.Metadata
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.NalUnitUtil
;
import
com.google.android.exoplayer2.util.NalUnitUtil
;
...
@@ -58,6 +59,17 @@ public final class Mp4Extractor implements Extractor, SeekMap {
...
@@ -58,6 +59,17 @@ public final class Mp4Extractor implements Extractor, SeekMap {
};
};
/**
/**
* Flags controlling the behavior of the extractor.
*/
@Retention
(
RetentionPolicy
.
SOURCE
)
@IntDef
(
flag
=
true
,
value
=
{
FLAG_WORKAROUND_IGNORE_EDIT_LISTS
})
public
@interface
Flags
{}
/**
* Flag to ignore any edit lists in the stream.
*/
public
static
final
int
FLAG_WORKAROUND_IGNORE_EDIT_LISTS
=
1
;
/**
* Parser states.
* Parser states.
*/
*/
@Retention
(
RetentionPolicy
.
SOURCE
)
@Retention
(
RetentionPolicy
.
SOURCE
)
...
@@ -76,6 +88,8 @@ public final class Mp4Extractor implements Extractor, SeekMap {
...
@@ -76,6 +88,8 @@ public final class Mp4Extractor implements Extractor, SeekMap {
*/
*/
private
static
final
long
RELOAD_MINIMUM_SEEK_DISTANCE
=
256
*
1024
;
private
static
final
long
RELOAD_MINIMUM_SEEK_DISTANCE
=
256
*
1024
;
private
final
@Flags
int
flags
;
// Temporary arrays.
// Temporary arrays.
private
final
ParsableByteArray
nalStartCode
;
private
final
ParsableByteArray
nalStartCode
;
private
final
ParsableByteArray
nalLength
;
private
final
ParsableByteArray
nalLength
;
...
@@ -98,7 +112,21 @@ public final class Mp4Extractor implements Extractor, SeekMap {
...
@@ -98,7 +112,21 @@ public final class Mp4Extractor implements Extractor, SeekMap {
private
long
durationUs
;
private
long
durationUs
;
private
boolean
isQuickTime
;
private
boolean
isQuickTime
;
/**
* Creates a new extractor for unfragmented MP4 streams.
*/
public
Mp4Extractor
()
{
public
Mp4Extractor
()
{
this
(
0
);
}
/**
* Creates a new extractor for unfragmented MP4 streams, using the specified flags to control the
* extractor's behavior.
*
* @param flags Flags that control the extractor's behavior.
*/
public
Mp4Extractor
(
@Flags
int
flags
)
{
this
.
flags
=
flags
;
atomHeader
=
new
ParsableByteArray
(
Atom
.
LONG_HEADER_SIZE
);
atomHeader
=
new
ParsableByteArray
(
Atom
.
LONG_HEADER_SIZE
);
containerAtoms
=
new
Stack
<>();
containerAtoms
=
new
Stack
<>();
nalStartCode
=
new
ParsableByteArray
(
NalUnitUtil
.
NAL_START_CODE
);
nalStartCode
=
new
ParsableByteArray
(
NalUnitUtil
.
NAL_START_CODE
);
...
@@ -345,7 +373,7 @@ public final class Mp4Extractor implements Extractor, SeekMap {
...
@@ -345,7 +373,7 @@ public final class Mp4Extractor implements Extractor, SeekMap {
}
}
Track
track
=
AtomParsers
.
parseTrak
(
atom
,
moov
.
getLeafAtomOfType
(
Atom
.
TYPE_mvhd
),
Track
track
=
AtomParsers
.
parseTrak
(
atom
,
moov
.
getLeafAtomOfType
(
Atom
.
TYPE_mvhd
),
C
.
TIME_UNSET
,
null
,
isQuickTime
);
C
.
TIME_UNSET
,
null
,
(
flags
&
FLAG_WORKAROUND_IGNORE_EDIT_LISTS
)
!=
0
,
isQuickTime
);
if
(
track
==
null
)
{
if
(
track
==
null
)
{
continue
;
continue
;
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/Track.java
View file @
ab6f9aea
...
@@ -81,12 +81,12 @@ public final class Track {
...
@@ -81,12 +81,12 @@ public final class Track {
/**
/**
* Durations of edit list segments in the movie timescale. Null if there is no edit list.
* Durations of edit list segments in the movie timescale. Null if there is no edit list.
*/
*/
public
final
long
[]
editListDurations
;
@Nullable
public
final
long
[]
editListDurations
;
/**
/**
* Media times for edit list segments in the track timescale. Null if there is no edit list.
* Media times for edit list segments in the track timescale. Null if there is no edit list.
*/
*/
public
final
long
[]
editListMediaTimes
;
@Nullable
public
final
long
[]
editListMediaTimes
;
/**
/**
* For H264 video tracks, the length in bytes of the NALUnitLength field in each sample. 0 for
* For H264 video tracks, the length in bytes of the NALUnitLength field in each sample. 0 for
...
@@ -99,7 +99,7 @@ public final class Track {
...
@@ -99,7 +99,7 @@ public final class Track {
public
Track
(
int
id
,
int
type
,
long
timescale
,
long
movieTimescale
,
long
durationUs
,
public
Track
(
int
id
,
int
type
,
long
timescale
,
long
movieTimescale
,
long
durationUs
,
Format
format
,
@Transformation
int
sampleTransformation
,
Format
format
,
@Transformation
int
sampleTransformation
,
@Nullable
TrackEncryptionBox
[]
sampleDescriptionEncryptionBoxes
,
int
nalUnitLengthFieldLength
,
@Nullable
TrackEncryptionBox
[]
sampleDescriptionEncryptionBoxes
,
int
nalUnitLengthFieldLength
,
long
[]
editListDurations
,
long
[]
editListMediaTimes
)
{
@Nullable
long
[]
editListDurations
,
@Nullable
long
[]
editListMediaTimes
)
{
this
.
id
=
id
;
this
.
id
=
id
;
this
.
type
=
type
;
this
.
type
=
type
;
this
.
timescale
=
timescale
;
this
.
timescale
=
timescale
;
...
...
library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java
View file @
ab6f9aea
...
@@ -23,6 +23,7 @@ import android.media.MediaCrypto;
...
@@ -23,6 +23,7 @@ import android.media.MediaCrypto;
import
android.media.MediaFormat
;
import
android.media.MediaFormat
;
import
android.os.Looper
;
import
android.os.Looper
;
import
android.os.SystemClock
;
import
android.os.SystemClock
;
import
android.support.annotation.IntDef
;
import
android.support.annotation.Nullable
;
import
android.support.annotation.Nullable
;
import
android.util.Log
;
import
android.util.Log
;
import
com.google.android.exoplayer2.BaseRenderer
;
import
com.google.android.exoplayer2.BaseRenderer
;
...
@@ -43,6 +44,9 @@ import com.google.android.exoplayer2.util.Assertions;
...
@@ -43,6 +44,9 @@ import com.google.android.exoplayer2.util.Assertions;
import
com.google.android.exoplayer2.util.NalUnitUtil
;
import
com.google.android.exoplayer2.util.NalUnitUtil
;
import
com.google.android.exoplayer2.util.TraceUtil
;
import
com.google.android.exoplayer2.util.TraceUtil
;
import
com.google.android.exoplayer2.util.Util
;
import
com.google.android.exoplayer2.util.Util
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.RetentionPolicy
;
import
java.nio.ByteBuffer
;
import
java.nio.ByteBuffer
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.List
;
...
@@ -158,9 +162,26 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
...
@@ -158,9 +162,26 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
*/
*/
private
static
final
int
REINITIALIZATION_STATE_WAIT_END_OF_STREAM
=
2
;
private
static
final
int
REINITIALIZATION_STATE_WAIT_END_OF_STREAM
=
2
;
@Retention
(
RetentionPolicy
.
SOURCE
)
@IntDef
({
ADAPTATION_WORKAROUND_MODE_NEVER
,
ADAPTATION_WORKAROUND_MODE_SAME_RESOLUTION
,
ADAPTATION_WORKAROUND_MODE_ALWAYS
})
private
@interface
AdaptationWorkaroundMode
{}
/**
* The adaptation workaround is never used.
*/
private
static
final
int
ADAPTATION_WORKAROUND_MODE_NEVER
=
0
;
/**
* The adaptation workaround is used when adapting between formats of the same resolution only.
*/
private
static
final
int
ADAPTATION_WORKAROUND_MODE_SAME_RESOLUTION
=
1
;
/**
* The adaptation workaround is always used when adapting between formats.
*/
private
static
final
int
ADAPTATION_WORKAROUND_MODE_ALWAYS
=
2
;
/**
/**
* H.264/AVC buffer to queue when using the adaptation workaround (see
* H.264/AVC buffer to queue when using the adaptation workaround (see
* {@link #codec
NeedsAdaptationWorkaround
(String)}. Consists of three NAL units with start codes:
* {@link #codec
AdaptationWorkaroundMode
(String)}. Consists of three NAL units with start codes:
* Baseline sequence/picture parameter sets and a 32 * 32 pixel IDR slice. This stream can be
* Baseline sequence/picture parameter sets and a 32 * 32 pixel IDR slice. This stream can be
* queued to force a resolution change when adapting to a new format.
* queued to force a resolution change when adapting to a new format.
*/
*/
...
@@ -182,9 +203,9 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
...
@@ -182,9 +203,9 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
private
DrmSession
<
FrameworkMediaCrypto
>
pendingDrmSession
;
private
DrmSession
<
FrameworkMediaCrypto
>
pendingDrmSession
;
private
MediaCodec
codec
;
private
MediaCodec
codec
;
private
MediaCodecInfo
codecInfo
;
private
MediaCodecInfo
codecInfo
;
private
@AdaptationWorkaroundMode
int
codecAdaptationWorkaroundMode
;
private
boolean
codecNeedsDiscardToSpsWorkaround
;
private
boolean
codecNeedsDiscardToSpsWorkaround
;
private
boolean
codecNeedsFlushWorkaround
;
private
boolean
codecNeedsFlushWorkaround
;
private
boolean
codecNeedsAdaptationWorkaround
;
private
boolean
codecNeedsEosPropagationWorkaround
;
private
boolean
codecNeedsEosPropagationWorkaround
;
private
boolean
codecNeedsEosFlushWorkaround
;
private
boolean
codecNeedsEosFlushWorkaround
;
private
boolean
codecNeedsEosOutputExceptionWorkaround
;
private
boolean
codecNeedsEosOutputExceptionWorkaround
;
...
@@ -355,9 +376,9 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
...
@@ -355,9 +376,9 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
}
}
String
codecName
=
codecInfo
.
name
;
String
codecName
=
codecInfo
.
name
;
codecAdaptationWorkaroundMode
=
codecAdaptationWorkaroundMode
(
codecName
);
codecNeedsDiscardToSpsWorkaround
=
codecNeedsDiscardToSpsWorkaround
(
codecName
,
format
);
codecNeedsDiscardToSpsWorkaround
=
codecNeedsDiscardToSpsWorkaround
(
codecName
,
format
);
codecNeedsFlushWorkaround
=
codecNeedsFlushWorkaround
(
codecName
);
codecNeedsFlushWorkaround
=
codecNeedsFlushWorkaround
(
codecName
);
codecNeedsAdaptationWorkaround
=
codecNeedsAdaptationWorkaround
(
codecName
);
codecNeedsEosPropagationWorkaround
=
codecNeedsEosPropagationWorkaround
(
codecName
);
codecNeedsEosPropagationWorkaround
=
codecNeedsEosPropagationWorkaround
(
codecName
);
codecNeedsEosFlushWorkaround
=
codecNeedsEosFlushWorkaround
(
codecName
);
codecNeedsEosFlushWorkaround
=
codecNeedsEosFlushWorkaround
(
codecName
);
codecNeedsEosOutputExceptionWorkaround
=
codecNeedsEosOutputExceptionWorkaround
(
codecName
);
codecNeedsEosOutputExceptionWorkaround
=
codecNeedsEosOutputExceptionWorkaround
(
codecName
);
...
@@ -458,7 +479,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
...
@@ -458,7 +479,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
codecReceivedBuffers
=
false
;
codecReceivedBuffers
=
false
;
codecNeedsDiscardToSpsWorkaround
=
false
;
codecNeedsDiscardToSpsWorkaround
=
false
;
codecNeedsFlushWorkaround
=
false
;
codecNeedsFlushWorkaround
=
false
;
codec
NeedsAdaptationWorkaround
=
false
;
codec
AdaptationWorkaroundMode
=
ADAPTATION_WORKAROUND_MODE_NEVER
;
codecNeedsEosPropagationWorkaround
=
false
;
codecNeedsEosPropagationWorkaround
=
false
;
codecNeedsEosFlushWorkaround
=
false
;
codecNeedsEosFlushWorkaround
=
false
;
codecNeedsMonoChannelCountWorkaround
=
false
;
codecNeedsMonoChannelCountWorkaround
=
false
;
...
@@ -802,8 +823,10 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
...
@@ -802,8 +823,10 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
&&
canReconfigureCodec
(
codec
,
codecInfo
.
adaptive
,
oldFormat
,
format
))
{
&&
canReconfigureCodec
(
codec
,
codecInfo
.
adaptive
,
oldFormat
,
format
))
{
codecReconfigured
=
true
;
codecReconfigured
=
true
;
codecReconfigurationState
=
RECONFIGURATION_STATE_WRITE_PENDING
;
codecReconfigurationState
=
RECONFIGURATION_STATE_WRITE_PENDING
;
codecNeedsAdaptationWorkaroundBuffer
=
codecNeedsAdaptationWorkaround
codecNeedsAdaptationWorkaroundBuffer
=
&&
format
.
width
==
oldFormat
.
width
&&
format
.
height
==
oldFormat
.
height
;
codecAdaptationWorkaroundMode
==
ADAPTATION_WORKAROUND_MODE_ALWAYS
||
(
codecAdaptationWorkaroundMode
==
ADAPTATION_WORKAROUND_MODE_SAME_RESOLUTION
&&
format
.
width
==
oldFormat
.
width
&&
format
.
height
==
oldFormat
.
height
);
}
else
{
}
else
{
if
(
codecReceivedBuffers
)
{
if
(
codecReceivedBuffers
)
{
// Signal end of stream and wait for any final output buffers before re-initialization.
// Signal end of stream and wait for any final output buffers before re-initialization.
...
@@ -989,7 +1012,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
...
@@ -989,7 +1012,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
*/
*/
private
void
processOutputFormat
()
throws
ExoPlaybackException
{
private
void
processOutputFormat
()
throws
ExoPlaybackException
{
MediaFormat
format
=
codec
.
getOutputFormat
();
MediaFormat
format
=
codec
.
getOutputFormat
();
if
(
codec
NeedsAdaptationWorkaround
if
(
codec
AdaptationWorkaroundMode
!=
ADAPTATION_WORKAROUND_MODE_NEVER
&&
format
.
getInteger
(
MediaFormat
.
KEY_WIDTH
)
==
ADAPTATION_WORKAROUND_SLICE_WIDTH_HEIGHT
&&
format
.
getInteger
(
MediaFormat
.
KEY_WIDTH
)
==
ADAPTATION_WORKAROUND_SLICE_WIDTH_HEIGHT
&&
format
.
getInteger
(
MediaFormat
.
KEY_HEIGHT
)
==
ADAPTATION_WORKAROUND_SLICE_WIDTH_HEIGHT
)
{
&&
format
.
getInteger
(
MediaFormat
.
KEY_HEIGHT
)
==
ADAPTATION_WORKAROUND_SLICE_WIDTH_HEIGHT
)
{
// We assume this format changed event was caused by the adaptation workaround.
// We assume this format changed event was caused by the adaptation workaround.
...
@@ -1122,22 +1145,30 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
...
@@ -1122,22 +1145,30 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
}
}
/**
/**
* Returns whether the decoder is known to get stuck during some adaptations where the resolution
* Returns a mode that specifies when the adaptation workaround should be enabled.
* does not change.
* <p>
* <p>
* If true is returned, the renderer will work around the issue by queueing and discarding a blank
* When enabled, the workaround queues and discards a blank frame with a resolution whose width
* frame at a different resolution, which resets the codec's internal state.
* and height both equal {@link #ADAPTATION_WORKAROUND_SLICE_WIDTH_HEIGHT}, to reset the codec's
* internal state when a format change occurs.
* <p>
* <p>
* See [Internal: b/27807182].
* See [Internal: b/27807182].
* See <a href="https://github.com/google/ExoPlayer/issues/3257">GitHub issue #3257</a>.
*
*
* @param name The name of the decoder.
* @param name The name of the decoder.
* @return T
rue if the decoder is known to get stuck during some adaptations
.
* @return T
he mode specifying when the adaptation workaround should be enabled
.
*/
*/
private
static
boolean
codecNeedsAdaptationWorkaround
(
String
name
)
{
private
@AdaptationWorkaroundMode
int
codecAdaptationWorkaroundMode
(
String
name
)
{
return
Util
.
SDK_INT
<
24
if
(
Util
.
SDK_INT
<=
24
&&
"OMX.Exynos.avc.dec.secure"
.
equals
(
name
)
&&
(
Util
.
MODEL
.
startsWith
(
"SM-T585"
)
||
Util
.
MODEL
.
startsWith
(
"SM-A520"
)))
{
return
ADAPTATION_WORKAROUND_MODE_ALWAYS
;
}
else
if
(
Util
.
SDK_INT
<
24
&&
(
"OMX.Nvidia.h264.decode"
.
equals
(
name
)
||
"OMX.Nvidia.h264.decode.secure"
.
equals
(
name
))
&&
(
"OMX.Nvidia.h264.decode"
.
equals
(
name
)
||
"OMX.Nvidia.h264.decode.secure"
.
equals
(
name
))
&&
(
"flounder"
.
equals
(
Util
.
DEVICE
)
||
"flounder_lte"
.
equals
(
Util
.
DEVICE
)
&&
(
"flounder"
.
equals
(
Util
.
DEVICE
)
||
"flounder_lte"
.
equals
(
Util
.
DEVICE
)
||
"grouper"
.
equals
(
Util
.
DEVICE
)
||
"tilapia"
.
equals
(
Util
.
DEVICE
));
||
"grouper"
.
equals
(
Util
.
DEVICE
)
||
"tilapia"
.
equals
(
Util
.
DEVICE
)))
{
return
ADAPTATION_WORKAROUND_MODE_SAME_RESOLUTION
;
}
else
{
return
ADAPTATION_WORKAROUND_MODE_NEVER
;
}
}
}
/**
/**
...
...
library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java
View file @
ab6f9aea
...
@@ -973,9 +973,11 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
...
@@ -973,9 +973,11 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
* If true is returned then we fall back to releasing and re-instantiating the codec instead.
* If true is returned then we fall back to releasing and re-instantiating the codec instead.
*/
*/
private
static
boolean
codecNeedsSetOutputSurfaceWorkaround
(
String
name
)
{
private
static
boolean
codecNeedsSetOutputSurfaceWorkaround
(
String
name
)
{
// Work around https://github.com/google/ExoPlayer/issues/3236
// Work around https://github.com/google/ExoPlayer/issues/3236 and
return
(
"deb"
.
equals
(
Util
.
DEVICE
)
||
"flo"
.
equals
(
Util
.
DEVICE
))
// https://github.com/google/ExoPlayer/issues/3355.
&&
"OMX.qcom.video.decoder.avc"
.
equals
(
name
);
return
((
"deb"
.
equals
(
Util
.
DEVICE
)
||
"flo"
.
equals
(
Util
.
DEVICE
))
&&
"OMX.qcom.video.decoder.avc"
.
equals
(
name
))
||
(
"tcl_eu"
.
equals
(
Util
.
DEVICE
)
&&
"OMX.MTK.VIDEO.DECODER.AVC"
.
equals
(
name
));
}
}
/**
/**
...
...
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java
View file @
ab6f9aea
...
@@ -173,7 +173,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
...
@@ -173,7 +173,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
}
}
@Override
@Override
public
final
void
getNextChunk
(
MediaChunk
previous
,
long
playbackPositionUs
,
ChunkHolder
out
)
{
public
void
getNextChunk
(
MediaChunk
previous
,
long
playbackPositionUs
,
ChunkHolder
out
)
{
if
(
fatalError
!=
null
)
{
if
(
fatalError
!=
null
)
{
return
;
return
;
}
}
...
@@ -300,7 +300,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
...
@@ -300,7 +300,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
trackSelection
.
indexOf
(
chunk
.
trackFormat
),
e
);
trackSelection
.
indexOf
(
chunk
.
trackFormat
),
e
);
}
}
//
Private
methods.
//
Internal
methods.
private
ArrayList
<
Representation
>
getRepresentations
()
{
private
ArrayList
<
Representation
>
getRepresentations
()
{
List
<
AdaptationSet
>
manifestAdapationSets
=
manifest
.
getPeriod
(
periodIndex
).
adaptationSets
;
List
<
AdaptationSet
>
manifestAdapationSets
=
manifest
.
getPeriod
(
periodIndex
).
adaptationSets
;
...
@@ -319,7 +319,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
...
@@ -319,7 +319,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
}
}
}
}
pr
ivate
static
Chunk
newInitializationChunk
(
RepresentationHolder
representationHolder
,
pr
otected
static
Chunk
newInitializationChunk
(
RepresentationHolder
representationHolder
,
DataSource
dataSource
,
Format
trackFormat
,
int
trackSelectionReason
,
DataSource
dataSource
,
Format
trackFormat
,
int
trackSelectionReason
,
Object
trackSelectionData
,
RangedUri
initializationUri
,
RangedUri
indexUri
)
{
Object
trackSelectionData
,
RangedUri
initializationUri
,
RangedUri
indexUri
)
{
RangedUri
requestUri
;
RangedUri
requestUri
;
...
@@ -340,7 +340,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
...
@@ -340,7 +340,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
trackSelectionReason
,
trackSelectionData
,
representationHolder
.
extractorWrapper
);
trackSelectionReason
,
trackSelectionData
,
representationHolder
.
extractorWrapper
);
}
}
pr
ivate
static
Chunk
newMediaChunk
(
RepresentationHolder
representationHolder
,
pr
otected
static
Chunk
newMediaChunk
(
RepresentationHolder
representationHolder
,
DataSource
dataSource
,
int
trackType
,
Format
trackFormat
,
int
trackSelectionReason
,
DataSource
dataSource
,
int
trackType
,
Format
trackFormat
,
int
trackSelectionReason
,
Object
trackSelectionData
,
int
firstSegmentNum
,
int
maxSegmentCount
)
{
Object
trackSelectionData
,
int
firstSegmentNum
,
int
maxSegmentCount
)
{
Representation
representation
=
representationHolder
.
representation
;
Representation
representation
=
representationHolder
.
representation
;
...
...
library/hls/src/androidTest/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylistParserTest.java
View file @
ab6f9aea
...
@@ -28,7 +28,7 @@ import java.util.List;
...
@@ -28,7 +28,7 @@ import java.util.List;
import
junit.framework.TestCase
;
import
junit.framework.TestCase
;
/**
/**
* Test for {@link HlsMasterPlaylistParserTest}
* Test for {@link HlsMasterPlaylistParserTest}
.
*/
*/
public
class
HlsMasterPlaylistParserTest
extends
TestCase
{
public
class
HlsMasterPlaylistParserTest
extends
TestCase
{
...
...
library/hls/src/androidTest/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylistParserTest.java
View file @
ab6f9aea
...
@@ -27,7 +27,7 @@ import java.util.Locale;
...
@@ -27,7 +27,7 @@ import java.util.Locale;
import
junit.framework.TestCase
;
import
junit.framework.TestCase
;
/**
/**
* Test for {@link HlsMediaPlaylistParserTest}
* Test for {@link HlsMediaPlaylistParserTest}
.
*/
*/
public
class
HlsMediaPlaylistParserTest
extends
TestCase
{
public
class
HlsMediaPlaylistParserTest
extends
TestCase
{
...
...
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java
View file @
ab6f9aea
...
@@ -26,9 +26,12 @@ import com.google.android.exoplayer2.source.MediaPeriod;
...
@@ -26,9 +26,12 @@ import com.google.android.exoplayer2.source.MediaPeriod;
import
com.google.android.exoplayer2.source.MediaSource
;
import
com.google.android.exoplayer2.source.MediaSource
;
import
com.google.android.exoplayer2.source.SinglePeriodTimeline
;
import
com.google.android.exoplayer2.source.SinglePeriodTimeline
;
import
com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist
;
import
com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist
;
import
com.google.android.exoplayer2.source.hls.playlist.HlsPlaylist
;
import
com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistParser
;
import
com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistTracker
;
import
com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistTracker
;
import
com.google.android.exoplayer2.upstream.Allocator
;
import
com.google.android.exoplayer2.upstream.Allocator
;
import
com.google.android.exoplayer2.upstream.DataSource
;
import
com.google.android.exoplayer2.upstream.DataSource
;
import
com.google.android.exoplayer2.upstream.ParsingLoadable
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.Assertions
;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.util.List
;
import
java.util.List
;
...
@@ -52,6 +55,7 @@ public final class HlsMediaSource implements MediaSource,
...
@@ -52,6 +55,7 @@ public final class HlsMediaSource implements MediaSource,
private
final
HlsDataSourceFactory
dataSourceFactory
;
private
final
HlsDataSourceFactory
dataSourceFactory
;
private
final
int
minLoadableRetryCount
;
private
final
int
minLoadableRetryCount
;
private
final
EventDispatcher
eventDispatcher
;
private
final
EventDispatcher
eventDispatcher
;
private
final
ParsingLoadable
.
Parser
<
HlsPlaylist
>
playlistParser
;
private
HlsPlaylistTracker
playlistTracker
;
private
HlsPlaylistTracker
playlistTracker
;
private
Listener
sourceListener
;
private
Listener
sourceListener
;
...
@@ -72,9 +76,18 @@ public final class HlsMediaSource implements MediaSource,
...
@@ -72,9 +76,18 @@ public final class HlsMediaSource implements MediaSource,
public
HlsMediaSource
(
Uri
manifestUri
,
HlsDataSourceFactory
dataSourceFactory
,
public
HlsMediaSource
(
Uri
manifestUri
,
HlsDataSourceFactory
dataSourceFactory
,
int
minLoadableRetryCount
,
Handler
eventHandler
,
int
minLoadableRetryCount
,
Handler
eventHandler
,
AdaptiveMediaSourceEventListener
eventListener
)
{
AdaptiveMediaSourceEventListener
eventListener
)
{
this
(
manifestUri
,
dataSourceFactory
,
minLoadableRetryCount
,
eventHandler
,
eventListener
,
new
HlsPlaylistParser
());
}
public
HlsMediaSource
(
Uri
manifestUri
,
HlsDataSourceFactory
dataSourceFactory
,
int
minLoadableRetryCount
,
Handler
eventHandler
,
AdaptiveMediaSourceEventListener
eventListener
,
ParsingLoadable
.
Parser
<
HlsPlaylist
>
playlistParser
)
{
this
.
manifestUri
=
manifestUri
;
this
.
manifestUri
=
manifestUri
;
this
.
dataSourceFactory
=
dataSourceFactory
;
this
.
dataSourceFactory
=
dataSourceFactory
;
this
.
minLoadableRetryCount
=
minLoadableRetryCount
;
this
.
minLoadableRetryCount
=
minLoadableRetryCount
;
this
.
playlistParser
=
playlistParser
;
eventDispatcher
=
new
EventDispatcher
(
eventHandler
,
eventListener
);
eventDispatcher
=
new
EventDispatcher
(
eventHandler
,
eventListener
);
}
}
...
@@ -82,7 +95,7 @@ public final class HlsMediaSource implements MediaSource,
...
@@ -82,7 +95,7 @@ public final class HlsMediaSource implements MediaSource,
public
void
prepareSource
(
ExoPlayer
player
,
boolean
isTopLevelSource
,
Listener
listener
)
{
public
void
prepareSource
(
ExoPlayer
player
,
boolean
isTopLevelSource
,
Listener
listener
)
{
Assertions
.
checkState
(
playlistTracker
==
null
);
Assertions
.
checkState
(
playlistTracker
==
null
);
playlistTracker
=
new
HlsPlaylistTracker
(
manifestUri
,
dataSourceFactory
,
eventDispatcher
,
playlistTracker
=
new
HlsPlaylistTracker
(
manifestUri
,
dataSourceFactory
,
eventDispatcher
,
minLoadableRetryCount
,
this
);
minLoadableRetryCount
,
this
,
playlistParser
);
sourceListener
=
listener
;
sourceListener
=
listener
;
playlistTracker
.
start
();
playlistTracker
.
start
();
}
}
...
...
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylist.java
View file @
ab6f9aea
...
@@ -17,6 +17,7 @@ package com.google.android.exoplayer2.source.hls.playlist;
...
@@ -17,6 +17,7 @@ package com.google.android.exoplayer2.source.hls.playlist;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.util.MimeTypes
;
import
com.google.android.exoplayer2.util.MimeTypes
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.List
;
...
@@ -109,6 +110,20 @@ public final class HlsMasterPlaylist extends HlsPlaylist {
...
@@ -109,6 +110,20 @@ public final class HlsMasterPlaylist extends HlsPlaylist {
}
}
/**
/**
* Returns a copy of this playlist which includes only the renditions identified by the given
* urls.
*
* @param renditionUrls List of rendition urls.
* @return A copy of this playlist which includes only the renditions identified by the given
* urls.
*/
public
HlsMasterPlaylist
copy
(
List
<
String
>
renditionUrls
)
{
return
new
HlsMasterPlaylist
(
baseUri
,
tags
,
copyRenditionsList
(
variants
,
renditionUrls
),
copyRenditionsList
(
audios
,
renditionUrls
),
copyRenditionsList
(
subtitles
,
renditionUrls
),
muxedAudioFormat
,
muxedCaptionFormats
);
}
/**
* Creates a playlist with a single variant.
* Creates a playlist with a single variant.
*
*
* @param variantUrl The url of the single variant.
* @param variantUrl The url of the single variant.
...
@@ -121,4 +136,15 @@ public final class HlsMasterPlaylist extends HlsPlaylist {
...
@@ -121,4 +136,15 @@ public final class HlsMasterPlaylist extends HlsPlaylist {
emptyList
,
null
,
null
);
emptyList
,
null
,
null
);
}
}
private
static
List
<
HlsUrl
>
copyRenditionsList
(
List
<
HlsUrl
>
renditions
,
List
<
String
>
urls
)
{
List
<
HlsUrl
>
copiedRenditions
=
new
ArrayList
<>(
urls
.
size
());
for
(
int
i
=
0
;
i
<
renditions
.
size
();
i
++)
{
HlsUrl
rendition
=
renditions
.
get
(
i
);
if
(
urls
.
contains
(
rendition
.
url
))
{
copiedRenditions
.
add
(
rendition
);
}
}
return
copiedRenditions
;
}
}
}
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistTracker.java
View file @
ab6f9aea
This diff is collapsed.
Click to expand it.
testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaSource.java
View file @
ab6f9aea
...
@@ -111,4 +111,5 @@ public class FakeMediaSource implements MediaSource {
...
@@ -111,4 +111,5 @@ public class FakeMediaSource implements MediaSource {
}
}
return
new
TrackGroupArray
(
trackGroups
);
return
new
TrackGroupArray
(
trackGroups
);
}
}
}
}
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