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
78ecb10a
authored
Jul 15, 2021
by
bachinger
Committed by
Ian Baker
Jul 16, 2021
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Add RepresentationHolder.selectedBaseUrl and use it for new chunks
PiperOrigin-RevId: 384968532
parent
99abb4e1
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
173 additions
and
26 deletions
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashUtil.java
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashUtil.java
View file @
78ecb10a
...
...
@@ -46,24 +46,42 @@ public final class DashUtil {
/**
* Builds a {@link DataSpec} for a given {@link RangedUri} belonging to {@link Representation}.
*
* @param
representation The {@link Representation} to which the request belongs
.
* @param
baseUrl The base url with which to resolve the request URI
.
* @param requestUri The {@link RangedUri} of the data to request.
* @param cacheKey An optional cache key.
* @param flags Flags to be set on the returned {@link DataSpec}. See {@link
* DataSpec.Builder#setFlags(int)}.
* @return The {@link DataSpec}.
*/
public
static
DataSpec
buildDataSpec
(
Representation
representation
,
RangedUri
requestUri
,
int
flags
)
{
String
baseUrl
,
RangedUri
requestUri
,
@Nullable
String
cacheKey
,
int
flags
)
{
return
new
DataSpec
.
Builder
()
.
setUri
(
requestUri
.
resolveUri
(
representation
.
baseUrls
.
get
(
0
).
u
rl
))
.
setUri
(
requestUri
.
resolveUri
(
baseU
rl
))
.
setPosition
(
requestUri
.
start
)
.
setLength
(
requestUri
.
length
)
.
setKey
(
representation
.
getCacheKey
()
)
.
setKey
(
cacheKey
)
.
setFlags
(
flags
)
.
build
();
}
/**
* Builds a {@link DataSpec} for a given {@link RangedUri} belonging to {@link Representation}.
*
* <p>Uses the first base URL of the representation to build the data spec.
*
* @param representation The {@link Representation} to which the request belongs.
* @param requestUri The {@link RangedUri} of the data to request.
* @param flags Flags to be set on the returned {@link DataSpec}. See {@link
* DataSpec.Builder#setFlags(int)}.
* @return The {@link DataSpec}.
*/
public
static
DataSpec
buildDataSpec
(
Representation
representation
,
RangedUri
requestUri
,
int
flags
)
{
return
buildDataSpec
(
representation
.
baseUrls
.
get
(
0
).
url
,
requestUri
,
representation
.
getCacheKey
(),
flags
);
}
/**
* Loads a DASH manifest.
*
* @param dataSource The {@link HttpDataSource} from which the manifest should be read.
...
...
@@ -96,6 +114,7 @@ public final class DashUtil {
}
}
Format
manifestFormat
=
representation
.
format
;
@Nullable
Format
sampleFormat
=
DashUtil
.
loadSampleFormat
(
dataSource
,
primaryTrackType
,
representation
);
return
sampleFormat
==
null
?
manifestFormat
...
...
@@ -109,18 +128,22 @@ public final class DashUtil {
* @param trackType The type of the representation. Typically one of the {@link
* com.google.android.exoplayer2.C} {@code TRACK_TYPE_*} constants.
* @param representation The representation which initialization chunk belongs to.
* @param baseUrlIndex The index of the base URL to be picked from the {@link
* Representation#baseUrls list of base URLs}.
* @return the sample {@link Format} of the given representation.
* @throws IOException Thrown when there is an error while loading.
*/
@Nullable
public
static
Format
loadSampleFormat
(
DataSource
dataSource
,
int
trackType
,
Representation
representation
)
throws
IOException
{
DataSource
dataSource
,
int
trackType
,
Representation
representation
,
int
baseUrlIndex
)
throws
IOException
{
if
(
representation
.
getInitializationUri
()
==
null
)
{
return
null
;
}
ChunkExtractor
chunkExtractor
=
newChunkExtractor
(
trackType
,
representation
.
format
);
try
{
loadInitializationData
(
chunkExtractor
,
dataSource
,
representation
,
/* loadIndex= */
false
);
loadInitializationData
(
chunkExtractor
,
dataSource
,
representation
,
baseUrlIndex
,
/* loadIndex= */
false
);
}
finally
{
chunkExtractor
.
release
();
}
...
...
@@ -128,6 +151,24 @@ public final class DashUtil {
}
/**
* Loads initialization data for the {@code representation} and returns the sample {@link Format}.
*
* <p>Uses the first base URL for loading the format.
*
* @param dataSource The source from which the data should be loaded.
* @param trackType The type of the representation. Typically one of the {@link
* com.google.android.exoplayer2.C} {@code TRACK_TYPE_*} constants.
* @param representation The representation which initialization chunk belongs to.
* @return the sample {@link Format} of the given representation.
* @throws IOException Thrown when there is an error while loading.
*/
@Nullable
public
static
Format
loadSampleFormat
(
DataSource
dataSource
,
int
trackType
,
Representation
representation
)
throws
IOException
{
return
loadSampleFormat
(
dataSource
,
trackType
,
representation
,
/* baseUrlIndex= */
0
);
}
/**
* Loads initialization and index data for the {@code representation} and returns the {@link
* ChunkIndex}.
*
...
...
@@ -135,19 +176,22 @@ public final class DashUtil {
* @param trackType The type of the representation. Typically one of the {@link
* com.google.android.exoplayer2.C} {@code TRACK_TYPE_*} constants.
* @param representation The representation which initialization chunk belongs to.
* @param baseUrlIndex The index of the base URL with which to resolve the request URI.
* @return The {@link ChunkIndex} of the given representation, or null if no initialization or
* index data exists.
* @throws IOException Thrown when there is an error while loading.
*/
@Nullable
public
static
ChunkIndex
loadChunkIndex
(
DataSource
dataSource
,
int
trackType
,
Representation
representation
)
throws
IOException
{
DataSource
dataSource
,
int
trackType
,
Representation
representation
,
int
baseUrlIndex
)
throws
IOException
{
if
(
representation
.
getInitializationUri
()
==
null
)
{
return
null
;
}
ChunkExtractor
chunkExtractor
=
newChunkExtractor
(
trackType
,
representation
.
format
);
try
{
loadInitializationData
(
chunkExtractor
,
dataSource
,
representation
,
/* loadIndex= */
true
);
loadInitializationData
(
chunkExtractor
,
dataSource
,
representation
,
baseUrlIndex
,
/* loadIndex= */
true
);
}
finally
{
chunkExtractor
.
release
();
}
...
...
@@ -155,12 +199,33 @@ public final class DashUtil {
}
/**
* Loads initialization and index data for the {@code representation} and returns the {@link
* ChunkIndex}.
*
* <p>Uses the first base URL for loading the index.
*
* @param dataSource The source from which the data should be loaded.
* @param trackType The type of the representation. Typically one of the {@link
* com.google.android.exoplayer2.C} {@code TRACK_TYPE_*} constants.
* @param representation The representation which initialization chunk belongs to.
* @return The {@link ChunkIndex} of the given representation, or null if no initialization or
* index data exists.
* @throws IOException Thrown when there is an error while loading.
*/
@Nullable
public
static
ChunkIndex
loadChunkIndex
(
DataSource
dataSource
,
int
trackType
,
Representation
representation
)
throws
IOException
{
return
loadChunkIndex
(
dataSource
,
trackType
,
representation
,
/* baseUrlIndex= */
0
);
}
/**
* Loads initialization data for the {@code representation} and optionally index data then returns
* a {@link BundledChunkExtractor} which contains the output.
*
* @param chunkExtractor The {@link ChunkExtractor} to use.
* @param dataSource The source from which the data should be loaded.
* @param representation The representation which initialization chunk belongs to.
* @param baseUrlIndex The index of the base URL with which to resolve the request URI.
* @param loadIndex Whether to load index data too.
* @throws IOException Thrown when there is an error while loading.
*/
...
...
@@ -168,6 +233,7 @@ public final class DashUtil {
ChunkExtractor
chunkExtractor
,
DataSource
dataSource
,
Representation
representation
,
int
baseUrlIndex
,
boolean
loadIndex
)
throws
IOException
{
RangedUri
initializationUri
=
Assertions
.
checkNotNull
(
representation
.
getInitializationUri
());
...
...
@@ -179,24 +245,54 @@ public final class DashUtil {
}
// It's common for initialization and index data to be stored adjacently. Attempt to merge
// the two requests together to request both at once.
requestUri
=
initializationUri
.
attemptMerge
(
indexUri
,
representation
.
baseUrls
.
get
(
0
).
url
);
requestUri
=
initializationUri
.
attemptMerge
(
indexUri
,
representation
.
baseUrls
.
get
(
baseUrlIndex
).
url
);
if
(
requestUri
==
null
)
{
loadInitializationData
(
dataSource
,
representation
,
chunkExtractor
,
initializationUri
);
loadInitializationData
(
dataSource
,
representation
,
baseUrlIndex
,
chunkExtractor
,
initializationUri
);
requestUri
=
indexUri
;
}
}
else
{
requestUri
=
initializationUri
;
}
loadInitializationData
(
dataSource
,
representation
,
chunkExtractor
,
requestUri
);
loadInitializationData
(
dataSource
,
representation
,
baseUrlIndex
,
chunkExtractor
,
requestUri
);
}
/**
* Loads initialization data for the {@code representation} and optionally index data then returns
* a {@link BundledChunkExtractor} which contains the output.
*
* <p>Uses the first base URL for loading the initialization data.
*
* @param chunkExtractor The {@link ChunkExtractor} to use.
* @param dataSource The source from which the data should be loaded.
* @param representation The representation which initialization chunk belongs to.
* @param loadIndex Whether to load index data too.
* @throws IOException Thrown when there is an error while loading.
*/
public
static
void
loadInitializationData
(
ChunkExtractor
chunkExtractor
,
DataSource
dataSource
,
Representation
representation
,
boolean
loadIndex
)
throws
IOException
{
loadInitializationData
(
chunkExtractor
,
dataSource
,
representation
,
/* baseUrlIndex= */
0
,
loadIndex
);
}
private
static
void
loadInitializationData
(
DataSource
dataSource
,
Representation
representation
,
int
baseUrlIndex
,
ChunkExtractor
chunkExtractor
,
RangedUri
requestUri
)
throws
IOException
{
DataSpec
dataSpec
=
DashUtil
.
buildDataSpec
(
representation
,
requestUri
,
/* flags= */
0
);
DataSpec
dataSpec
=
DashUtil
.
buildDataSpec
(
representation
.
baseUrls
.
get
(
baseUrlIndex
).
url
,
requestUri
,
representation
.
getCacheKey
(),
/* flags= */
0
);
InitializationChunk
initializationChunk
=
new
InitializationChunk
(
dataSource
,
...
...
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java
View file @
78ecb10a
...
...
@@ -40,6 +40,7 @@ import com.google.android.exoplayer2.source.chunk.MediaChunkIterator;
import
com.google.android.exoplayer2.source.chunk.SingleSampleMediaChunk
;
import
com.google.android.exoplayer2.source.dash.PlayerEmsgHandler.PlayerTrackEmsgHandler
;
import
com.google.android.exoplayer2.source.dash.manifest.AdaptationSet
;
import
com.google.android.exoplayer2.source.dash.manifest.BaseUrl
;
import
com.google.android.exoplayer2.source.dash.manifest.DashManifest
;
import
com.google.android.exoplayer2.source.dash.manifest.RangedUri
;
import
com.google.android.exoplayer2.source.dash.manifest.Representation
;
...
...
@@ -203,6 +204,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
new
RepresentationHolder
(
periodDurationUs
,
representation
,
representation
.
baseUrls
.
get
(
0
),
BundledChunkExtractor
.
FACTORY
.
createProgressiveMediaExtractor
(
trackType
,
representation
.
format
,
...
...
@@ -562,14 +564,20 @@ public class DefaultDashChunkSource implements DashChunkSource {
if
(
initializationUri
!=
null
)
{
// It's common for initialization and index data to be stored adjacently. Attempt to merge
// the two requests together to request both at once.
requestUri
=
initializationUri
.
attemptMerge
(
indexUri
,
representation
.
baseUrls
.
get
(
0
).
url
);
requestUri
=
initializationUri
.
attemptMerge
(
indexUri
,
representationHolder
.
selectedBaseUrl
.
url
);
if
(
requestUri
==
null
)
{
requestUri
=
initializationUri
;
}
}
else
{
requestUri
=
indexUri
;
}
DataSpec
dataSpec
=
DashUtil
.
buildDataSpec
(
representation
,
requestUri
,
/* flags= */
0
);
DataSpec
dataSpec
=
DashUtil
.
buildDataSpec
(
representationHolder
.
selectedBaseUrl
.
url
,
requestUri
,
representation
.
getCacheKey
(),
/* flags= */
0
);
return
new
InitializationChunk
(
dataSource
,
dataSpec
,
...
...
@@ -593,7 +601,6 @@ public class DefaultDashChunkSource implements DashChunkSource {
Representation
representation
=
representationHolder
.
representation
;
long
startTimeUs
=
representationHolder
.
getSegmentStartTimeUs
(
firstSegmentNum
);
RangedUri
segmentUri
=
representationHolder
.
getSegmentUrl
(
firstSegmentNum
);
String
baseUrl
=
representation
.
baseUrls
.
get
(
0
).
url
;
if
(
representationHolder
.
chunkExtractor
==
null
)
{
long
endTimeUs
=
representationHolder
.
getSegmentEndTimeUs
(
firstSegmentNum
);
int
flags
=
...
...
@@ -601,7 +608,12 @@ public class DefaultDashChunkSource implements DashChunkSource {
firstSegmentNum
,
nowPeriodTimeUs
)
?
0
:
DataSpec
.
FLAG_MIGHT_NOT_USE_FULL_NETWORK_SPEED
;
DataSpec
dataSpec
=
DashUtil
.
buildDataSpec
(
representation
,
segmentUri
,
flags
);
DataSpec
dataSpec
=
DashUtil
.
buildDataSpec
(
representationHolder
.
selectedBaseUrl
.
url
,
segmentUri
,
representation
.
getCacheKey
(),
flags
);
return
new
SingleSampleMediaChunk
(
dataSource
,
dataSpec
,
...
...
@@ -617,7 +629,9 @@ public class DefaultDashChunkSource implements DashChunkSource {
int
segmentCount
=
1
;
for
(
int
i
=
1
;
i
<
maxSegmentCount
;
i
++)
{
RangedUri
nextSegmentUri
=
representationHolder
.
getSegmentUrl
(
firstSegmentNum
+
i
);
@Nullable
RangedUri
mergedSegmentUri
=
segmentUri
.
attemptMerge
(
nextSegmentUri
,
baseUrl
);
@Nullable
RangedUri
mergedSegmentUri
=
segmentUri
.
attemptMerge
(
nextSegmentUri
,
representationHolder
.
selectedBaseUrl
.
url
);
if
(
mergedSegmentUri
==
null
)
{
// Unable to merge segment fetches because the URIs do not merge.
break
;
...
...
@@ -636,7 +650,12 @@ public class DefaultDashChunkSource implements DashChunkSource {
representationHolder
.
isSegmentAvailableAtFullNetworkSpeed
(
segmentNum
,
nowPeriodTimeUs
)
?
0
:
DataSpec
.
FLAG_MIGHT_NOT_USE_FULL_NETWORK_SPEED
;
DataSpec
dataSpec
=
DashUtil
.
buildDataSpec
(
representation
,
segmentUri
,
flags
);
DataSpec
dataSpec
=
DashUtil
.
buildDataSpec
(
representationHolder
.
selectedBaseUrl
.
url
,
segmentUri
,
representation
.
getCacheKey
(),
flags
);
long
sampleOffsetUs
=
-
representation
.
presentationTimeOffsetUs
;
return
new
ContainerMediaChunk
(
dataSource
,
...
...
@@ -691,7 +710,11 @@ public class DefaultDashChunkSource implements DashChunkSource {
representationHolder
.
isSegmentAvailableAtFullNetworkSpeed
(
currentIndex
,
nowPeriodTimeUs
)
?
0
:
DataSpec
.
FLAG_MIGHT_NOT_USE_FULL_NETWORK_SPEED
;
return
DashUtil
.
buildDataSpec
(
representationHolder
.
representation
,
segmentUri
,
flags
);
return
DashUtil
.
buildDataSpec
(
representationHolder
.
selectedBaseUrl
.
url
,
segmentUri
,
representationHolder
.
representation
.
getCacheKey
(),
flags
);
}
@Override
...
...
@@ -713,6 +736,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
@Nullable
/* package */
final
ChunkExtractor
chunkExtractor
;
public
final
Representation
representation
;
public
final
BaseUrl
selectedBaseUrl
;
@Nullable
public
final
DashSegmentIndex
segmentIndex
;
private
final
long
periodDurationUs
;
...
...
@@ -721,11 +745,13 @@ public class DefaultDashChunkSource implements DashChunkSource {
/* package */
RepresentationHolder
(
long
periodDurationUs
,
Representation
representation
,
BaseUrl
selectedBaseUrl
,
@Nullable
ChunkExtractor
chunkExtractor
,
long
segmentNumShift
,
@Nullable
DashSegmentIndex
segmentIndex
)
{
this
.
periodDurationUs
=
periodDurationUs
;
this
.
representation
=
representation
;
this
.
selectedBaseUrl
=
selectedBaseUrl
;
this
.
segmentNumShift
=
segmentNumShift
;
this
.
chunkExtractor
=
chunkExtractor
;
this
.
segmentIndex
=
segmentIndex
;
...
...
@@ -735,26 +761,41 @@ public class DefaultDashChunkSource implements DashChunkSource {
/* package */
RepresentationHolder
copyWithNewRepresentation
(
long
newPeriodDurationUs
,
Representation
newRepresentation
)
throws
BehindLiveWindowException
{
DashSegmentIndex
oldIndex
=
representation
.
getIndex
();
DashSegmentIndex
newIndex
=
newRepresentation
.
getIndex
();
@Nullable
DashSegmentIndex
oldIndex
=
representation
.
getIndex
();
@Nullable
DashSegmentIndex
newIndex
=
newRepresentation
.
getIndex
();
if
(
oldIndex
==
null
)
{
// Segment numbers cannot shift if the index isn't defined by the manifest.
return
new
RepresentationHolder
(
newPeriodDurationUs
,
newRepresentation
,
chunkExtractor
,
segmentNumShift
,
oldIndex
);
newPeriodDurationUs
,
newRepresentation
,
selectedBaseUrl
,
chunkExtractor
,
segmentNumShift
,
oldIndex
);
}
if
(!
oldIndex
.
isExplicit
())
{
// Segment numbers cannot shift if the index isn't explicit.
return
new
RepresentationHolder
(
newPeriodDurationUs
,
newRepresentation
,
chunkExtractor
,
segmentNumShift
,
newIndex
);
newPeriodDurationUs
,
newRepresentation
,
selectedBaseUrl
,
chunkExtractor
,
segmentNumShift
,
newIndex
);
}
long
oldIndexSegmentCount
=
oldIndex
.
getSegmentCount
(
newPeriodDurationUs
);
if
(
oldIndexSegmentCount
==
0
)
{
// Segment numbers cannot shift if the old index was empty.
return
new
RepresentationHolder
(
newPeriodDurationUs
,
newRepresentation
,
chunkExtractor
,
segmentNumShift
,
newIndex
);
newPeriodDurationUs
,
newRepresentation
,
selectedBaseUrl
,
chunkExtractor
,
segmentNumShift
,
newIndex
);
}
long
oldIndexFirstSegmentNum
=
oldIndex
.
getFirstSegmentNum
();
...
...
@@ -786,13 +827,23 @@ public class DefaultDashChunkSource implements DashChunkSource {
-
newIndexFirstSegmentNum
;
}
return
new
RepresentationHolder
(
newPeriodDurationUs
,
newRepresentation
,
chunkExtractor
,
newSegmentNumShift
,
newIndex
);
newPeriodDurationUs
,
newRepresentation
,
selectedBaseUrl
,
chunkExtractor
,
newSegmentNumShift
,
newIndex
);
}
@CheckResult
/* package */
RepresentationHolder
copyWithNewSegmentIndex
(
DashSegmentIndex
segmentIndex
)
{
return
new
RepresentationHolder
(
periodDurationUs
,
representation
,
chunkExtractor
,
segmentNumShift
,
segmentIndex
);
periodDurationUs
,
representation
,
selectedBaseUrl
,
chunkExtractor
,
segmentNumShift
,
segmentIndex
);
}
public
long
getFirstSegmentNum
()
{
...
...
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