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
cbffc14f
authored
Jul 19, 2017
by
ojw28
Committed by
GitHub
Jul 19, 2017
Browse files
Options
_('Browse Files')
Download
Plain Diff
Merge pull request #3083 from google/dev-v2-r2.4.4
r2.4.4
parents
2bebd526
46ba81c4
Hide whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
364 additions
and
347 deletions
RELEASENOTES.md
build.gradle
demo/src/main/AndroidManifest.xml
demo/src/main/java/com/google/android/exoplayer2/demo/TrackSelectionHelper.java
demo/src/main/res/values/strings.xml
library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ogg/VorbisBitArrayTest.java
library/core/src/androidTest/java/com/google/android/exoplayer2/util/ParsableBitArrayTest.java
library/core/src/androidTest/java/com/google/android/exoplayer2/util/ParsableNalUnitBitArrayTest.java
library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/VorbisBitArray.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/SeiReader.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java
library/core/src/main/java/com/google/android/exoplayer2/util/FlacStreamInfo.java
library/core/src/main/java/com/google/android/exoplayer2/util/NalUnitUtil.java
library/core/src/main/java/com/google/android/exoplayer2/util/ParsableBitArray.java
library/core/src/main/java/com/google/android/exoplayer2/util/ParsableNalUnitBitArray.java
library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistTracker.java
library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java
library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java
RELEASENOTES.md
View file @
cbffc14f
# Release notes #
### r2.4.4 ###
*
HLS/MPEG-TS: Some initial optimizations of MPEG-TS extractor performance
(
[
#3040
](
https://github.com/google/ExoPlayer/issues/3040
)
).
*
HLS: Fix propagation of format identifier for CEA-608
(
[
#3033
](
https://github.com/google/ExoPlayer/issues/3033
)
).
*
HLS: Detect playlist stuck and reset conditions
(
[
#2872
](
https://github.com/google/ExoPlayer/issues/2872
)
).
*
Video: Fix video dimension reporting on some devices
(
[
#3007
](
https://github.com/google/ExoPlayer/issues/3007
)
).
### r2.4.3 ###
*
Audio: Workaround custom audio decoders misreporting their maximum supported
...
...
build.gradle
View file @
cbffc14f
...
...
@@ -48,7 +48,7 @@ allprojects {
releaseRepoName
=
getBintrayRepo
()
releaseUserOrg
=
'google'
releaseGroupId
=
'com.google.android.exoplayer'
releaseVersion
=
'r2.4.
3
'
releaseVersion
=
'r2.4.
4
'
releaseWebsite
=
'https://github.com/google/ExoPlayer'
}
if
(
it
.
hasProperty
(
'externalBuildDir'
))
{
...
...
demo/src/main/AndroidManifest.xml
View file @
cbffc14f
...
...
@@ -16,8 +16,8 @@
<manifest
xmlns:android=
"http://schemas.android.com/apk/res/android"
package=
"com.google.android.exoplayer2.demo"
android:versionCode=
"240
3
"
android:versionName=
"2.4.
3
"
>
android:versionCode=
"240
4
"
android:versionName=
"2.4.
4
"
>
<uses-permission
android:name=
"android.permission.INTERNET"
/>
<uses-permission
android:name=
"android.permission.READ_EXTERNAL_STORAGE"
/>
...
...
demo/src/main/java/com/google/android/exoplayer2/demo/TrackSelectionHelper.java
View file @
cbffc14f
...
...
@@ -136,7 +136,6 @@ import java.util.Arrays;
root
.
addView
(
defaultView
);
// Per-track views.
boolean
haveSupportedTracks
=
false
;
boolean
haveAdaptiveTracks
=
false
;
trackViews
=
new
CheckedTextView
[
trackGroups
.
length
][];
for
(
int
groupIndex
=
0
;
groupIndex
<
trackGroups
.
length
;
groupIndex
++)
{
...
...
@@ -159,7 +158,6 @@ import java.util.Arrays;
trackView
.
setFocusable
(
true
);
trackView
.
setTag
(
Pair
.
create
(
groupIndex
,
trackIndex
));
trackView
.
setOnClickListener
(
this
);
haveSupportedTracks
=
true
;
}
else
{
trackView
.
setFocusable
(
false
);
trackView
.
setEnabled
(
false
);
...
...
@@ -169,10 +167,7 @@ import java.util.Arrays;
}
}
if
(!
haveSupportedTracks
)
{
// Indicate that the default selection will be nothing.
defaultView
.
setText
(
R
.
string
.
selection_default_none
);
}
else
if
(
haveAdaptiveTracks
)
{
if
(
haveAdaptiveTracks
)
{
// View for using random adaptation.
enableRandomAdaptationView
=
(
CheckedTextView
)
inflater
.
inflate
(
android
.
R
.
layout
.
simple_list_item_multiple_choice
,
root
,
false
);
...
...
demo/src/main/res/values/strings.xml
View file @
cbffc14f
...
...
@@ -30,8 +30,6 @@
<string
name=
"selection_default"
>
Default
</string>
<string
name=
"selection_default_none"
>
Default (none)
</string>
<string
name=
"unexpected_intent_action"
>
Unexpected intent action:
<xliff:g
id=
"action"
>
%1$s
</xliff:g></string>
<string
name=
"enable_random_adaptation"
>
Enable random adaptation
</string>
...
...
library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ogg/VorbisBitArrayTest.java
View file @
cbffc14f
...
...
@@ -25,36 +25,26 @@ public final class VorbisBitArrayTest extends TestCase {
public
void
testReadBit
()
{
VorbisBitArray
bitArray
=
new
VorbisBitArray
(
TestUtil
.
createByteArray
(
0x5c
,
0x50
));
assertFalse
(
bitArray
.
readBit
());
assertFalse
(
bitArray
.
readBit
());
assertTrue
(
bitArray
.
readBit
());
assertTrue
(
bitArray
.
readBit
());
assertTrue
(
bitArray
.
readBit
());
assertFalse
(
bitArray
.
readBit
());
assertTrue
(
bitArray
.
readBit
());
assertFalse
(
bitArray
.
readBit
());
assertFalse
(
bitArray
.
readBit
());
assertFalse
(
bitArray
.
readBit
());
assertFalse
(
bitArray
.
readBit
());
assertFalse
(
bitArray
.
readBit
());
assertTrue
(
bitArray
.
readBit
());
assertFalse
(
bitArray
.
readBit
());
assertTrue
(
bitArray
.
readBit
());
assertFalse
(
bitArray
.
readBit
());
try
{
assertFalse
(
bitArray
.
readBit
());
fail
();
}
catch
(
IllegalStateException
e
)
{
/* ignored */
}
}
public
void
testSkipBits
()
{
VorbisBitArray
bitArray
=
new
VorbisBitArray
(
TestUtil
.
createByteArray
(
0xF0
,
0x0F
));
bitArray
.
skipBits
(
10
);
assertEquals
(
10
,
bitArray
.
getPosition
());
assertTrue
(
bitArray
.
readBit
());
...
...
@@ -64,27 +54,10 @@ public final class VorbisBitArrayTest extends TestCase {
assertEquals
(
14
,
bitArray
.
getPosition
());
assertFalse
(
bitArray
.
readBit
());
assertFalse
(
bitArray
.
readBit
());
try
{
bitArray
.
readBit
();
fail
();
}
catch
(
IllegalStateException
e
)
{
// ignored
}
}
public
void
testSkipBitsThrowsErrorIfEOB
()
{
VorbisBitArray
bitArray
=
new
VorbisBitArray
(
TestUtil
.
createByteArray
(
0xF0
,
0x0F
));
try
{
bitArray
.
skipBits
(
17
);
fail
();
}
catch
(
IllegalStateException
e
)
{
/* ignored */
}
}
public
void
testGetPosition
()
throws
Exception
{
VorbisBitArray
bitArray
=
new
VorbisBitArray
(
TestUtil
.
createByteArray
(
0xF0
,
0x0F
));
assertEquals
(
0
,
bitArray
.
getPosition
());
bitArray
.
readBit
();
assertEquals
(
1
,
bitArray
.
getPosition
());
...
...
@@ -96,35 +69,11 @@ public final class VorbisBitArrayTest extends TestCase {
public
void
testSetPosition
()
throws
Exception
{
VorbisBitArray
bitArray
=
new
VorbisBitArray
(
TestUtil
.
createByteArray
(
0xF0
,
0x0F
));
assertEquals
(
0
,
bitArray
.
getPosition
());
bitArray
.
setPosition
(
4
);
assertEquals
(
4
,
bitArray
.
getPosition
());
bitArray
.
setPosition
(
15
);
assertFalse
(
bitArray
.
readBit
());
try
{
bitArray
.
readBit
();
fail
();
}
catch
(
IllegalStateException
e
)
{
/* ignored */
}
}
public
void
testSetPositionIllegalPositions
()
throws
Exception
{
VorbisBitArray
bitArray
=
new
VorbisBitArray
(
TestUtil
.
createByteArray
(
0xF0
,
0x0F
));
try
{
bitArray
.
setPosition
(
16
);
fail
();
}
catch
(
IllegalArgumentException
e
)
{
assertEquals
(
0
,
bitArray
.
getPosition
());
}
try
{
bitArray
.
setPosition
(-
1
);
fail
();
}
catch
(
IllegalArgumentException
e
)
{
assertEquals
(
0
,
bitArray
.
getPosition
());
}
}
public
void
testReadInt32
()
{
...
...
@@ -136,13 +85,11 @@ public final class VorbisBitArrayTest extends TestCase {
public
void
testReadBits
()
throws
Exception
{
VorbisBitArray
bitArray
=
new
VorbisBitArray
(
TestUtil
.
createByteArray
(
0x03
,
0x22
));
assertEquals
(
3
,
bitArray
.
readBits
(
2
));
bitArray
.
skipBits
(
6
);
assertEquals
(
2
,
bitArray
.
readBits
(
2
));
bitArray
.
skipBits
(
2
);
assertEquals
(
2
,
bitArray
.
readBits
(
2
));
bitArray
.
reset
();
assertEquals
(
0x2203
,
bitArray
.
readBits
(
16
));
}
...
...
@@ -156,7 +103,6 @@ public final class VorbisBitArrayTest extends TestCase {
public
void
testReadBitsBeyondByteBoundaries
()
throws
Exception
{
VorbisBitArray
bitArray
=
new
VorbisBitArray
(
TestUtil
.
createByteArray
(
0xFF
,
0x0F
,
0xFF
,
0x0F
));
assertEquals
(
0x0FFF0FFF
,
bitArray
.
readBits
(
32
));
bitArray
.
reset
();
...
...
@@ -188,83 +134,6 @@ public final class VorbisBitArrayTest extends TestCase {
assertEquals
(
0
,
bitArray
.
getPosition
());
bitArray
.
readBit
();
assertEquals
(
1
,
bitArray
.
getPosition
());
try
{
bitArray
.
readBits
(
24
);
fail
();
}
catch
(
IllegalStateException
e
)
{
assertEquals
(
1
,
bitArray
.
getPosition
());
}
}
public
void
testLimit
()
{
VorbisBitArray
bitArray
=
new
VorbisBitArray
(
TestUtil
.
createByteArray
(
0xc0
,
0x02
),
1
);
try
{
bitArray
.
skipBits
(
9
);
fail
();
}
catch
(
IllegalStateException
e
)
{
assertEquals
(
0
,
bitArray
.
getPosition
());
}
try
{
bitArray
.
readBits
(
9
);
fail
();
}
catch
(
IllegalStateException
e
)
{
assertEquals
(
0
,
bitArray
.
getPosition
());
}
int
byteValue
=
bitArray
.
readBits
(
8
);
assertEquals
(
0xc0
,
byteValue
);
assertEquals
(
8
,
bitArray
.
getPosition
());
try
{
bitArray
.
readBit
();
fail
();
}
catch
(
IllegalStateException
e
)
{
assertEquals
(
8
,
bitArray
.
getPosition
());
}
}
public
void
testBitsLeft
()
{
VorbisBitArray
bitArray
=
new
VorbisBitArray
(
TestUtil
.
createByteArray
(
0xc0
,
0x02
));
assertEquals
(
16
,
bitArray
.
bitsLeft
());
assertEquals
(
bitArray
.
limit
(),
bitArray
.
getPosition
()
+
bitArray
.
bitsLeft
());
bitArray
.
skipBits
(
1
);
assertEquals
(
15
,
bitArray
.
bitsLeft
());
assertEquals
(
bitArray
.
limit
(),
bitArray
.
getPosition
()
+
bitArray
.
bitsLeft
());
bitArray
.
skipBits
(
3
);
assertEquals
(
12
,
bitArray
.
bitsLeft
());
assertEquals
(
bitArray
.
limit
(),
bitArray
.
getPosition
()
+
bitArray
.
bitsLeft
());
bitArray
.
setPosition
(
6
);
assertEquals
(
10
,
bitArray
.
bitsLeft
());
assertEquals
(
bitArray
.
limit
(),
bitArray
.
getPosition
()
+
bitArray
.
bitsLeft
());
bitArray
.
skipBits
(
1
);
assertEquals
(
9
,
bitArray
.
bitsLeft
());
assertEquals
(
bitArray
.
limit
(),
bitArray
.
getPosition
()
+
bitArray
.
bitsLeft
());
bitArray
.
skipBits
(
1
);
assertEquals
(
8
,
bitArray
.
bitsLeft
());
assertEquals
(
bitArray
.
limit
(),
bitArray
.
getPosition
()
+
bitArray
.
bitsLeft
());
bitArray
.
readBits
(
4
);
assertEquals
(
4
,
bitArray
.
bitsLeft
());
assertEquals
(
bitArray
.
limit
(),
bitArray
.
getPosition
()
+
bitArray
.
bitsLeft
());
bitArray
.
readBits
(
4
);
assertEquals
(
0
,
bitArray
.
bitsLeft
());
assertEquals
(
bitArray
.
limit
(),
bitArray
.
getPosition
()
+
bitArray
.
bitsLeft
());
try
{
bitArray
.
readBit
();
fail
();
}
catch
(
IllegalStateException
e
)
{
assertEquals
(
0
,
bitArray
.
bitsLeft
());
}
}
}
library/core/src/androidTest/java/com/google/android/exoplayer2/util/ParsableBitArrayTest.java
0 → 100644
View file @
cbffc14f
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com
.
google
.
android
.
exoplayer2
.
util
;
import
android.test.MoreAsserts
;
import
junit.framework.TestCase
;
/**
* Tests for {@link ParsableBitArray}.
*/
public
final
class
ParsableBitArrayTest
extends
TestCase
{
private
static
final
byte
[]
TEST_DATA
=
new
byte
[]
{
0x3C
,
(
byte
)
0xD2
,
(
byte
)
0x5F
,
(
byte
)
0x01
,
(
byte
)
0xFF
,
(
byte
)
0x14
,
(
byte
)
0x60
,
(
byte
)
0x99
};
public
void
testReadAllBytes
()
{
ParsableBitArray
testArray
=
new
ParsableBitArray
(
TEST_DATA
);
byte
[]
bytesRead
=
new
byte
[
TEST_DATA
.
length
];
testArray
.
readBytes
(
bytesRead
,
0
,
TEST_DATA
.
length
);
MoreAsserts
.
assertEquals
(
TEST_DATA
,
bytesRead
);
assertEquals
(
TEST_DATA
.
length
*
8
,
testArray
.
getPosition
());
assertEquals
(
TEST_DATA
.
length
,
testArray
.
getBytePosition
());
}
public
void
testReadBit
()
{
ParsableBitArray
testArray
=
new
ParsableBitArray
(
TEST_DATA
);
assertReadBitsToEnd
(
0
,
testArray
);
}
public
void
testReadBits
()
{
ParsableBitArray
testArray
=
new
ParsableBitArray
(
TEST_DATA
);
assertEquals
(
getTestDataBits
(
0
,
5
),
testArray
.
readBits
(
5
));
assertEquals
(
getTestDataBits
(
5
,
3
),
testArray
.
readBits
(
3
));
assertEquals
(
getTestDataBits
(
8
,
16
),
testArray
.
readBits
(
16
));
assertEquals
(
getTestDataBits
(
24
,
3
),
testArray
.
readBits
(
3
));
assertEquals
(
getTestDataBits
(
27
,
18
),
testArray
.
readBits
(
18
));
assertEquals
(
getTestDataBits
(
45
,
5
),
testArray
.
readBits
(
5
));
assertEquals
(
getTestDataBits
(
50
,
14
),
testArray
.
readBits
(
14
));
}
public
void
testRead32BitsByteAligned
()
{
ParsableBitArray
testArray
=
new
ParsableBitArray
(
TEST_DATA
);
assertEquals
(
getTestDataBits
(
0
,
32
),
testArray
.
readBits
(
32
));
assertEquals
(
getTestDataBits
(
32
,
32
),
testArray
.
readBits
(
32
));
}
public
void
testRead32BitsNonByteAligned
()
{
ParsableBitArray
testArray
=
new
ParsableBitArray
(
TEST_DATA
);
assertEquals
(
getTestDataBits
(
0
,
5
),
testArray
.
readBits
(
5
));
assertEquals
(
getTestDataBits
(
5
,
32
),
testArray
.
readBits
(
32
));
}
public
void
testSkipBytes
()
{
ParsableBitArray
testArray
=
new
ParsableBitArray
(
TEST_DATA
);
testArray
.
skipBytes
(
2
);
assertReadBitsToEnd
(
16
,
testArray
);
}
public
void
testSkipBitsByteAligned
()
{
ParsableBitArray
testArray
=
new
ParsableBitArray
(
TEST_DATA
);
testArray
.
skipBits
(
16
);
assertReadBitsToEnd
(
16
,
testArray
);
}
public
void
testSkipBitsNonByteAligned
()
{
ParsableBitArray
testArray
=
new
ParsableBitArray
(
TEST_DATA
);
testArray
.
skipBits
(
5
);
assertReadBitsToEnd
(
5
,
testArray
);
}
public
void
testSetPositionByteAligned
()
{
ParsableBitArray
testArray
=
new
ParsableBitArray
(
TEST_DATA
);
testArray
.
setPosition
(
16
);
assertReadBitsToEnd
(
16
,
testArray
);
}
public
void
testSetPositionNonByteAligned
()
{
ParsableBitArray
testArray
=
new
ParsableBitArray
(
TEST_DATA
);
testArray
.
setPosition
(
5
);
assertReadBitsToEnd
(
5
,
testArray
);
}
public
void
testByteAlignFromNonByteAligned
()
{
ParsableBitArray
testArray
=
new
ParsableBitArray
(
TEST_DATA
);
testArray
.
setPosition
(
11
);
testArray
.
byteAlign
();
assertEquals
(
2
,
testArray
.
getBytePosition
());
assertEquals
(
16
,
testArray
.
getPosition
());
assertReadBitsToEnd
(
16
,
testArray
);
}
public
void
testByteAlignFromByteAligned
()
{
ParsableBitArray
testArray
=
new
ParsableBitArray
(
TEST_DATA
);
testArray
.
setPosition
(
16
);
testArray
.
byteAlign
();
// Should be a no-op.
assertEquals
(
2
,
testArray
.
getBytePosition
());
assertEquals
(
16
,
testArray
.
getPosition
());
assertReadBitsToEnd
(
16
,
testArray
);
}
private
static
void
assertReadBitsToEnd
(
int
expectedStartPosition
,
ParsableBitArray
testArray
)
{
int
position
=
testArray
.
getPosition
();
assertEquals
(
expectedStartPosition
,
position
);
for
(
int
i
=
position
;
i
<
TEST_DATA
.
length
*
8
;
i
++)
{
assertEquals
(
getTestDataBit
(
i
),
testArray
.
readBit
());
assertEquals
(
i
+
1
,
testArray
.
getPosition
());
}
}
private
static
int
getTestDataBits
(
int
bitPosition
,
int
length
)
{
int
result
=
0
;
for
(
int
i
=
0
;
i
<
length
;
i
++)
{
result
=
result
<<
1
;
if
(
getTestDataBit
(
bitPosition
++))
{
result
|=
0x1
;
}
}
return
result
;
}
private
static
boolean
getTestDataBit
(
int
bitPosition
)
{
return
(
TEST_DATA
[
bitPosition
/
8
]
&
(
0x80
>>>
(
bitPosition
%
8
)))
!=
0
;
}
}
library/core/src/androidTest/java/com/google/android/exoplayer2/util/ParsableNalUnitBitArrayTest.java
View file @
cbffc14f
...
...
@@ -95,7 +95,7 @@ public final class ParsableNalUnitBitArrayTest extends TestCase {
ParsableNalUnitBitArray
array
=
new
ParsableNalUnitBitArray
(
createByteArray
(
0
,
0
,
3
,
128
,
0
),
0
,
5
);
assertFalse
(
array
.
canReadExpGolombCodedNum
());
array
.
skipBit
s
(
1
);
array
.
skipBit
(
);
assertTrue
(
array
.
canReadExpGolombCodedNum
());
assertEquals
(
32767
,
array
.
readUnsignedExpGolombCodedInt
());
assertFalse
(
array
.
canReadBits
(
1
));
...
...
library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java
View file @
cbffc14f
...
...
@@ -24,13 +24,13 @@ public interface ExoPlayerLibraryInfo {
* 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.
String
VERSION
=
"2.4.
3
"
;
String
VERSION
=
"2.4.
4
"
;
/**
* The version of the library expressed as {@code "ExoPlayerLib/" + VERSION}.
*/
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
String
VERSION_SLASHY
=
"ExoPlayerLib/2.4.
3
"
;
String
VERSION_SLASHY
=
"ExoPlayerLib/2.4.
4
"
;
/**
* The version of the library expressed as an integer, for example 1002003.
...
...
@@ -40,7 +40,7 @@ public interface ExoPlayerLibraryInfo {
* integer version 123045006 (123-045-006).
*/
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
int
VERSION_INT
=
200400
3
;
int
VERSION_INT
=
200400
4
;
/**
* Whether the library was compiled with {@link com.google.android.exoplayer2.util.Assertions}
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/VorbisBitArray.java
View file @
cbffc14f
...
...
@@ -25,8 +25,9 @@ import com.google.android.exoplayer2.util.Assertions;
*/
/* package */
final
class
VorbisBitArray
{
public
final
byte
[]
data
;
private
final
int
limit
;
private
final
byte
[]
data
;
private
final
int
byteLimit
;
private
int
byteOffset
;
private
int
bitOffset
;
...
...
@@ -36,18 +37,8 @@ import com.google.android.exoplayer2.util.Assertions;
* @param data the array to wrap.
*/
public
VorbisBitArray
(
byte
[]
data
)
{
this
(
data
,
data
.
length
);
}
/**
* Creates a new instance that wraps an existing array.
*
* @param data the array to wrap.
* @param limit the limit in bytes.
*/
public
VorbisBitArray
(
byte
[]
data
,
int
limit
)
{
this
.
data
=
data
;
this
.
limit
=
limit
*
8
;
byteLimit
=
data
.
length
;
}
/**
...
...
@@ -64,7 +55,9 @@ import com.google.android.exoplayer2.util.Assertions;
* @return {@code true} if the bit is set, {@code false} otherwise.
*/
public
boolean
readBit
()
{
return
readBits
(
1
)
==
1
;
boolean
returnValue
=
(((
data
[
byteOffset
]
&
0xFF
)
>>
bitOffset
)
&
0x01
)
==
1
;
skipBits
(
1
);
return
returnValue
;
}
/**
...
...
@@ -74,53 +67,32 @@ import com.google.android.exoplayer2.util.Assertions;
* @return An integer whose bottom {@code numBits} bits hold the read data.
*/
public
int
readBits
(
int
numBits
)
{
Assertions
.
checkState
(
getPosition
()
+
numBits
<=
limit
);
if
(
numBits
==
0
)
{
return
0
;
}
int
result
=
0
;
int
bitCount
=
0
;
if
(
bitOffset
!=
0
)
{
bitCount
=
Math
.
min
(
numBits
,
8
-
bitOffset
);
int
mask
=
0xFF
>>>
(
8
-
bitCount
);
result
=
(
data
[
byteOffset
]
>>>
bitOffset
)
&
mask
;
bitOffset
+=
bitCount
;
if
(
bitOffset
==
8
)
{
byteOffset
++;
bitOffset
=
0
;
}
}
if
(
numBits
-
bitCount
>
7
)
{
int
numBytes
=
(
numBits
-
bitCount
)
/
8
;
for
(
int
i
=
0
;
i
<
numBytes
;
i
++)
{
result
|=
(
data
[
byteOffset
++]
&
0xFF
L
)
<<
bitCount
;
bitCount
+=
8
;
}
int
tempByteOffset
=
byteOffset
;
int
bitsRead
=
Math
.
min
(
numBits
,
8
-
bitOffset
);
int
returnValue
=
((
data
[
tempByteOffset
++]
&
0xFF
)
>>
bitOffset
)
&
(
0xFF
>>
(
8
-
bitsRead
));
while
(
bitsRead
<
numBits
)
{
returnValue
|=
(
data
[
tempByteOffset
++]
&
0xFF
)
<<
bitsRead
;
bitsRead
+=
8
;
}
if
(
numBits
>
bitCount
)
{
int
bitsOnNextByte
=
numBits
-
bitCount
;
int
mask
=
0xFF
>>>
(
8
-
bitsOnNextByte
);
result
|=
(
data
[
byteOffset
]
&
mask
)
<<
bitCount
;
bitOffset
+=
bitsOnNextByte
;
}
return
result
;
returnValue
&=
0xFFFFFFFF
>>>
(
32
-
numBits
);
skipBits
(
numBits
);
return
returnValue
;
}
/**
* Skips {@code numberOfBits} bits.
*
* @param num
berOf
Bits The number of bits to skip.
* @param numBits The number of bits to skip.
*/
public
void
skipBits
(
int
num
berOf
Bits
)
{
Assertions
.
checkState
(
getPosition
()
+
numberOfBits
<=
limit
)
;
byteOffset
+=
num
berOfBits
/
8
;
bitOffset
+=
num
berOfBits
%
8
;
public
void
skipBits
(
int
numBits
)
{
int
numBytes
=
numBits
/
8
;
byteOffset
+=
num
Bytes
;
bitOffset
+=
num
Bits
-
(
numBytes
*
8
)
;
if
(
bitOffset
>
7
)
{
byteOffset
++;
bitOffset
-=
8
;
}
assertValidOffset
();
}
/**
...
...
@@ -136,23 +108,22 @@ import com.google.android.exoplayer2.util.Assertions;
* @param position The new reading position in bits.
*/
public
void
setPosition
(
int
position
)
{
Assertions
.
checkArgument
(
position
<
limit
&&
position
>=
0
);
byteOffset
=
position
/
8
;
bitOffset
=
position
-
(
byteOffset
*
8
);
assertValidOffset
();
}
/**
* Returns the number of remaining bits.
*/
public
int
bitsLeft
()
{
return
limit
-
getPosition
()
;
return
(
byteLimit
-
byteOffset
)
*
8
-
bitOffset
;
}
/**
* Returns the limit in bits.
**/
public
int
limit
()
{
return
limit
;
private
void
assertValidOffset
()
{
// It is fine for position to be at the end of the array, but no further.
Assertions
.
checkState
(
byteOffset
>=
0
&&
(
byteOffset
<
byteLimit
||
(
byteOffset
==
byteLimit
&&
bitOffset
==
0
)));
}
}
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H264Reader.java
View file @
cbffc14f
...
...
@@ -316,7 +316,7 @@ public final class H264Reader implements ElementaryStreamReader {
if
(!
bitArray
.
canReadBits
(
8
))
{
return
;
}
bitArray
.
skipBit
s
(
1
);
// forbidden_zero_bit
bitArray
.
skipBit
(
);
// forbidden_zero_bit
int
nalRefIdc
=
bitArray
.
readBits
(
2
);
bitArray
.
skipBits
(
5
);
// nal_unit_type
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H265Reader.java
View file @
cbffc14f
...
...
@@ -225,7 +225,7 @@ public final class H265Reader implements ElementaryStreamReader {
ParsableNalUnitBitArray
bitArray
=
new
ParsableNalUnitBitArray
(
sps
.
nalData
,
0
,
sps
.
nalLength
);
bitArray
.
skipBits
(
40
+
4
);
// NAL header, sps_video_parameter_set_id
int
maxSubLayersMinus1
=
bitArray
.
readBits
(
3
);
bitArray
.
skipBit
s
(
1
);
// sps_temporal_id_nesting_flag
bitArray
.
skipBit
(
);
// sps_temporal_id_nesting_flag
// profile_tier_level(1, sps_max_sub_layers_minus1)
bitArray
.
skipBits
(
88
);
// if (profilePresentFlag) {...}
...
...
@@ -247,7 +247,7 @@ public final class H265Reader implements ElementaryStreamReader {
bitArray
.
readUnsignedExpGolombCodedInt
();
// sps_seq_parameter_set_id
int
chromaFormatIdc
=
bitArray
.
readUnsignedExpGolombCodedInt
();
if
(
chromaFormatIdc
==
3
)
{
bitArray
.
skipBit
s
(
1
);
// separate_colour_plane_flag
bitArray
.
skipBit
(
);
// separate_colour_plane_flag
}
int
picWidthInLumaSamples
=
bitArray
.
readUnsignedExpGolombCodedInt
();
int
picHeightInLumaSamples
=
bitArray
.
readUnsignedExpGolombCodedInt
();
...
...
@@ -288,7 +288,7 @@ public final class H265Reader implements ElementaryStreamReader {
bitArray
.
skipBits
(
8
);
bitArray
.
readUnsignedExpGolombCodedInt
();
// log2_min_pcm_luma_coding_block_size_minus3
bitArray
.
readUnsignedExpGolombCodedInt
();
// log2_diff_max_min_pcm_luma_coding_block_size
bitArray
.
skipBit
s
(
1
);
// pcm_loop_filter_disabled_flag
bitArray
.
skipBit
(
);
// pcm_loop_filter_disabled_flag
}
// Skips all short term reference picture sets.
skipShortTermRefPicSets
(
bitArray
);
...
...
@@ -365,11 +365,11 @@ public final class H265Reader implements ElementaryStreamReader {
interRefPicSetPredictionFlag
=
bitArray
.
readBit
();
}
if
(
interRefPicSetPredictionFlag
)
{
bitArray
.
skipBit
s
(
1
);
// delta_rps_sign
bitArray
.
skipBit
(
);
// delta_rps_sign
bitArray
.
readUnsignedExpGolombCodedInt
();
// abs_delta_rps_minus1
for
(
int
j
=
0
;
j
<=
previousNumDeltaPocs
;
j
++)
{
if
(
bitArray
.
readBit
())
{
// used_by_curr_pic_flag[j]
bitArray
.
skipBit
s
(
1
);
// use_delta_flag[j]
bitArray
.
skipBit
(
);
// use_delta_flag[j]
}
}
}
else
{
...
...
@@ -378,11 +378,11 @@ public final class H265Reader implements ElementaryStreamReader {
previousNumDeltaPocs
=
numNegativePics
+
numPositivePics
;
for
(
int
i
=
0
;
i
<
numNegativePics
;
i
++)
{
bitArray
.
readUnsignedExpGolombCodedInt
();
// delta_poc_s0_minus1[i]
bitArray
.
skipBit
s
(
1
);
// used_by_curr_pic_s0_flag[i]
bitArray
.
skipBit
(
);
// used_by_curr_pic_s0_flag[i]
}
for
(
int
i
=
0
;
i
<
numPositivePics
;
i
++)
{
bitArray
.
readUnsignedExpGolombCodedInt
();
// delta_poc_s1_minus1[i]
bitArray
.
skipBit
s
(
1
);
// used_by_curr_pic_s1_flag[i]
bitArray
.
skipBit
(
);
// used_by_curr_pic_s1_flag[i]
}
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/SeiReader.java
View file @
cbffc14f
...
...
@@ -51,9 +51,10 @@ import java.util.List;
Assertions
.
checkArgument
(
MimeTypes
.
APPLICATION_CEA608
.
equals
(
channelMimeType
)
||
MimeTypes
.
APPLICATION_CEA708
.
equals
(
channelMimeType
),
"Invalid closed caption mime type provided: "
+
channelMimeType
);
output
.
format
(
Format
.
createTextSampleFormat
(
idGenerator
.
getFormatId
(),
channelMimeType
,
null
,
Format
.
NO_VALUE
,
channelFormat
.
selectionFlags
,
channelFormat
.
language
,
channelFormat
.
accessibilityChannel
,
null
));
String
formatId
=
channelFormat
.
id
!=
null
?
channelFormat
.
id
:
idGenerator
.
getFormatId
();
output
.
format
(
Format
.
createTextSampleFormat
(
formatId
,
channelMimeType
,
null
,
Format
.
NO_VALUE
,
channelFormat
.
selectionFlags
,
channelFormat
.
language
,
channelFormat
.
accessibilityChannel
,
null
));
outputs
[
i
]
=
output
;
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java
View file @
cbffc14f
...
...
@@ -111,7 +111,6 @@ public final class TsExtractor implements Extractor {
@Mode
private
final
int
mode
;
private
final
List
<
TimestampAdjuster
>
timestampAdjusters
;
private
final
ParsableByteArray
tsPacketBuffer
;
private
final
ParsableBitArray
tsScratch
;
private
final
SparseIntArray
continuityCounters
;
private
final
TsPayloadReader
.
Factory
payloadReaderFactory
;
private
final
SparseArray
<
TsPayloadReader
>
tsPayloadReaders
;
// Indexed by pid
...
...
@@ -164,7 +163,6 @@ public final class TsExtractor implements Extractor {
timestampAdjusters
.
add
(
timestampAdjuster
);
}
tsPacketBuffer
=
new
ParsableByteArray
(
BUFFER_SIZE
);
tsScratch
=
new
ParsableBitArray
(
new
byte
[
3
]);
trackIds
=
new
SparseBooleanArray
();
tsPayloadReaders
=
new
SparseArray
<>();
continuityCounters
=
new
SparseIntArray
();
...
...
@@ -250,24 +248,23 @@ public final class TsExtractor implements Extractor {
return
RESULT_CONTINUE
;
}
tsPacketBuffer
.
skipBytes
(
1
);
tsPacketBuffer
.
readBytes
(
tsScratch
,
3
);
if
(
tsScratch
.
readBit
())
{
// transport_error_indicator
int
tsPacketHeader
=
tsPacketBuffer
.
readInt
();
if
((
tsPacketHeader
&
0x800000
)
!=
0
)
{
// transport_error_indicator
// There are uncorrectable errors in this packet.
tsPacketBuffer
.
setPosition
(
endOfPacket
);
return
RESULT_CONTINUE
;
}
boolean
payloadUnitStartIndicator
=
tsScratch
.
readBit
()
;
tsScratch
.
skipBits
(
1
);
// transport_priority
int
pid
=
tsScratch
.
readBits
(
13
)
;
tsScratch
.
skipBits
(
2
);
// transport_scrambling_control
boolean
adaptationFieldExists
=
tsScratch
.
readBit
()
;
boolean
payloadExists
=
tsScratch
.
readBit
()
;
boolean
payloadUnitStartIndicator
=
(
tsPacketHeader
&
0x400000
)
!=
0
;
// Ignoring transport_priority (tsPacketHeader & 0x200000)
int
pid
=
(
tsPacketHeader
&
0x1FFF00
)
>>
8
;
// Ignoring transport_scrambling_control (tsPacketHeader & 0xC0)
boolean
adaptationFieldExists
=
(
tsPacketHeader
&
0x20
)
!=
0
;
boolean
payloadExists
=
(
tsPacketHeader
&
0x10
)
!=
0
;
// Discontinuity check.
boolean
discontinuityFound
=
false
;
int
continuityCounter
=
tsScratch
.
readBits
(
4
);
if
(
mode
!=
MODE_HLS
)
{
int
continuityCounter
=
tsPacketHeader
&
0xF
;
int
previousCounter
=
continuityCounters
.
get
(
pid
,
continuityCounter
-
1
);
continuityCounters
.
put
(
pid
,
continuityCounter
);
if
(
previousCounter
==
continuityCounter
)
{
...
...
@@ -276,7 +273,7 @@ public final class TsExtractor implements Extractor {
tsPacketBuffer
.
setPosition
(
endOfPacket
);
return
RESULT_CONTINUE
;
}
}
else
if
(
continuityCounter
!=
(
previousCounter
+
1
)
%
16
)
{
}
else
if
(
continuityCounter
!=
(
(
previousCounter
+
1
)
&
0xF
)
)
{
discontinuityFound
=
true
;
}
}
...
...
@@ -296,7 +293,6 @@ public final class TsExtractor implements Extractor {
}
tsPacketBuffer
.
setLimit
(
endOfPacket
);
payloadReader
.
consume
(
tsPacketBuffer
,
payloadUnitStartIndicator
);
Assertions
.
checkState
(
tsPacketBuffer
.
getPosition
()
<=
endOfPacket
);
tsPacketBuffer
.
setLimit
(
limit
);
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/util/FlacStreamInfo.java
View file @
cbffc14f
...
...
@@ -47,7 +47,8 @@ public final class FlacStreamInfo {
this
.
sampleRate
=
scratch
.
readBits
(
20
);
this
.
channels
=
scratch
.
readBits
(
3
)
+
1
;
this
.
bitsPerSample
=
scratch
.
readBits
(
5
)
+
1
;
this
.
totalSamples
=
scratch
.
readBits
(
36
);
this
.
totalSamples
=
((
scratch
.
readBits
(
4
)
&
0xF
L
)
<<
32
)
|
(
scratch
.
readBits
(
32
)
&
0xFFFFFFFF
L
);
// Remaining 16 bytes is md5 value
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/util/NalUnitUtil.java
View file @
cbffc14f
...
...
@@ -265,7 +265,7 @@ public final class NalUnitUtil {
}
data
.
readUnsignedExpGolombCodedInt
();
// bit_depth_luma_minus8
data
.
readUnsignedExpGolombCodedInt
();
// bit_depth_chroma_minus8
data
.
skipBit
s
(
1
);
// qpprime_y_zero_transform_bypass_flag
data
.
skipBit
(
);
// qpprime_y_zero_transform_bypass_flag
boolean
seqScalingMatrixPresentFlag
=
data
.
readBit
();
if
(
seqScalingMatrixPresentFlag
)
{
int
limit
=
(
chromaFormatIdc
!=
3
)
?
8
:
12
;
...
...
@@ -295,17 +295,17 @@ public final class NalUnitUtil {
}
}
data
.
readUnsignedExpGolombCodedInt
();
// max_num_ref_frames
data
.
skipBit
s
(
1
);
// gaps_in_frame_num_value_allowed_flag
data
.
skipBit
(
);
// gaps_in_frame_num_value_allowed_flag
int
picWidthInMbs
=
data
.
readUnsignedExpGolombCodedInt
()
+
1
;
int
picHeightInMapUnits
=
data
.
readUnsignedExpGolombCodedInt
()
+
1
;
boolean
frameMbsOnlyFlag
=
data
.
readBit
();
int
frameHeightInMbs
=
(
2
-
(
frameMbsOnlyFlag
?
1
:
0
))
*
picHeightInMapUnits
;
if
(!
frameMbsOnlyFlag
)
{
data
.
skipBit
s
(
1
);
// mb_adaptive_frame_field_flag
data
.
skipBit
(
);
// mb_adaptive_frame_field_flag
}
data
.
skipBit
s
(
1
);
// direct_8x8_inference_flag
data
.
skipBit
(
);
// direct_8x8_inference_flag
int
frameWidth
=
picWidthInMbs
*
16
;
int
frameHeight
=
frameHeightInMbs
*
16
;
boolean
frameCroppingFlag
=
data
.
readBit
();
...
...
@@ -368,7 +368,7 @@ public final class NalUnitUtil {
data
.
skipBits
(
8
);
// nal_unit
int
picParameterSetId
=
data
.
readUnsignedExpGolombCodedInt
();
int
seqParameterSetId
=
data
.
readUnsignedExpGolombCodedInt
();
data
.
skipBit
s
(
1
);
// entropy_coding_mode_flag
data
.
skipBit
(
);
// entropy_coding_mode_flag
boolean
bottomFieldPicOrderInFramePresentFlag
=
data
.
readBit
();
return
new
PpsData
(
picParameterSetId
,
seqParameterSetId
,
bottomFieldPicOrderInFramePresentFlag
);
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/util/ParsableBitArray.java
View file @
cbffc14f
...
...
@@ -111,13 +111,25 @@ public final class ParsableBitArray {
}
/**
* Skips a single bit.
*/
public
void
skipBit
()
{
if
(++
bitOffset
==
8
)
{
bitOffset
=
0
;
byteOffset
++;
}
assertValidOffset
();
}
/**
* Skips bits and moves current reading position forward.
*
* @param n The number of bits to skip.
* @param n
umBits
The number of bits to skip.
*/
public
void
skipBits
(
int
n
)
{
byteOffset
+=
(
n
/
8
);
bitOffset
+=
(
n
%
8
);
public
void
skipBits
(
int
numBits
)
{
int
numBytes
=
numBits
/
8
;
byteOffset
+=
numBytes
;
bitOffset
+=
numBits
-
(
numBytes
*
8
);
if
(
bitOffset
>
7
)
{
byteOffset
++;
bitOffset
-=
8
;
...
...
@@ -131,7 +143,9 @@ public final class ParsableBitArray {
* @return Whether the bit is set.
*/
public
boolean
readBit
()
{
return
readBits
(
1
)
==
1
;
boolean
returnValue
=
(
data
[
byteOffset
]
&
(
0x80
>>
bitOffset
))
!=
0
;
skipBit
();
return
returnValue
;
}
/**
...
...
@@ -141,48 +155,18 @@ public final class ParsableBitArray {
* @return An integer whose bottom n bits hold the read data.
*/
public
int
readBits
(
int
numBits
)
{
if
(
numBits
==
0
)
{
return
0
;
}
int
returnValue
=
0
;
// Read as many whole bytes as we can.
int
wholeBytes
=
(
numBits
/
8
);
for
(
int
i
=
0
;
i
<
wholeBytes
;
i
++)
{
int
byteValue
;
if
(
bitOffset
!=
0
)
{
byteValue
=
((
data
[
byteOffset
]
&
0xFF
)
<<
bitOffset
)
|
((
data
[
byteOffset
+
1
]
&
0xFF
)
>>>
(
8
-
bitOffset
));
}
else
{
byteValue
=
data
[
byteOffset
];
}
numBits
-=
8
;
returnValue
|=
(
byteValue
&
0xFF
)
<<
numBits
;
byteOffset
++;
bitOffset
+=
numBits
;
while
(
bitOffset
>
8
)
{
bitOffset
-=
8
;
returnValue
|=
(
data
[
byteOffset
++]
&
0xFF
)
<<
bitOffset
;
}
// Read any remaining bits.
if
(
numBits
>
0
)
{
int
nextBit
=
bitOffset
+
numBits
;
byte
writeMask
=
(
byte
)
(
0xFF
>>
(
8
-
numBits
));
if
(
nextBit
>
8
)
{
// Combine bits from current byte and next byte.
returnValue
|=
((((
data
[
byteOffset
]
&
0xFF
)
<<
(
nextBit
-
8
)
|
((
data
[
byteOffset
+
1
]
&
0xFF
)
>>
(
16
-
nextBit
)))
&
writeMask
));
byteOffset
++;
}
else
{
// Bits to be read only within current byte.
returnValue
|=
(((
data
[
byteOffset
]
&
0xFF
)
>>
(
8
-
nextBit
))
&
writeMask
);
if
(
nextBit
==
8
)
{
byteOffset
++;
}
}
bitOffset
=
nextBit
%
8
;
returnValue
|=
(
data
[
byteOffset
]
&
0xFF
)
>>
8
-
bitOffset
;
returnValue
&=
0xFFFFFFFF
>>>
(
32
-
numBits
);
if
(
bitOffset
==
8
)
{
bitOffset
=
0
;
byteOffset
++;
}
assertValidOffset
();
return
returnValue
;
}
...
...
@@ -231,7 +215,6 @@ public final class ParsableBitArray {
private
void
assertValidOffset
()
{
// It is fine for position to be at the end of the array, but no further.
Assertions
.
checkState
(
byteOffset
>=
0
&&
(
bitOffset
>=
0
&&
bitOffset
<
8
)
&&
(
byteOffset
<
byteLimit
||
(
byteOffset
==
byteLimit
&&
bitOffset
==
0
)));
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/util/ParsableNalUnitBitArray.java
View file @
cbffc14f
...
...
@@ -55,14 +55,26 @@ public final class ParsableNalUnitBitArray {
}
/**
* Skips a single bit.
*/
public
void
skipBit
()
{
if
(++
bitOffset
==
8
)
{
bitOffset
=
0
;
byteOffset
+=
shouldSkipByte
(
byteOffset
+
1
)
?
2
:
1
;
}
assertValidOffset
();
}
/**
* Skips bits and moves current reading position forward.
*
* @param n The number of bits to skip.
* @param n
umBits
The number of bits to skip.
*/
public
void
skipBits
(
int
n
)
{
public
void
skipBits
(
int
n
umBits
)
{
int
oldByteOffset
=
byteOffset
;
byteOffset
+=
(
n
/
8
);
bitOffset
+=
(
n
%
8
);
int
numBytes
=
numBits
/
8
;
byteOffset
+=
numBytes
;
bitOffset
+=
numBits
-
(
numBytes
*
8
);
if
(
bitOffset
>
7
)
{
byteOffset
++;
bitOffset
-=
8
;
...
...
@@ -81,13 +93,14 @@ public final class ParsableNalUnitBitArray {
* Returns whether it's possible to read {@code n} bits starting from the current offset. The
* offset is not modified.
*
* @param n The number of bits.
* @param n
umBits
The number of bits.
* @return Whether it is possible to read {@code n} bits.
*/
public
boolean
canReadBits
(
int
n
)
{
public
boolean
canReadBits
(
int
n
umBits
)
{
int
oldByteOffset
=
byteOffset
;
int
newByteOffset
=
byteOffset
+
(
n
/
8
);
int
newBitOffset
=
bitOffset
+
(
n
%
8
);
int
numBytes
=
numBits
/
8
;
int
newByteOffset
=
byteOffset
+
numBytes
;
int
newBitOffset
=
bitOffset
+
numBits
-
(
numBytes
*
8
);
if
(
newBitOffset
>
7
)
{
newByteOffset
++;
newBitOffset
-=
8
;
...
...
@@ -108,7 +121,9 @@ public final class ParsableNalUnitBitArray {
* @return Whether the bit is set.
*/
public
boolean
readBit
()
{
return
readBits
(
1
)
==
1
;
boolean
returnValue
=
(
data
[
byteOffset
]
&
(
0x80
>>
bitOffset
))
!=
0
;
skipBit
();
return
returnValue
;
}
/**
...
...
@@ -118,50 +133,19 @@ public final class ParsableNalUnitBitArray {
* @return An integer whose bottom n bits hold the read data.
*/
public
int
readBits
(
int
numBits
)
{
if
(
numBits
==
0
)
{
return
0
;
}
int
returnValue
=
0
;
// Read as many whole bytes as we can.
int
wholeBytes
=
(
numBits
/
8
);
for
(
int
i
=
0
;
i
<
wholeBytes
;
i
++)
{
int
nextByteOffset
=
shouldSkipByte
(
byteOffset
+
1
)
?
byteOffset
+
2
:
byteOffset
+
1
;
int
byteValue
;
if
(
bitOffset
!=
0
)
{
byteValue
=
((
data
[
byteOffset
]
&
0xFF
)
<<
bitOffset
)
|
((
data
[
nextByteOffset
]
&
0xFF
)
>>>
(
8
-
bitOffset
));
}
else
{
byteValue
=
data
[
byteOffset
];
}
numBits
-=
8
;
returnValue
|=
(
byteValue
&
0xFF
)
<<
numBits
;
byteOffset
=
nextByteOffset
;
bitOffset
+=
numBits
;
while
(
bitOffset
>
8
)
{
bitOffset
-=
8
;
returnValue
|=
(
data
[
byteOffset
]
&
0xFF
)
<<
bitOffset
;
byteOffset
+=
shouldSkipByte
(
byteOffset
+
1
)
?
2
:
1
;
}
// Read any remaining bits.
if
(
numBits
>
0
)
{
int
nextBit
=
bitOffset
+
numBits
;
byte
writeMask
=
(
byte
)
(
0xFF
>>
(
8
-
numBits
));
int
nextByteOffset
=
shouldSkipByte
(
byteOffset
+
1
)
?
byteOffset
+
2
:
byteOffset
+
1
;
if
(
nextBit
>
8
)
{
// Combine bits from current byte and next byte.
returnValue
|=
((((
data
[
byteOffset
]
&
0xFF
)
<<
(
nextBit
-
8
)
|
((
data
[
nextByteOffset
]
&
0xFF
)
>>
(
16
-
nextBit
)))
&
writeMask
));
byteOffset
=
nextByteOffset
;
}
else
{
// Bits to be read only within current byte.
returnValue
|=
(((
data
[
byteOffset
]
&
0xFF
)
>>
(
8
-
nextBit
))
&
writeMask
);
if
(
nextBit
==
8
)
{
byteOffset
=
nextByteOffset
;
}
}
bitOffset
=
nextBit
%
8
;
returnValue
|=
(
data
[
byteOffset
]
&
0xFF
)
>>
8
-
bitOffset
;
returnValue
&=
0xFFFFFFFF
>>>
(
32
-
numBits
);
if
(
bitOffset
==
8
)
{
bitOffset
=
0
;
byteOffset
+=
shouldSkipByte
(
byteOffset
+
1
)
?
2
:
1
;
}
assertValidOffset
();
return
returnValue
;
}
...
...
@@ -220,7 +204,6 @@ public final class ParsableNalUnitBitArray {
private
void
assertValidOffset
()
{
// It is fine for position to be at the end of the array, but no further.
Assertions
.
checkState
(
byteOffset
>=
0
&&
(
bitOffset
>=
0
&&
bitOffset
<
8
)
&&
(
byteOffset
<
byteLimit
||
(
byteOffset
==
byteLimit
&&
bitOffset
==
0
)));
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java
View file @
cbffc14f
...
...
@@ -578,9 +578,10 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
}
private
void
maybeNotifyVideoSizeChanged
()
{
if
(
reportedWidth
!=
currentWidth
||
reportedHeight
!=
currentHeight
if
((
currentWidth
!=
Format
.
NO_VALUE
||
currentHeight
!=
Format
.
NO_VALUE
)
&&
(
reportedWidth
!=
currentWidth
||
reportedHeight
!=
currentHeight
||
reportedUnappliedRotationDegrees
!=
currentUnappliedRotationDegrees
||
reportedPixelWidthHeightRatio
!=
currentPixelWidthHeightRatio
)
{
||
reportedPixelWidthHeightRatio
!=
currentPixelWidthHeightRatio
)
)
{
eventDispatcher
.
videoSizeChanged
(
currentWidth
,
currentHeight
,
currentUnappliedRotationDegrees
,
currentPixelWidthHeightRatio
);
reportedWidth
=
currentWidth
;
...
...
@@ -592,8 +593,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
private
void
maybeRenotifyVideoSizeChanged
()
{
if
(
reportedWidth
!=
Format
.
NO_VALUE
||
reportedHeight
!=
Format
.
NO_VALUE
)
{
eventDispatcher
.
videoSizeChanged
(
currentWidth
,
currentHeight
,
currentUnappliedRotationDegrees
,
current
PixelWidthHeightRatio
);
eventDispatcher
.
videoSizeChanged
(
reportedWidth
,
reportedHeight
,
reportedUnappliedRotationDegrees
,
reported
PixelWidthHeightRatio
);
}
}
...
...
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistTracker.java
View file @
cbffc14f
...
...
@@ -41,6 +41,38 @@ import java.util.List;
public
final
class
HlsPlaylistTracker
implements
Loader
.
Callback
<
ParsingLoadable
<
HlsPlaylist
>>
{
/**
* Thrown when a playlist is considered to be stuck due to a server side error.
*/
public
static
final
class
PlaylistStuckException
extends
IOException
{
/**
* The url of the stuck playlist.
*/
public
final
String
url
;
private
PlaylistStuckException
(
String
url
)
{
this
.
url
=
url
;
}
}
/**
* Thrown when the media sequence of a new snapshot indicates the server has reset.
*/
public
static
final
class
PlaylistResetException
extends
IOException
{
/**
* The url of the reset playlist.
*/
public
final
String
url
;
private
PlaylistResetException
(
String
url
)
{
this
.
url
=
url
;
}
}
/**
* Listener for primary playlist changes.
*/
public
interface
PrimaryPlaylistListener
{
...
...
@@ -76,6 +108,11 @@ public final class HlsPlaylistTracker implements Loader.Callback<ParsingLoadable
}
/**
* Coefficient applied on the target duration of a playlist to determine the amount of time after
* which an unchanging playlist is considered stuck.
*/
private
static
final
double
PLAYLIST_STUCK_TARGET_DURATION_COEFFICIENT
=
3.5
;
/**
* The minimum number of milliseconds that a url is kept as primary url, if no
* {@link #getPlaylistSnapshot} call is made for that url.
*/
...
...
@@ -213,14 +250,14 @@ public final class HlsPlaylistTracker implements Loader.Callback<ParsingLoadable
}
/**
* If the playlist is having trouble
loading the playlist referenced by the given {@link HlsUrl},
* this method throws the underlying error.
* If the playlist is having trouble
refreshing the playlist referenced by the given
*
{@link HlsUrl},
this method throws the underlying error.
*
* @param url The {@link HlsUrl}.
* @throws IOException The underyling error.
*/
public
void
maybeThrowPlaylistRefreshError
(
HlsUrl
url
)
throws
IOException
{
playlistBundles
.
get
(
url
).
m
ediaPlaylistLoader
.
maybeThrow
Error
();
playlistBundles
.
get
(
url
).
m
aybeThrowPlaylistRefresh
Error
();
}
/**
...
...
@@ -441,9 +478,11 @@ public final class HlsPlaylistTracker implements Loader.Callback<ParsingLoadable
private
HlsMediaPlaylist
playlistSnapshot
;
private
long
lastSnapshotLoadMs
;
private
long
lastSnapshotChangeMs
;
private
long
lastSnapshotAccessTimeMs
;
private
long
blacklistUntilMs
;
private
boolean
pendingRefresh
;
private
IOException
playlistError
;
public
MediaPlaylistBundle
(
HlsUrl
playlistUrl
,
long
initialLastSnapshotAccessTimeMs
)
{
this
.
playlistUrl
=
playlistUrl
;
...
...
@@ -483,6 +522,13 @@ public final class HlsPlaylistTracker implements Loader.Callback<ParsingLoadable
}
}
public
void
maybeThrowPlaylistRefreshError
()
throws
IOException
{
mediaPlaylistLoader
.
maybeThrowError
();
if
(
playlistError
!=
null
)
{
throw
playlistError
;
}
}
// Loader.Callback implementation.
@Override
...
...
@@ -494,8 +540,7 @@ public final class HlsPlaylistTracker implements Loader.Callback<ParsingLoadable
eventDispatcher
.
loadCompleted
(
loadable
.
dataSpec
,
C
.
DATA_TYPE_MANIFEST
,
elapsedRealtimeMs
,
loadDurationMs
,
loadable
.
bytesLoaded
());
}
else
{
onLoadError
(
loadable
,
elapsedRealtimeMs
,
loadDurationMs
,
new
ParserException
(
"Loaded playlist has unexpected type."
));
playlistError
=
new
ParserException
(
"Loaded playlist has unexpected type."
);
}
}
...
...
@@ -517,10 +562,7 @@ public final class HlsPlaylistTracker implements Loader.Callback<ParsingLoadable
}
boolean
shouldRetry
=
true
;
if
(
ChunkedTrackBlacklistUtil
.
shouldBlacklist
(
error
))
{
blacklistUntilMs
=
SystemClock
.
elapsedRealtime
()
+
ChunkedTrackBlacklistUtil
.
DEFAULT_TRACK_BLACKLIST_MS
;
notifyPlaylistBlacklisting
(
playlistUrl
,
ChunkedTrackBlacklistUtil
.
DEFAULT_TRACK_BLACKLIST_MS
);
blacklistPlaylist
();
shouldRetry
=
primaryHlsUrl
==
playlistUrl
&&
!
maybeSelectNewPrimaryUrl
();
}
return
shouldRetry
?
Loader
.
RETRY
:
Loader
.
DONT_RETRY
;
...
...
@@ -538,14 +580,28 @@ public final class HlsPlaylistTracker implements Loader.Callback<ParsingLoadable
private
void
processLoadedPlaylist
(
HlsMediaPlaylist
loadedPlaylist
)
{
HlsMediaPlaylist
oldPlaylist
=
playlistSnapshot
;
lastSnapshotLoadMs
=
SystemClock
.
elapsedRealtime
();
long
currentTimeMs
=
SystemClock
.
elapsedRealtime
();
lastSnapshotLoadMs
=
currentTimeMs
;
playlistSnapshot
=
getLatestPlaylistSnapshot
(
oldPlaylist
,
loadedPlaylist
);
long
refreshDelayUs
=
C
.
TIME_UNSET
;
if
(
playlistSnapshot
!=
oldPlaylist
)
{
playlistError
=
null
;
lastSnapshotChangeMs
=
currentTimeMs
;
if
(
onPlaylistUpdated
(
playlistUrl
,
playlistSnapshot
))
{
refreshDelayUs
=
playlistSnapshot
.
targetDurationUs
;
}
}
else
if
(!
playlistSnapshot
.
hasEndTag
)
{
if
(
currentTimeMs
-
lastSnapshotChangeMs
>
C
.
usToMs
(
playlistSnapshot
.
targetDurationUs
)
*
PLAYLIST_STUCK_TARGET_DURATION_COEFFICIENT
)
{
// The playlist seems to be stuck, we blacklist it.
playlistError
=
new
PlaylistStuckException
(
playlistUrl
.
url
);
blacklistPlaylist
();
}
else
if
(
loadedPlaylist
.
mediaSequence
+
loadedPlaylist
.
segments
.
size
()
<
playlistSnapshot
.
mediaSequence
)
{
// The media sequence has jumped backwards. The server has likely reset.
playlistError
=
new
PlaylistResetException
(
playlistUrl
.
url
);
}
refreshDelayUs
=
playlistSnapshot
.
targetDurationUs
/
2
;
}
if
(
refreshDelayUs
!=
C
.
TIME_UNSET
)
{
...
...
@@ -554,6 +610,12 @@ public final class HlsPlaylistTracker implements Loader.Callback<ParsingLoadable
}
}
private
void
blacklistPlaylist
()
{
blacklistUntilMs
=
SystemClock
.
elapsedRealtime
()
+
ChunkedTrackBlacklistUtil
.
DEFAULT_TRACK_BLACKLIST_MS
;
notifyPlaylistBlacklisting
(
playlistUrl
,
ChunkedTrackBlacklistUtil
.
DEFAULT_TRACK_BLACKLIST_MS
);
}
}
}
library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java
View file @
cbffc14f
...
...
@@ -712,7 +712,12 @@ public class PlaybackControlView extends FrameLayout {
if
(
fastForwardMs
<=
0
)
{
return
;
}
seekTo
(
Math
.
min
(
player
.
getCurrentPosition
()
+
fastForwardMs
,
player
.
getDuration
()));
long
durationMs
=
player
.
getDuration
();
long
seekPositionMs
=
player
.
getCurrentPosition
()
+
fastForwardMs
;
if
(
durationMs
!=
C
.
TIME_UNSET
)
{
seekPositionMs
=
Math
.
min
(
seekPositionMs
,
durationMs
);
}
seekTo
(
seekPositionMs
);
}
private
void
seekTo
(
long
positionMs
)
{
...
...
library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java
View file @
cbffc14f
...
...
@@ -574,7 +574,8 @@ public final class SimpleExoPlayerView extends FrameLayout {
/**
* Sets the rewind increment in milliseconds.
*
* @param rewindMs The rewind increment in milliseconds.
* @param rewindMs The rewind increment in milliseconds. A non-positive value will cause the
* rewind button to be disabled.
*/
public
void
setRewindIncrementMs
(
int
rewindMs
)
{
Assertions
.
checkState
(
controller
!=
null
);
...
...
@@ -584,7 +585,8 @@ public final class SimpleExoPlayerView extends FrameLayout {
/**
* Sets the fast forward increment in milliseconds.
*
* @param fastForwardMs The fast forward increment in milliseconds.
* @param fastForwardMs The fast forward increment in milliseconds. A non-positive value will
* cause the fast forward button to be disabled.
*/
public
void
setFastForwardIncrementMs
(
int
fastForwardMs
)
{
Assertions
.
checkState
(
controller
!=
null
);
...
...
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