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
7df99381
authored
Jun 03, 2020
by
kimvde
Committed by
Oliver Woodman
Jun 04, 2020
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Optimize extractors order using file extension
PiperOrigin-RevId: 314508481
parent
3904f677
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
207 additions
and
70 deletions
RELEASENOTES.md
library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaSource.java
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/DefaultExtractorsFactory.java
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ExtractorsFactory.java
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/DefaultExtractorsFactoryTest.java
RELEASENOTES.md
View file @
7df99381
...
@@ -156,12 +156,17 @@
...
@@ -156,12 +156,17 @@
*
HLS:
*
HLS:
*
Add support for upstream discard including cancelation of ongoing load
*
Add support for upstream discard including cancelation of ongoing load
(
[
#6322
](
https://github.com/google/ExoPlayer/issues/6322
)
).
(
[
#6322
](
https://github.com/google/ExoPlayer/issues/6322
)
).
*
MP3
:
*
Extractors
:
*
Add
`IndexSeeker`
for accurate seeks in VBR streams
*
Add
`IndexSeeker`
for accurate seeks in VBR
MP3
streams
(
[
#6787
](
https://github.com/google/ExoPlayer/issues/6787
)
). This seeker
(
[
#6787
](
https://github.com/google/ExoPlayer/issues/6787
)
). This seeker
is enabled by passing
`FLAG_ENABLE_INDEX_SEEKING`
to the
`Mp3Extractor`
.
is enabled by passing
`FLAG_ENABLE_INDEX_SEEKING`
to the
`Mp3Extractor`
.
It may require to scan a significant portion of the file for seeking,
It may require to scan a significant portion of the file for seeking,
which may be costly on large files.
which may be costly on large files.
*
Change the order of extractors for sniffing to reduce start-up latency
in
`DefaultExtractorsFactory`
and
`DefaultHlsExtractorsFactory`
(
[
#6410
](
https://github.com/google/ExoPlayer/issues/6410
)
).
*
Select first extractors based on the filename extension in
`DefaultExtractorsFactory`
.
*
Testing
*
Testing
*
Add
`TestExoPlayer`
, a utility class with APIs to create
*
Add
`TestExoPlayer`
, a utility class with APIs to create
`SimpleExoPlayer`
instances with fake components for testing.
`SimpleExoPlayer`
instances with fake components for testing.
...
@@ -179,9 +184,6 @@
...
@@ -179,9 +184,6 @@
*
Cast extension: Implement playlist API and deprecate the old queue
*
Cast extension: Implement playlist API and deprecate the old queue
manipulation API.
manipulation API.
*
Demo app: Retain previous position in list of samples.
*
Demo app: Retain previous position in list of samples.
*
Change the order of extractors for sniffing to reduce start-up latency in
`DefaultExtractorsFactory`
and
`DefaultHlsExtractorsFactory`
(
[
#6410
](
https://github.com/google/ExoPlayer/issues/6410
)
).
*
Add Guava dependency.
*
Add Guava dependency.
### 2.11.5 (2020-06-03) ###
### 2.11.5 (2020-06-03) ###
...
...
library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaSource.java
View file @
7df99381
...
@@ -276,7 +276,7 @@ public final class ProgressiveMediaSource extends BaseMediaSource
...
@@ -276,7 +276,7 @@ public final class ProgressiveMediaSource extends BaseMediaSource
return
new
ProgressiveMediaPeriod
(
return
new
ProgressiveMediaPeriod
(
playbackProperties
.
uri
,
playbackProperties
.
uri
,
dataSource
,
dataSource
,
extractorsFactory
.
createExtractors
(),
extractorsFactory
.
createExtractors
(
playbackProperties
.
uri
),
drmSessionManager
,
drmSessionManager
,
loadableLoadErrorHandlingPolicy
,
loadableLoadErrorHandlingPolicy
,
createEventDispatcher
(
id
),
createEventDispatcher
(
id
),
...
...
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/DefaultExtractorsFactory.java
View file @
7df99381
...
@@ -15,6 +15,23 @@
...
@@ -15,6 +15,23 @@
*/
*/
package
com
.
google
.
android
.
exoplayer2
.
extractor
;
package
com
.
google
.
android
.
exoplayer2
.
extractor
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
FilenameUtil
.
FILE_FORMAT_AC3
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
FilenameUtil
.
FILE_FORMAT_AC4
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
FilenameUtil
.
FILE_FORMAT_ADTS
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
FilenameUtil
.
FILE_FORMAT_AMR
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
FilenameUtil
.
FILE_FORMAT_FLAC
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
FilenameUtil
.
FILE_FORMAT_FLV
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
FilenameUtil
.
FILE_FORMAT_MATROSKA
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
FilenameUtil
.
FILE_FORMAT_MP3
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
FilenameUtil
.
FILE_FORMAT_MP4
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
FilenameUtil
.
FILE_FORMAT_OGG
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
FilenameUtil
.
FILE_FORMAT_PS
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
FilenameUtil
.
FILE_FORMAT_TS
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
FilenameUtil
.
FILE_FORMAT_UNKNOWN
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
FilenameUtil
.
FILE_FORMAT_WAV
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
FilenameUtil
.
getFormatFromExtension
;
import
android.net.Uri
;
import
androidx.annotation.Nullable
;
import
androidx.annotation.Nullable
;
import
com.google.android.exoplayer2.extractor.amr.AmrExtractor
;
import
com.google.android.exoplayer2.extractor.amr.AmrExtractor
;
import
com.google.android.exoplayer2.extractor.flac.FlacExtractor
;
import
com.google.android.exoplayer2.extractor.flac.FlacExtractor
;
...
@@ -32,8 +49,11 @@ import com.google.android.exoplayer2.extractor.ts.PsExtractor;
...
@@ -32,8 +49,11 @@ import com.google.android.exoplayer2.extractor.ts.PsExtractor;
import
com.google.android.exoplayer2.extractor.ts.TsExtractor
;
import
com.google.android.exoplayer2.extractor.ts.TsExtractor
;
import
com.google.android.exoplayer2.extractor.ts.TsPayloadReader
;
import
com.google.android.exoplayer2.extractor.ts.TsPayloadReader
;
import
com.google.android.exoplayer2.extractor.wav.WavExtractor
;
import
com.google.android.exoplayer2.extractor.wav.WavExtractor
;
import
com.google.android.exoplayer2.util.FilenameUtil
;
import
com.google.android.exoplayer2.util.TimestampAdjuster
;
import
com.google.android.exoplayer2.util.TimestampAdjuster
;
import
java.lang.reflect.Constructor
;
import
java.lang.reflect.Constructor
;
import
java.util.ArrayList
;
import
java.util.List
;
/**
/**
* An {@link ExtractorsFactory} that provides an array of extractors for the following formats:
* An {@link ExtractorsFactory} that provides an array of extractors for the following formats:
...
@@ -63,6 +83,25 @@ import java.lang.reflect.Constructor;
...
@@ -63,6 +83,25 @@ import java.lang.reflect.Constructor;
*/
*/
public
final
class
DefaultExtractorsFactory
implements
ExtractorsFactory
{
public
final
class
DefaultExtractorsFactory
implements
ExtractorsFactory
{
// Extractors order is optimized according to
// https://docs.google.com/document/d/1w2mKaWMxfz2Ei8-LdxqbPs1VLe_oudB-eryXXw9OvQQ.
private
static
final
int
[]
DEFAULT_EXTRACTOR_ORDER
=
new
int
[]
{
FILE_FORMAT_FLV
,
FILE_FORMAT_FLAC
,
FILE_FORMAT_WAV
,
FILE_FORMAT_MP4
,
FILE_FORMAT_AMR
,
FILE_FORMAT_PS
,
FILE_FORMAT_OGG
,
FILE_FORMAT_TS
,
FILE_FORMAT_MATROSKA
,
FILE_FORMAT_ADTS
,
FILE_FORMAT_AC3
,
FILE_FORMAT_AC4
,
FILE_FORMAT_MP3
,
};
@Nullable
@Nullable
private
static
final
Constructor
<?
extends
Extractor
>
FLAC_EXTENSION_EXTRACTOR_CONSTRUCTOR
;
private
static
final
Constructor
<?
extends
Extractor
>
FLAC_EXTENSION_EXTRACTOR_CONSTRUCTOR
;
...
@@ -240,48 +279,96 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory {
...
@@ -240,48 +279,96 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory {
@Override
@Override
public
synchronized
Extractor
[]
createExtractors
()
{
public
synchronized
Extractor
[]
createExtractors
()
{
Extractor
[]
extractors
=
new
Extractor
[
14
];
return
createExtractors
(
Uri
.
EMPTY
);
// Extractors order is optimized according to
}
// https://docs.google.com/document/d/1w2mKaWMxfz2Ei8-LdxqbPs1VLe_oudB-eryXXw9OvQQ.
extractors
[
0
]
=
new
FlvExtractor
();
@Override
if
(
FLAC_EXTENSION_EXTRACTOR_CONSTRUCTOR
!=
null
)
{
public
synchronized
Extractor
[]
createExtractors
(
Uri
uri
)
{
try
{
List
<
Extractor
>
extractors
=
new
ArrayList
<>(
/* initialCapacity= */
14
);
extractors
[
1
]
=
FLAC_EXTENSION_EXTRACTOR_CONSTRUCTOR
.
newInstance
();
}
catch
(
Exception
e
)
{
String
filename
=
uri
.
getLastPathSegment
();
// Should never happen.
@FilenameUtil
.
FileFormat
throw
new
IllegalStateException
(
"Unexpected error creating FLAC extractor"
,
e
);
int
extensionFormat
=
filename
==
null
?
FILE_FORMAT_UNKNOWN
:
getFormatFromExtension
(
filename
);
addExtractorsForFormat
(
extensionFormat
,
extractors
);
for
(
int
format
:
DEFAULT_EXTRACTOR_ORDER
)
{
if
(
format
!=
extensionFormat
)
{
addExtractorsForFormat
(
format
,
extractors
);
}
}
}
else
{
extractors
[
1
]
=
new
FlacExtractor
(
coreFlacFlags
);
}
}
extractors
[
2
]
=
new
WavExtractor
();
extractors
[
3
]
=
new
FragmentedMp4Extractor
(
fragmentedMp4Flags
);
return
extractors
.
toArray
(
new
Extractor
[
extractors
.
size
()]);
extractors
[
4
]
=
new
Mp4Extractor
(
mp4Flags
);
extractors
[
5
]
=
new
AmrExtractor
(
amrFlags
|
(
constantBitrateSeekingEnabled
?
AmrExtractor
.
FLAG_ENABLE_CONSTANT_BITRATE_SEEKING
:
0
));
extractors
[
6
]
=
new
PsExtractor
();
extractors
[
7
]
=
new
OggExtractor
();
extractors
[
8
]
=
new
TsExtractor
(
tsMode
,
tsFlags
);
extractors
[
9
]
=
new
MatroskaExtractor
(
matroskaFlags
);
extractors
[
10
]
=
new
AdtsExtractor
(
adtsFlags
|
(
constantBitrateSeekingEnabled
?
AdtsExtractor
.
FLAG_ENABLE_CONSTANT_BITRATE_SEEKING
:
0
));
extractors
[
11
]
=
new
Ac3Extractor
();
extractors
[
12
]
=
new
Ac4Extractor
();
extractors
[
13
]
=
new
Mp3Extractor
(
mp3Flags
|
(
constantBitrateSeekingEnabled
?
Mp3Extractor
.
FLAG_ENABLE_CONSTANT_BITRATE_SEEKING
:
0
));
return
extractors
;
}
}
private
void
addExtractorsForFormat
(
@FilenameUtil
.
FileFormat
int
fileFormat
,
List
<
Extractor
>
extractors
)
{
switch
(
fileFormat
)
{
case
FILE_FORMAT_AC3:
extractors
.
add
(
new
Ac3Extractor
());
break
;
case
FILE_FORMAT_AC4:
extractors
.
add
(
new
Ac4Extractor
());
break
;
case
FILE_FORMAT_ADTS:
extractors
.
add
(
new
AdtsExtractor
(
adtsFlags
|
(
constantBitrateSeekingEnabled
?
AdtsExtractor
.
FLAG_ENABLE_CONSTANT_BITRATE_SEEKING
:
0
)));
break
;
case
FILE_FORMAT_AMR:
extractors
.
add
(
new
AmrExtractor
(
amrFlags
|
(
constantBitrateSeekingEnabled
?
AmrExtractor
.
FLAG_ENABLE_CONSTANT_BITRATE_SEEKING
:
0
)));
break
;
case
FILE_FORMAT_FLAC:
if
(
FLAC_EXTENSION_EXTRACTOR_CONSTRUCTOR
!=
null
)
{
try
{
extractors
.
add
(
FLAC_EXTENSION_EXTRACTOR_CONSTRUCTOR
.
newInstance
());
}
catch
(
Exception
e
)
{
// Should never happen.
throw
new
IllegalStateException
(
"Unexpected error creating FLAC extractor"
,
e
);
}
}
else
{
extractors
.
add
(
new
FlacExtractor
(
coreFlacFlags
));
}
break
;
case
FILE_FORMAT_FLV:
extractors
.
add
(
new
FlvExtractor
());
break
;
case
FILE_FORMAT_MATROSKA:
extractors
.
add
(
new
MatroskaExtractor
(
matroskaFlags
));
break
;
case
FILE_FORMAT_MP3:
extractors
.
add
(
new
Mp3Extractor
(
mp3Flags
|
(
constantBitrateSeekingEnabled
?
Mp3Extractor
.
FLAG_ENABLE_CONSTANT_BITRATE_SEEKING
:
0
)));
break
;
case
FILE_FORMAT_MP4:
extractors
.
add
(
new
FragmentedMp4Extractor
(
fragmentedMp4Flags
));
extractors
.
add
(
new
Mp4Extractor
(
mp4Flags
));
break
;
case
FILE_FORMAT_OGG:
extractors
.
add
(
new
OggExtractor
());
break
;
case
FILE_FORMAT_PS:
extractors
.
add
(
new
PsExtractor
());
break
;
case
FILE_FORMAT_TS:
extractors
.
add
(
new
TsExtractor
(
tsMode
,
tsFlags
));
break
;
case
FILE_FORMAT_WAV:
extractors
.
add
(
new
WavExtractor
());
break
;
default
:
break
;
}
}
}
}
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ExtractorsFactory.java
View file @
7df99381
...
@@ -15,9 +15,19 @@
...
@@ -15,9 +15,19 @@
*/
*/
package
com
.
google
.
android
.
exoplayer2
.
extractor
;
package
com
.
google
.
android
.
exoplayer2
.
extractor
;
import
android.net.Uri
;
/** Factory for arrays of {@link Extractor} instances. */
/** Factory for arrays of {@link Extractor} instances. */
public
interface
ExtractorsFactory
{
public
interface
ExtractorsFactory
{
/** Returns an array of new {@link Extractor} instances. */
/** Returns an array of new {@link Extractor} instances. */
Extractor
[]
createExtractors
();
Extractor
[]
createExtractors
();
/**
* Returns an array of new {@link Extractor} instances to extract the stream corresponding to the
* provided {@link Uri}.
*/
default
Extractor
[]
createExtractors
(
Uri
uri
)
{
return
createExtractors
();
}
}
}
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/DefaultExtractorsFactoryTest.java
View file @
7df99381
...
@@ -17,6 +17,7 @@ package com.google.android.exoplayer2.extractor;
...
@@ -17,6 +17,7 @@ package com.google.android.exoplayer2.extractor;
import
static
com
.
google
.
common
.
truth
.
Truth
.
assertThat
;
import
static
com
.
google
.
common
.
truth
.
Truth
.
assertThat
;
import
android.net.Uri
;
import
androidx.test.ext.junit.runners.AndroidJUnit4
;
import
androidx.test.ext.junit.runners.AndroidJUnit4
;
import
com.google.android.exoplayer2.extractor.amr.AmrExtractor
;
import
com.google.android.exoplayer2.extractor.amr.AmrExtractor
;
import
com.google.android.exoplayer2.extractor.flac.FlacExtractor
;
import
com.google.android.exoplayer2.extractor.flac.FlacExtractor
;
...
@@ -42,34 +43,71 @@ import org.junit.runner.RunWith;
...
@@ -42,34 +43,71 @@ import org.junit.runner.RunWith;
public
final
class
DefaultExtractorsFactoryTest
{
public
final
class
DefaultExtractorsFactoryTest
{
@Test
@Test
public
void
createExtractors_
returnExpectedClasses
()
{
public
void
createExtractors_
withoutUri_optimizesSniffingOrder
()
{
DefaultExtractorsFactory
defaultExtractorsFactory
=
new
DefaultExtractorsFactory
();
DefaultExtractorsFactory
defaultExtractorsFactory
=
new
DefaultExtractorsFactory
();
Extractor
[]
extractors
=
defaultExtractorsFactory
.
createExtractors
();
Extractor
[]
extractors
=
defaultExtractorsFactory
.
createExtractors
();
List
<
Class
<?>>
listCreatedExtractorClasses
=
new
ArrayList
<>();
for
(
Extractor
extractor
:
extractors
)
{
listCreatedExtractorClasses
.
add
(
extractor
.
getClass
());
}
Class
<?>[]
expectedExtractorClassses
=
List
<
Class
<?
extends
Extractor
>>
extractorClasses
=
getExtractorClasses
(
extractors
);
new
Class
<?>[]
{
assertThat
(
extractorClasses
.
subList
(
0
,
3
))
MatroskaExtractor
.
class
,
.
containsExactly
(
FlvExtractor
.
class
,
FlacExtractor
.
class
,
WavExtractor
.
class
)
FragmentedMp4Extractor
.
class
,
.
inOrder
();
Mp4Extractor
.
class
,
assertThat
(
extractorClasses
.
subList
(
3
,
5
))
Mp3Extractor
.
class
,
.
containsExactly
(
Mp4Extractor
.
class
,
FragmentedMp4Extractor
.
class
);
AdtsExtractor
.
class
,
assertThat
(
extractorClasses
.
subList
(
5
,
extractors
.
length
))
Ac3Extractor
.
class
,
.
containsExactly
(
TsExtractor
.
class
,
AmrExtractor
.
class
,
FlvExtractor
.
class
,
PsExtractor
.
class
,
OggExtractor
.
class
,
OggExtractor
.
class
,
PsExtractor
.
class
,
TsExtractor
.
class
,
WavExtractor
.
class
,
MatroskaExtractor
.
class
,
AmrExtractor
.
class
,
AdtsExtractor
.
class
,
Ac4Extractor
.
class
,
Ac3Extractor
.
class
,
FlacExtractor
.
class
Ac4Extractor
.
class
,
};
Mp3Extractor
.
class
)
.
inOrder
();
}
@Test
public
void
createExtractors_withUri_startsWithExtractorsMatchingExtension
()
{
DefaultExtractorsFactory
defaultExtractorsFactory
=
new
DefaultExtractorsFactory
();
Extractor
[]
extractors
=
defaultExtractorsFactory
.
createExtractors
(
Uri
.
parse
(
"test.mp4"
));
List
<
Class
<?
extends
Extractor
>>
extractorClasses
=
getExtractorClasses
(
extractors
);
assertThat
(
extractorClasses
.
subList
(
0
,
2
))
.
containsExactly
(
Mp4Extractor
.
class
,
FragmentedMp4Extractor
.
class
);
}
assertThat
(
listCreatedExtractorClasses
).
containsNoDuplicates
();
@Test
assertThat
(
listCreatedExtractorClasses
).
containsExactlyElementsIn
(
expectedExtractorClassses
);
public
void
createExtractors_withUri_optimizesSniffingOrder
()
{
DefaultExtractorsFactory
defaultExtractorsFactory
=
new
DefaultExtractorsFactory
();
Extractor
[]
extractors
=
defaultExtractorsFactory
.
createExtractors
(
Uri
.
parse
(
"test.mp4"
));
List
<
Class
<?
extends
Extractor
>>
extractorClasses
=
getExtractorClasses
(
extractors
);
assertThat
(
extractorClasses
.
subList
(
2
,
extractors
.
length
))
.
containsExactly
(
FlvExtractor
.
class
,
FlacExtractor
.
class
,
WavExtractor
.
class
,
AmrExtractor
.
class
,
PsExtractor
.
class
,
OggExtractor
.
class
,
TsExtractor
.
class
,
MatroskaExtractor
.
class
,
AdtsExtractor
.
class
,
Ac3Extractor
.
class
,
Ac4Extractor
.
class
,
Mp3Extractor
.
class
)
.
inOrder
();
}
private
static
List
<
Class
<?
extends
Extractor
>>
getExtractorClasses
(
Extractor
[]
extractors
)
{
List
<
Class
<?
extends
Extractor
>>
extractorClasses
=
new
ArrayList
<>();
for
(
Extractor
extractor
:
extractors
)
{
extractorClasses
.
add
(
extractor
.
getClass
());
}
return
extractorClasses
;
}
}
}
}
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