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
c107017a
authored
Sep 25, 2020
by
bachinger
Committed by
kim-vde
Sep 25, 2020
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Ensure implicit manifest updates arrives asap
PiperOrigin-RevId: 333714978
parent
397fe8f3
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
200 additions
and
129 deletions
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashSegmentIndex.java
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashWrappingSegmentIndex.java
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/Representation.java
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/SegmentBase.java
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/SingleSegmentIndex.java
library/dash/src/test/java/com/google/android/exoplayer2/source/dash/manifest/RepresentationTest.java → library/dash/src/test/java/com/google/android/exoplayer2/source/dash/manifest/SegmentBaseTest.java
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java
View file @
c107017a
...
...
@@ -50,6 +50,8 @@ import com.google.android.exoplayer2.source.dash.PlayerEmsgHandler.PlayerEmsgCal
import
com.google.android.exoplayer2.source.dash.manifest.AdaptationSet
;
import
com.google.android.exoplayer2.source.dash.manifest.DashManifest
;
import
com.google.android.exoplayer2.source.dash.manifest.DashManifestParser
;
import
com.google.android.exoplayer2.source.dash.manifest.Period
;
import
com.google.android.exoplayer2.source.dash.manifest.Representation
;
import
com.google.android.exoplayer2.source.dash.manifest.UtcTimingElement
;
import
com.google.android.exoplayer2.upstream.Allocator
;
import
com.google.android.exoplayer2.upstream.DataSource
;
...
...
@@ -68,10 +70,12 @@ import com.google.android.exoplayer2.util.MimeTypes;
import
com.google.android.exoplayer2.util.SntpClient
;
import
com.google.android.exoplayer2.util.Util
;
import
com.google.common.base.Charsets
;
import
com.google.common.math.LongMath
;
import
java.io.BufferedReader
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.InputStreamReader
;
import
java.math.RoundingMode
;
import
java.text.ParseException
;
import
java.text.SimpleDateFormat
;
import
java.util.Collections
;
...
...
@@ -441,7 +445,7 @@ public final class DashMediaSource extends BaseMediaSource {
* MediaSourceCaller#onSourceInfoRefreshed(MediaSource, Timeline)} when the source's {@link
* Timeline} is changing dynamically (for example, for incomplete live streams).
*/
private
static
final
int
NOTIFY_MANIFEST_INTERVAL_MS
=
5000
;
private
static
final
long
DEFAULT_
NOTIFY_MANIFEST_INTERVAL_MS
=
5000
;
/**
* The minimum default start position for live streams, relative to the start of the live window.
*/
...
...
@@ -1106,7 +1110,10 @@ public final class DashMediaSource extends BaseMediaSource {
handler
.
removeCallbacks
(
simulateManifestRefreshRunnable
);
// If the window is changing implicitly, post a simulated manifest refresh to update it.
if
(
windowChangingImplicitly
)
{
handler
.
postDelayed
(
simulateManifestRefreshRunnable
,
NOTIFY_MANIFEST_INTERVAL_MS
);
handler
.
postDelayed
(
simulateManifestRefreshRunnable
,
getIntervalUntilNextManifestRefreshMs
(
manifest
,
Util
.
getNowUnixTimeMs
(
elapsedRealtimeOffsetMs
)));
}
if
(
manifestLoadPending
)
{
startLoadingManifest
();
...
...
@@ -1165,6 +1172,38 @@ public final class DashMediaSource extends BaseMediaSource {
loadable
.
type
);
}
private
static
long
getIntervalUntilNextManifestRefreshMs
(
DashManifest
manifest
,
long
nowUnixTimeMs
)
{
int
periodIndex
=
manifest
.
getPeriodCount
()
-
1
;
Period
period
=
manifest
.
getPeriod
(
periodIndex
);
long
periodStartUs
=
C
.
msToUs
(
period
.
startMs
);
long
periodDurationUs
=
manifest
.
getPeriodDurationUs
(
periodIndex
);
long
nowUnixTimeUs
=
C
.
msToUs
(
nowUnixTimeMs
);
long
availabilityStartTimeUs
=
C
.
msToUs
(
manifest
.
availabilityStartTimeMs
);
long
intervalUs
=
C
.
msToUs
(
DEFAULT_NOTIFY_MANIFEST_INTERVAL_MS
);
for
(
int
i
=
0
;
i
<
period
.
adaptationSets
.
size
();
i
++)
{
List
<
Representation
>
representations
=
period
.
adaptationSets
.
get
(
i
).
representations
;
if
(
representations
.
isEmpty
())
{
continue
;
}
@Nullable
DashSegmentIndex
index
=
representations
.
get
(
0
).
getIndex
();
if
(
index
!=
null
)
{
long
nextSegmentShiftUnixTimeUs
=
availabilityStartTimeUs
+
periodStartUs
+
index
.
getNextSegmentAvailableTimeUs
(
periodDurationUs
,
nowUnixTimeUs
);
long
requiredIntervalUs
=
nextSegmentShiftUnixTimeUs
-
nowUnixTimeUs
;
// Avoid multiple refreshes within a very small amount of time.
if
(
requiredIntervalUs
<
intervalUs
-
100_000
||
(
requiredIntervalUs
>
intervalUs
&&
requiredIntervalUs
<
intervalUs
+
100_000
))
{
intervalUs
=
requiredIntervalUs
;
}
}
}
// Round up to compensate for a potential loss in the us to ms conversion.
return
LongMath
.
divide
(
intervalUs
,
1000
,
RoundingMode
.
CEILING
);
}
private
static
final
class
PeriodSeekInfo
{
public
static
PeriodSeekInfo
createPeriodSeekInfo
(
...
...
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashSegmentIndex.java
View file @
c107017a
...
...
@@ -102,6 +102,18 @@ public interface DashSegmentIndex {
int
getAvailableSegmentCount
(
long
periodDurationUs
,
long
nowUnixTimeUs
);
/**
* Returns the time, in microseconds, at which a new segment becomes available, or {@link
* C#TIME_UNSET} if not applicable.
*
* @param periodDurationUs The duration of the enclosing period in microseconds, or {@link
* C#TIME_UNSET} if the period's duration is not yet known.
* @param nowUnixTimeUs The current time in milliseconds since the Unix epoch.
* @return The time, in microseconds, at which a new segment becomes available, or {@link
* C#TIME_UNSET} if not applicable.
*/
long
getNextSegmentAvailableTimeUs
(
long
periodDurationUs
,
long
nowUnixTimeUs
);
/**
* Returns true if segments are defined explicitly by the index.
*
* <p>If true is returned, each segment is defined explicitly by the index data, and all of the
...
...
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashWrappingSegmentIndex.java
View file @
c107017a
...
...
@@ -15,6 +15,7 @@
*/
package
com
.
google
.
android
.
exoplayer2
.
source
.
dash
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.extractor.ChunkIndex
;
import
com.google.android.exoplayer2.source.dash.manifest.RangedUri
;
...
...
@@ -57,6 +58,11 @@ public final class DashWrappingSegmentIndex implements DashSegmentIndex {
}
@Override
public
long
getNextSegmentAvailableTimeUs
(
long
periodDurationUs
,
long
nowUnixTimeUs
)
{
return
C
.
TIME_UNSET
;
}
@Override
public
long
getTimeUs
(
long
segmentNum
)
{
return
chunkIndex
.
timesUs
[(
int
)
segmentNum
]
-
timeOffsetUs
;
}
...
...
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java
View file @
c107017a
...
...
@@ -291,9 +291,11 @@ public class DashManifestParser extends DefaultHandler
parseSegmentList
(
xpp
,
/* parent= */
null
,
periodStartUnixTimeMs
,
durationMs
,
baseUrlAvailabilityTimeOffsetUs
,
segmentBaseAvailabilityTimeOffsetUs
);
segmentBaseAvailabilityTimeOffsetUs
,
timeShiftBufferDepthMs
);
}
else
if
(
XmlPullParserUtil
.
isStartTag
(
xpp
,
"SegmentTemplate"
))
{
segmentBaseAvailabilityTimeOffsetUs
=
parseAvailabilityTimeOffsetUs
(
xpp
,
/* parentAvailabilityTimeOffsetUs= */
C
.
TIME_UNSET
);
...
...
@@ -302,9 +304,11 @@ public class DashManifestParser extends DefaultHandler
xpp
,
/* parent= */
null
,
ImmutableList
.
of
(),
periodStartUnixTimeMs
,
durationMs
,
baseUrlAvailabilityTimeOffsetUs
,
segmentBaseAvailabilityTimeOffsetUs
);
segmentBaseAvailabilityTimeOffsetUs
,
timeShiftBufferDepthMs
);
}
else
if
(
XmlPullParserUtil
.
isStartTag
(
xpp
,
"AssetIdentifier"
))
{
assetIdentifier
=
parseDescriptor
(
xpp
,
"AssetIdentifier"
);
}
else
{
...
...
@@ -407,9 +411,11 @@ public class DashManifestParser extends DefaultHandler
essentialProperties
,
supplementalProperties
,
segmentBase
,
periodStartUnixTimeMs
,
periodDurationMs
,
baseUrlAvailabilityTimeOffsetUs
,
segmentBaseAvailabilityTimeOffsetUs
);
segmentBaseAvailabilityTimeOffsetUs
,
timeShiftBufferDepthMs
);
contentType
=
checkContentTypeConsistency
(
contentType
,
MimeTypes
.
getTrackType
(
representationInfo
.
format
.
sampleMimeType
));
...
...
@@ -423,9 +429,11 @@ public class DashManifestParser extends DefaultHandler
parseSegmentList
(
xpp
,
(
SegmentList
)
segmentBase
,
periodStartUnixTimeMs
,
periodDurationMs
,
baseUrlAvailabilityTimeOffsetUs
,
segmentBaseAvailabilityTimeOffsetUs
);
segmentBaseAvailabilityTimeOffsetUs
,
timeShiftBufferDepthMs
);
}
else
if
(
XmlPullParserUtil
.
isStartTag
(
xpp
,
"SegmentTemplate"
))
{
segmentBaseAvailabilityTimeOffsetUs
=
parseAvailabilityTimeOffsetUs
(
xpp
,
segmentBaseAvailabilityTimeOffsetUs
);
...
...
@@ -434,9 +442,11 @@ public class DashManifestParser extends DefaultHandler
xpp
,
(
SegmentTemplate
)
segmentBase
,
supplementalProperties
,
periodStartUnixTimeMs
,
periodDurationMs
,
baseUrlAvailabilityTimeOffsetUs
,
segmentBaseAvailabilityTimeOffsetUs
);
segmentBaseAvailabilityTimeOffsetUs
,
timeShiftBufferDepthMs
);
}
else
if
(
XmlPullParserUtil
.
isStartTag
(
xpp
,
"InbandEventStream"
))
{
inbandEventStreams
.
add
(
parseDescriptor
(
xpp
,
"InbandEventStream"
));
}
else
if
(
XmlPullParserUtil
.
isStartTag
(
xpp
,
"Label"
))
{
...
...
@@ -455,9 +465,7 @@ public class DashManifestParser extends DefaultHandler
label
,
drmSchemeType
,
drmSchemeDatas
,
inbandEventStreams
,
periodStartUnixTimeMs
,
timeShiftBufferDepthMs
));
inbandEventStreams
));
}
return
buildAdaptationSet
(
...
...
@@ -599,9 +607,11 @@ public class DashManifestParser extends DefaultHandler
List
<
Descriptor
>
adaptationSetEssentialProperties
,
List
<
Descriptor
>
adaptationSetSupplementalProperties
,
@Nullable
SegmentBase
segmentBase
,
long
periodStartUnixTimeMs
,
long
periodDurationMs
,
long
baseUrlAvailabilityTimeOffsetUs
,
long
segmentBaseAvailabilityTimeOffsetUs
)
long
segmentBaseAvailabilityTimeOffsetUs
,
long
timeShiftBufferDepthMs
)
throws
XmlPullParserException
,
IOException
{
String
id
=
xpp
.
getAttributeValue
(
null
,
"id"
);
int
bandwidth
=
parseInt
(
xpp
,
"bandwidth"
,
Format
.
NO_VALUE
);
...
...
@@ -641,9 +651,11 @@ public class DashManifestParser extends DefaultHandler
parseSegmentList
(
xpp
,
(
SegmentList
)
segmentBase
,
periodStartUnixTimeMs
,
periodDurationMs
,
baseUrlAvailabilityTimeOffsetUs
,
segmentBaseAvailabilityTimeOffsetUs
);
segmentBaseAvailabilityTimeOffsetUs
,
timeShiftBufferDepthMs
);
}
else
if
(
XmlPullParserUtil
.
isStartTag
(
xpp
,
"SegmentTemplate"
))
{
segmentBaseAvailabilityTimeOffsetUs
=
parseAvailabilityTimeOffsetUs
(
xpp
,
segmentBaseAvailabilityTimeOffsetUs
);
...
...
@@ -652,9 +664,11 @@ public class DashManifestParser extends DefaultHandler
xpp
,
(
SegmentTemplate
)
segmentBase
,
adaptationSetSupplementalProperties
,
periodStartUnixTimeMs
,
periodDurationMs
,
baseUrlAvailabilityTimeOffsetUs
,
segmentBaseAvailabilityTimeOffsetUs
);
segmentBaseAvailabilityTimeOffsetUs
,
timeShiftBufferDepthMs
);
}
else
if
(
XmlPullParserUtil
.
isStartTag
(
xpp
,
"ContentProtection"
))
{
Pair
<
String
,
SchemeData
>
contentProtection
=
parseContentProtection
(
xpp
);
if
(
contentProtection
.
first
!=
null
)
{
...
...
@@ -754,9 +768,7 @@ public class DashManifestParser extends DefaultHandler
@Nullable
String
label
,
@Nullable
String
extraDrmSchemeType
,
ArrayList
<
SchemeData
>
extraDrmSchemeDatas
,
ArrayList
<
Descriptor
>
extraInbandEventStreams
,
long
periodStartUnixTimeMs
,
long
timeShiftBufferDepthMs
)
{
ArrayList
<
Descriptor
>
extraInbandEventStreams
)
{
Format
.
Builder
formatBuilder
=
representationInfo
.
format
.
buildUpon
();
if
(
label
!=
null
)
{
formatBuilder
.
setLabel
(
label
);
...
...
@@ -778,9 +790,7 @@ public class DashManifestParser extends DefaultHandler
formatBuilder
.
build
(),
representationInfo
.
baseUrl
,
representationInfo
.
segmentBase
,
inbandEventStreams
,
periodStartUnixTimeMs
,
timeShiftBufferDepthMs
);
inbandEventStreams
);
}
// SegmentBase, SegmentList and SegmentTemplate parsing.
...
...
@@ -825,9 +835,11 @@ public class DashManifestParser extends DefaultHandler
protected
SegmentList
parseSegmentList
(
XmlPullParser
xpp
,
@Nullable
SegmentList
parent
,
long
periodStartUnixTimeMs
,
long
periodDurationMs
,
long
baseUrlAvailabilityTimeOffsetUs
,
long
segmentBaseAvailabilityTimeOffsetUs
)
long
segmentBaseAvailabilityTimeOffsetUs
,
long
timeShiftBufferDepthMs
)
throws
XmlPullParserException
,
IOException
{
long
timescale
=
parseLong
(
xpp
,
"timescale"
,
parent
!=
null
?
parent
.
timescale
:
1
);
...
...
@@ -873,7 +885,9 @@ public class DashManifestParser extends DefaultHandler
duration
,
timeline
,
availabilityTimeOffsetUs
,
segments
);
segments
,
timeShiftBufferDepthMs
,
periodStartUnixTimeMs
);
}
protected
SegmentList
buildSegmentList
(
...
...
@@ -884,7 +898,9 @@ public class DashManifestParser extends DefaultHandler
long
duration
,
@Nullable
List
<
SegmentTimelineElement
>
timeline
,
long
availabilityTimeOffsetUs
,
@Nullable
List
<
RangedUri
>
segments
)
{
@Nullable
List
<
RangedUri
>
segments
,
long
timeShiftBufferDepthMs
,
long
periodStartUnixTimeMs
)
{
return
new
SegmentList
(
initialization
,
timescale
,
...
...
@@ -893,16 +909,20 @@ public class DashManifestParser extends DefaultHandler
duration
,
timeline
,
availabilityTimeOffsetUs
,
segments
);
segments
,
C
.
msToUs
(
timeShiftBufferDepthMs
),
C
.
msToUs
(
periodStartUnixTimeMs
));
}
protected
SegmentTemplate
parseSegmentTemplate
(
XmlPullParser
xpp
,
@Nullable
SegmentTemplate
parent
,
List
<
Descriptor
>
adaptationSetSupplementalProperties
,
long
periodStartUnixTimeMs
,
long
periodDurationMs
,
long
baseUrlAvailabilityTimeOffsetUs
,
long
segmentBaseAvailabilityTimeOffsetUs
)
long
segmentBaseAvailabilityTimeOffsetUs
,
long
timeShiftBufferDepthMs
)
throws
XmlPullParserException
,
IOException
{
long
timescale
=
parseLong
(
xpp
,
"timescale"
,
parent
!=
null
?
parent
.
timescale
:
1
);
long
presentationTimeOffset
=
parseLong
(
xpp
,
"presentationTimeOffset"
,
...
...
@@ -949,7 +969,9 @@ public class DashManifestParser extends DefaultHandler
timeline
,
availabilityTimeOffsetUs
,
initializationTemplate
,
mediaTemplate
);
mediaTemplate
,
timeShiftBufferDepthMs
,
periodStartUnixTimeMs
);
}
protected
SegmentTemplate
buildSegmentTemplate
(
...
...
@@ -962,7 +984,9 @@ public class DashManifestParser extends DefaultHandler
List
<
SegmentTimelineElement
>
timeline
,
long
availabilityTimeOffsetUs
,
@Nullable
UrlTemplate
initializationTemplate
,
@Nullable
UrlTemplate
mediaTemplate
)
{
@Nullable
UrlTemplate
mediaTemplate
,
long
timeShiftBufferDepthMs
,
long
periodStartUnixTimeMs
)
{
return
new
SegmentTemplate
(
initialization
,
timescale
,
...
...
@@ -973,7 +997,9 @@ public class DashManifestParser extends DefaultHandler
timeline
,
availabilityTimeOffsetUs
,
initializationTemplate
,
mediaTemplate
);
mediaTemplate
,
C
.
msToUs
(
timeShiftBufferDepthMs
),
C
.
msToUs
(
periodStartUnixTimeMs
));
}
/**
...
...
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/Representation.java
View file @
c107017a
...
...
@@ -15,8 +15,6 @@
*/
package
com
.
google
.
android
.
exoplayer2
.
source
.
dash
.
manifest
;
import
static
java
.
lang
.
Math
.
max
;
import
android.net.Uri
;
import
androidx.annotation.Nullable
;
import
androidx.annotation.VisibleForTesting
;
...
...
@@ -73,14 +71,7 @@ public abstract class Representation {
*/
public
static
Representation
newInstance
(
long
revisionId
,
Format
format
,
String
baseUrl
,
SegmentBase
segmentBase
)
{
return
newInstance
(
revisionId
,
format
,
baseUrl
,
segmentBase
,
/* inbandEventStreams= */
null
,
/* periodStartUnixTimeMs= */
C
.
TIME_UNSET
,
/* timeShiftBufferDepthMs= */
C
.
TIME_UNSET
);
return
newInstance
(
revisionId
,
format
,
baseUrl
,
segmentBase
,
/* inbandEventStreams= */
null
);
}
/**
...
...
@@ -91,9 +82,6 @@ public abstract class Representation {
* @param baseUrl The base URL.
* @param segmentBase A segment base element for the representation.
* @param inbandEventStreams The in-band event streams in the representation. May be null.
* @param periodStartUnixTimeMs The start time of the enclosing {@link Period} in milliseconds
* since the Unix epoch, or {@link C#TIME_UNSET} is not applicable.
* @param timeShiftBufferDepthMs The {@link DashManifest#timeShiftBufferDepthMs}.
* @return The constructed instance.
*/
public
static
Representation
newInstance
(
...
...
@@ -101,17 +89,13 @@ public abstract class Representation {
Format
format
,
String
baseUrl
,
SegmentBase
segmentBase
,
@Nullable
List
<
Descriptor
>
inbandEventStreams
,
long
periodStartUnixTimeMs
,
long
timeShiftBufferDepthMs
)
{
@Nullable
List
<
Descriptor
>
inbandEventStreams
)
{
return
newInstance
(
revisionId
,
format
,
baseUrl
,
segmentBase
,
inbandEventStreams
,
periodStartUnixTimeMs
,
timeShiftBufferDepthMs
,
/* cacheKey= */
null
);
}
...
...
@@ -123,9 +107,6 @@ public abstract class Representation {
* @param baseUrl The base URL of the representation.
* @param segmentBase A segment base element for the representation.
* @param inbandEventStreams The in-band event streams in the representation. May be null.
* @param periodStartUnixTimeMs The start time of the enclosing {@link Period} in milliseconds
* since the Unix epoch, or {@link C#TIME_UNSET} is not applicable.
* @param timeShiftBufferDepthMs The {@link DashManifest#timeShiftBufferDepthMs}.
* @param cacheKey An optional key to be returned from {@link #getCacheKey()}, or null. This
* parameter is ignored if {@code segmentBase} consists of multiple segments.
* @return The constructed instance.
...
...
@@ -136,8 +117,6 @@ public abstract class Representation {
String
baseUrl
,
SegmentBase
segmentBase
,
@Nullable
List
<
Descriptor
>
inbandEventStreams
,
long
periodStartUnixTimeMs
,
long
timeShiftBufferDepthMs
,
@Nullable
String
cacheKey
)
{
if
(
segmentBase
instanceof
SingleSegmentBase
)
{
return
new
SingleSegmentRepresentation
(
...
...
@@ -150,13 +129,7 @@ public abstract class Representation {
C
.
LENGTH_UNSET
);
}
else
if
(
segmentBase
instanceof
MultiSegmentBase
)
{
return
new
MultiSegmentRepresentation
(
revisionId
,
format
,
baseUrl
,
(
MultiSegmentBase
)
segmentBase
,
inbandEventStreams
,
periodStartUnixTimeMs
,
timeShiftBufferDepthMs
);
revisionId
,
format
,
baseUrl
,
(
MultiSegmentBase
)
segmentBase
,
inbandEventStreams
);
}
else
{
throw
new
IllegalArgumentException
(
"segmentBase must be of type SingleSegmentBase or "
+
"MultiSegmentBase"
);
...
...
@@ -309,8 +282,6 @@ public abstract class Representation {
implements
DashSegmentIndex
{
@VisibleForTesting
/* package */
final
MultiSegmentBase
segmentBase
;
private
final
long
periodStartUnixTimeUs
;
private
final
long
timeShiftBufferDepthUs
;
/**
* Creates the multi-segment Representation.
...
...
@@ -320,22 +291,15 @@ public abstract class Representation {
* @param baseUrl The base URL of the representation.
* @param segmentBase The segment base underlying the representation.
* @param inbandEventStreams The in-band event streams in the representation. May be null.
* @param periodStartUnixTimeMs The start time of the enclosing {@link Period} in milliseconds
* since the Unix epoch, or {@link C#TIME_UNSET} is not applicable.
* @param timeShiftBufferDepthMs The {@link DashManifest#timeShiftBufferDepthMs}.
*/
public
MultiSegmentRepresentation
(
long
revisionId
,
Format
format
,
String
baseUrl
,
MultiSegmentBase
segmentBase
,
@Nullable
List
<
Descriptor
>
inbandEventStreams
,
long
periodStartUnixTimeMs
,
long
timeShiftBufferDepthMs
)
{
@Nullable
List
<
Descriptor
>
inbandEventStreams
)
{
super
(
revisionId
,
format
,
baseUrl
,
segmentBase
,
inbandEventStreams
);
this
.
segmentBase
=
segmentBase
;
this
.
periodStartUnixTimeUs
=
C
.
msToUs
(
periodStartUnixTimeMs
);
this
.
timeShiftBufferDepthUs
=
C
.
msToUs
(
timeShiftBufferDepthMs
);
}
@Override
...
...
@@ -384,17 +348,7 @@ public abstract class Representation {
@Override
public
long
getFirstAvailableSegmentNum
(
long
periodDurationUs
,
long
nowUnixTimeUs
)
{
long
segmentCount
=
segmentBase
.
getSegmentCount
(
periodDurationUs
);
if
(
segmentCount
!=
INDEX_UNBOUNDED
||
timeShiftBufferDepthUs
==
C
.
TIME_UNSET
)
{
return
segmentBase
.
getFirstSegmentNum
();
}
// The index is itself unbounded. We need to use the current time to calculate the range of
// available segments.
long
liveEdgeTimeInPeriodUs
=
nowUnixTimeUs
-
periodStartUnixTimeUs
;
long
timeShiftBufferStartInPeriodUs
=
liveEdgeTimeInPeriodUs
-
timeShiftBufferDepthUs
;
long
timeShiftBufferStartSegmentNum
=
getSegmentNum
(
timeShiftBufferStartInPeriodUs
,
periodDurationUs
);
return
max
(
getFirstSegmentNum
(),
timeShiftBufferStartSegmentNum
);
return
segmentBase
.
getFirstAvailableSegmentNum
(
periodDurationUs
,
nowUnixTimeUs
);
}
@Override
...
...
@@ -404,18 +358,12 @@ public abstract class Representation {
@Override
public
int
getAvailableSegmentCount
(
long
periodDurationUs
,
long
nowUnixTimeUs
)
{
int
segmentCount
=
segmentBase
.
getSegmentCount
(
periodDurationUs
);
if
(
segmentCount
!=
INDEX_UNBOUNDED
)
{
return
segmentCount
;
}
// The index is itself unbounded. We need to use the current time to calculate the range of
// available segments.
long
liveEdgeTimeInPeriodUs
=
nowUnixTimeUs
-
periodStartUnixTimeUs
;
long
availabilityEndTimeUs
=
liveEdgeTimeInPeriodUs
+
segmentBase
.
availabilityTimeOffsetUs
;
// getSegmentNum(availabilityEndTimeUs) will not be completed yet.
long
firstIncompleteSegmentNum
=
getSegmentNum
(
availabilityEndTimeUs
,
periodDurationUs
);
long
firstAvailableSegmentNum
=
getFirstAvailableSegmentNum
(
periodDurationUs
,
nowUnixTimeUs
);
return
(
int
)
(
firstIncompleteSegmentNum
-
firstAvailableSegmentNum
);
return
segmentBase
.
getAvailableSegmentCount
(
periodDurationUs
,
nowUnixTimeUs
);
}
@Override
public
long
getNextSegmentAvailableTimeUs
(
long
periodDurationUs
,
long
nowUnixTimeUs
)
{
return
segmentBase
.
getNextSegmentAvailableTimeUs
(
periodDurationUs
,
nowUnixTimeUs
);
}
@Override
...
...
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/SegmentBase.java
View file @
c107017a
This diff is collapsed.
Click to expand it.
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/SingleSegmentIndex.java
View file @
c107017a
...
...
@@ -15,6 +15,7 @@
*/
package
com
.
google
.
android
.
exoplayer2
.
source
.
dash
.
manifest
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.source.dash.DashSegmentIndex
;
/**
...
...
@@ -72,6 +73,11 @@ import com.google.android.exoplayer2.source.dash.DashSegmentIndex;
}
@Override
public
long
getNextSegmentAvailableTimeUs
(
long
periodDurationUs
,
long
nowUnixTimeUs
)
{
return
C
.
TIME_UNSET
;
}
@Override
public
boolean
isExplicit
()
{
return
true
;
}
...
...
library/dash/src/test/java/com/google/android/exoplayer2/source/dash/manifest/
Representation
Test.java
→
library/dash/src/test/java/com/google/android/exoplayer2/source/dash/manifest/
SegmentBase
Test.java
View file @
c107017a
...
...
@@ -19,16 +19,15 @@ import static com.google.common.truth.Truth.assertThat;
import
androidx.test.ext.junit.runners.AndroidJUnit4
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.Format
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
/** Unit test for {@link
Representation
}. */
/** Unit test for {@link
SegmentBase
}. */
@RunWith
(
AndroidJUnit4
.
class
)
public
final
class
Representation
Test
{
public
final
class
SegmentBase
Test
{
@Test
public
void
getFirstAvailableSegmentNum_
multiSegmentRepresentationWithUnbounded
Template
()
{
public
void
getFirstAvailableSegmentNum_
unboundedSegment
Template
()
{
long
periodStartUnixTimeUs
=
123_000_000_000_000L
;
SegmentBase
.
SegmentTemplate
segmentTemplate
=
new
SegmentBase
.
SegmentTemplate
(
...
...
@@ -41,50 +40,43 @@ public final class RepresentationTest {
/* segmentTimeline= */
null
,
/* availabilityTimeOffsetUs= */
500_000
,
/* initializationTemplate= */
null
,
/* mediaTemplate= */
null
);
Representation
.
MultiSegmentRepresentation
representation
=
new
Representation
.
MultiSegmentRepresentation
(
/* revisionId= */
0
,
new
Format
.
Builder
().
build
(),
/* baseUrl= */
"https://baseUrl/"
,
segmentTemplate
,
/* inbandEventStreams= */
null
,
/* periodStartUnixTimeMs= */
C
.
usToMs
(
periodStartUnixTimeUs
),
/* timeShiftBufferDepthMs= */
6_000
);
/* mediaTemplate= */
null
,
/* timeShiftBufferDepthUs= */
6_000_000
,
/* periodStartUnixTimeUs= */
periodStartUnixTimeUs
);
assertThat
(
representation
.
getFirstAvailableSegmentNum
(
segmentTemplate
.
getFirstAvailableSegmentNum
(
/* periodDurationUs= */
C
.
TIME_UNSET
,
/* nowUnixTimeUs= */
periodStartUnixTimeUs
-
10_000_000
))
.
isEqualTo
(
42
);
assertThat
(
representation
.
getFirstAvailableSegmentNum
(
segmentTemplate
.
getFirstAvailableSegmentNum
(
/* periodDurationUs= */
C
.
TIME_UNSET
,
/* nowUnixTimeUs= */
periodStartUnixTimeUs
))
.
isEqualTo
(
42
);
assertThat
(
representation
.
getFirstAvailableSegmentNum
(
segmentTemplate
.
getFirstAvailableSegmentNum
(
/* periodDurationUs= */
C
.
TIME_UNSET
,
/* nowUnixTimeUs= */
periodStartUnixTimeUs
+
7_999_999
))
.
isEqualTo
(
42
);
assertThat
(
representation
.
getFirstAvailableSegmentNum
(
segmentTemplate
.
getFirstAvailableSegmentNum
(
/* periodDurationUs= */
C
.
TIME_UNSET
,
/* nowUnixTimeUs= */
periodStartUnixTimeUs
+
8_000_000
))
.
isEqualTo
(
43
);
assertThat
(
representation
.
getFirstAvailableSegmentNum
(
segmentTemplate
.
getFirstAvailableSegmentNum
(
/* periodDurationUs= */
C
.
TIME_UNSET
,
/* nowUnixTimeUs= */
periodStartUnixTimeUs
+
9_999_999
))
.
isEqualTo
(
43
);
assertThat
(
representation
.
getFirstAvailableSegmentNum
(
segmentTemplate
.
getFirstAvailableSegmentNum
(
/* periodDurationUs= */
C
.
TIME_UNSET
,
/* nowUnixTimeUs= */
periodStartUnixTimeUs
+
10_000_000
))
.
isEqualTo
(
44
);
}
@Test
public
void
getAvailableSegmentCount_
multiSegmentRepresentationWithUnbounded
Template
()
{
public
void
getAvailableSegmentCount_
unboundedSegment
Template
()
{
long
periodStartUnixTimeUs
=
123_000_000_000_000L
;
SegmentBase
.
SegmentTemplate
segmentTemplate
=
new
SegmentBase
.
SegmentTemplate
(
...
...
@@ -97,55 +89,97 @@ public final class RepresentationTest {
/* segmentTimeline= */
null
,
/* availabilityTimeOffsetUs= */
500_000
,
/* initializationTemplate= */
null
,
/* mediaTemplate= */
null
);
Representation
.
MultiSegmentRepresentation
representation
=
new
Representation
.
MultiSegmentRepresentation
(
/* revisionId= */
0
,
new
Format
.
Builder
().
build
(),
/* baseUrl= */
"https://baseUrl/"
,
segmentTemplate
,
/* inbandEventStreams= */
null
,
/* periodStartUnixTimeMs= */
C
.
usToMs
(
periodStartUnixTimeUs
),
/* timeShiftBufferDepthMs= */
6_000
);
/* mediaTemplate= */
null
,
/* timeShiftBufferDepthUs= */
6_000_000
,
/* periodStartUnixTimeUs= */
periodStartUnixTimeUs
);
assertThat
(
representation
.
getAvailableSegmentCount
(
segmentTemplate
.
getAvailableSegmentCount
(
/* periodDurationUs= */
C
.
TIME_UNSET
,
/* nowUnixTimeUs= */
periodStartUnixTimeUs
-
10_000_000
))
.
isEqualTo
(
0
);
assertThat
(
representation
.
getAvailableSegmentCount
(
segmentTemplate
.
getAvailableSegmentCount
(
/* periodDurationUs= */
C
.
TIME_UNSET
,
/* nowUnixTimeUs= */
periodStartUnixTimeUs
))
.
isEqualTo
(
0
);
assertThat
(
representation
.
getAvailableSegmentCount
(
segmentTemplate
.
getAvailableSegmentCount
(
/* periodDurationUs= */
C
.
TIME_UNSET
,
/* nowUnixTimeUs= */
periodStartUnixTimeUs
+
1_499_999
))
.
isEqualTo
(
0
);
assertThat
(
representation
.
getAvailableSegmentCount
(
segmentTemplate
.
getAvailableSegmentCount
(
/* periodDurationUs= */
C
.
TIME_UNSET
,
/* nowUnixTimeUs= */
periodStartUnixTimeUs
+
1_500_000
))
.
isEqualTo
(
1
);
assertThat
(
representation
.
getAvailableSegmentCount
(
segmentTemplate
.
getAvailableSegmentCount
(
/* periodDurationUs= */
C
.
TIME_UNSET
,
/* nowUnixTimeUs= */
periodStartUnixTimeUs
+
7_499_999
))
.
isEqualTo
(
3
);
assertThat
(
representation
.
getAvailableSegmentCount
(
segmentTemplate
.
getAvailableSegmentCount
(
/* periodDurationUs= */
C
.
TIME_UNSET
,
/* nowUnixTimeUs= */
periodStartUnixTimeUs
+
7_500_000
))
.
isEqualTo
(
4
);
assertThat
(
representation
.
getAvailableSegmentCount
(
segmentTemplate
.
getAvailableSegmentCount
(
/* periodDurationUs= */
C
.
TIME_UNSET
,
/* nowUnixTimeUs= */
periodStartUnixTimeUs
+
7_999_999
))
.
isEqualTo
(
4
);
assertThat
(
representation
.
getAvailableSegmentCount
(
segmentTemplate
.
getAvailableSegmentCount
(
/* periodDurationUs= */
C
.
TIME_UNSET
,
/* nowUnixTimeUs= */
periodStartUnixTimeUs
+
8_000_000
))
.
isEqualTo
(
3
);
}
@Test
public
void
getNextSegmentShiftTimeUse_unboundedSegmentTemplate
()
{
long
periodStartUnixTimeUs
=
123_000_000_000_000L
;
SegmentBase
.
SegmentTemplate
segmentTemplate
=
new
SegmentBase
.
SegmentTemplate
(
/* initialization= */
null
,
/* timescale= */
1000
,
/* presentationTimeOffset= */
0
,
/* startNumber= */
42
,
/* endNumber= */
C
.
INDEX_UNSET
,
/* duration= */
2000
,
/* segmentTimeline= */
null
,
/* availabilityTimeOffsetUs= */
500_000
,
/* initializationTemplate= */
null
,
/* mediaTemplate= */
null
,
/* timeShiftBufferDepthUs= */
6_000_000
,
/* periodStartUnixTimeUs= */
periodStartUnixTimeUs
);
assertThat
(
segmentTemplate
.
getNextSegmentAvailableTimeUs
(
/* periodDurationUs= */
C
.
TIME_UNSET
,
/* nowUnixTimeUs= */
periodStartUnixTimeUs
-
10_000_000
))
.
isEqualTo
(
1_500_000
);
assertThat
(
segmentTemplate
.
getNextSegmentAvailableTimeUs
(
/* periodDurationUs= */
C
.
TIME_UNSET
,
/* nowUnixTimeUs= */
periodStartUnixTimeUs
))
.
isEqualTo
(
1_500_000
);
assertThat
(
segmentTemplate
.
getNextSegmentAvailableTimeUs
(
/* periodDurationUs= */
C
.
TIME_UNSET
,
/* nowUnixTimeUs= */
periodStartUnixTimeUs
+
1_499_999
))
.
isEqualTo
(
1_500_000
);
assertThat
(
segmentTemplate
.
getNextSegmentAvailableTimeUs
(
/* periodDurationUs= */
C
.
TIME_UNSET
,
/* nowUnixTimeUs= */
periodStartUnixTimeUs
+
1_500_000
))
.
isEqualTo
(
3_500_000
);
assertThat
(
segmentTemplate
.
getNextSegmentAvailableTimeUs
(
/* periodDurationUs= */
C
.
TIME_UNSET
,
/* nowUnixTimeUs= */
periodStartUnixTimeUs
+
17_499_999
))
.
isEqualTo
(
17_500_000
);
assertThat
(
segmentTemplate
.
getNextSegmentAvailableTimeUs
(
/* periodDurationUs= */
C
.
TIME_UNSET
,
/* nowUnixTimeUs= */
periodStartUnixTimeUs
+
17_500_000
))
.
isEqualTo
(
19_500_000
);
}
}
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