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
a60ed20f
authored
Mar 09, 2021
by
gyumin
Committed by
Ian Baker
Mar 12, 2021
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Implement Bundleable for Timeline.Window
PiperOrigin-RevId: 361741354
parent
ae7c1091
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
229 additions
and
49 deletions
library/common/src/main/java/com/google/android/exoplayer2/MediaItem.java
library/common/src/main/java/com/google/android/exoplayer2/Timeline.java
library/common/src/test/java/com/google/android/exoplayer2/TimelineTest.java
library/common/src/main/java/com/google/android/exoplayer2/MediaItem.java
View file @
a60ed20f
...
@@ -1272,6 +1272,12 @@ public final class MediaItem implements Bundleable {
...
@@ -1272,6 +1272,12 @@ public final class MediaItem implements Bundleable {
private
static
final
int
FIELD_MEDIA_METADATA
=
2
;
private
static
final
int
FIELD_MEDIA_METADATA
=
2
;
private
static
final
int
FIELD_CLIPPING_PROPERTIES
=
3
;
private
static
final
int
FIELD_CLIPPING_PROPERTIES
=
3
;
/**
* {@inheritDoc}
*
* <p>It omits the {@link #playbackProperties} field. The {@link #playbackProperties} of an
* instance restored by {@link #CREATOR} will always be {@code null}.
*/
@Override
@Override
public
Bundle
toBundle
()
{
public
Bundle
toBundle
()
{
Bundle
bundle
=
new
Bundle
();
Bundle
bundle
=
new
Bundle
();
...
@@ -1282,46 +1288,51 @@ public final class MediaItem implements Bundleable {
...
@@ -1282,46 +1288,51 @@ public final class MediaItem implements Bundleable {
return
bundle
;
return
bundle
;
}
}
/** Object that can restore {@link MediaItem} from a {@link Bundle}. */
/**
public
static
final
Creator
<
MediaItem
>
CREATOR
=
* Object that can restore {@link MediaItem} from a {@link Bundle}.
bundle
->
{
*
String
mediaId
=
checkNotNull
(
bundle
.
getString
(
keyForField
(
FIELD_MEDIA_ID
)));
* <p>The {@link #playbackProperties} of a restored instance will always be {@code null}.
@Nullable
*/
Bundle
liveConfigurationBundle
=
bundle
.
getBundle
(
keyForField
(
FIELD_LIVE_CONFIGURATION
));
public
static
final
Creator
<
MediaItem
>
CREATOR
=
MediaItem:
:
fromBundle
;
LiveConfiguration
liveConfiguration
;
if
(
liveConfigurationBundle
==
null
)
{
private
static
MediaItem
fromBundle
(
Bundle
bundle
)
{
liveConfiguration
=
LiveConfiguration
.
UNSET
;
String
mediaId
=
checkNotNull
(
bundle
.
getString
(
keyForField
(
FIELD_MEDIA_ID
)));
}
else
{
@Nullable
liveConfiguration
=
LiveConfiguration
.
CREATOR
.
fromBundle
(
liveConfigurationBundle
);
Bundle
liveConfigurationBundle
=
bundle
.
getBundle
(
keyForField
(
FIELD_LIVE_CONFIGURATION
));
}
LiveConfiguration
liveConfiguration
;
@Nullable
Bundle
mediaMetadataBundle
=
bundle
.
getBundle
(
keyForField
(
FIELD_MEDIA_METADATA
));
if
(
liveConfigurationBundle
==
null
)
{
MediaMetadata
mediaMetadata
;
liveConfiguration
=
LiveConfiguration
.
UNSET
;
if
(
mediaMetadataBundle
==
null
)
{
}
else
{
mediaMetadata
=
new
MediaMetadata
.
Builder
().
build
();
liveConfiguration
=
LiveConfiguration
.
CREATOR
.
fromBundle
(
liveConfigurationBundle
);
}
else
{
}
mediaMetadata
=
MediaMetadata
.
CREATOR
.
fromBundle
(
mediaMetadataBundle
);
@Nullable
Bundle
mediaMetadataBundle
=
bundle
.
getBundle
(
keyForField
(
FIELD_MEDIA_METADATA
));
}
MediaMetadata
mediaMetadata
;
@Nullable
if
(
mediaMetadataBundle
==
null
)
{
Bundle
clippingPropertiesBundle
=
bundle
.
getBundle
(
keyForField
(
FIELD_CLIPPING_PROPERTIES
));
mediaMetadata
=
new
MediaMetadata
.
Builder
().
build
();
ClippingProperties
clippingProperties
;
}
else
{
if
(
clippingPropertiesBundle
==
null
)
{
mediaMetadata
=
MediaMetadata
.
CREATOR
.
fromBundle
(
mediaMetadataBundle
);
clippingProperties
=
}
new
ClippingProperties
(
@Nullable
/* startPositionMs= */
0
,
Bundle
clippingPropertiesBundle
=
bundle
.
getBundle
(
keyForField
(
FIELD_CLIPPING_PROPERTIES
));
/* endPositionMs= */
C
.
TIME_END_OF_SOURCE
,
ClippingProperties
clippingProperties
;
/* relativeToLiveWindow= */
false
,
if
(
clippingPropertiesBundle
==
null
)
{
/* relativeToDefaultPosition= */
false
,
clippingProperties
=
/* startsAtKeyFrame= */
false
);
new
ClippingProperties
(
}
else
{
/* startPositionMs= */
0
,
clippingProperties
=
ClippingProperties
.
CREATOR
.
fromBundle
(
clippingPropertiesBundle
);
/* endPositionMs= */
C
.
TIME_END_OF_SOURCE
,
}
/* relativeToLiveWindow= */
false
,
return
new
MediaItem
(
/* relativeToDefaultPosition= */
false
,
mediaId
,
/* startsAtKeyFrame= */
false
);
clippingProperties
,
}
else
{
/* playbackProperties= */
null
,
clippingProperties
=
ClippingProperties
.
CREATOR
.
fromBundle
(
clippingPropertiesBundle
);
liveConfiguration
,
}
mediaMetadata
);
return
new
MediaItem
(
};
mediaId
,
clippingProperties
,
/* playbackProperties= */
null
,
liveConfiguration
,
mediaMetadata
);
}
private
static
String
keyForField
(
@FieldNumber
int
field
)
{
private
static
String
keyForField
(
@FieldNumber
int
field
)
{
return
Integer
.
toString
(
field
,
Character
.
MAX_RADIX
);
return
Integer
.
toString
(
field
,
Character
.
MAX_RADIX
);
...
...
library/common/src/main/java/com/google/android/exoplayer2/Timeline.java
View file @
a60ed20f
...
@@ -136,13 +136,15 @@ public abstract class Timeline {
...
@@ -136,13 +136,15 @@ public abstract class Timeline {
* <p style="align:center"><img src="doc-files/timeline-window.svg" alt="Information defined by a
* <p style="align:center"><img src="doc-files/timeline-window.svg" alt="Information defined by a
* timeline window">
* timeline window">
*/
*/
public
static
final
class
Window
{
public
static
final
class
Window
implements
Bundleable
{
/**
/**
* A {@link #uid} for a window that must be used for single-window {@link Timeline Timelines}.
* A {@link #uid} for a window that must be used for single-window {@link Timeline Timelines}.
*/
*/
public
static
final
Object
SINGLE_WINDOW_UID
=
new
Object
();
public
static
final
Object
SINGLE_WINDOW_UID
=
new
Object
();
private
static
final
Object
FAKE_WINDOW_UID
=
new
Object
();
private
static
final
MediaItem
EMPTY_MEDIA_ITEM
=
private
static
final
MediaItem
EMPTY_MEDIA_ITEM
=
new
MediaItem
.
Builder
()
new
MediaItem
.
Builder
()
.
setMediaId
(
"com.google.android.exoplayer2.Timeline"
)
.
setMediaId
(
"com.google.android.exoplayer2.Timeline"
)
...
@@ -213,14 +215,6 @@ public abstract class Timeline {
...
@@ -213,14 +215,6 @@ public abstract class Timeline {
*/
*/
public
boolean
isPlaceholder
;
public
boolean
isPlaceholder
;
/** The index of the first period that belongs to this window. */
public
int
firstPeriodIndex
;
/**
* The index of the last period that belongs to this window.
*/
public
int
lastPeriodIndex
;
/**
/**
* The default position relative to the start of the window at which to begin playback, in
* The default position relative to the start of the window at which to begin playback, in
* microseconds. May be {@link C#TIME_UNSET} if and only if the window was populated with a
* microseconds. May be {@link C#TIME_UNSET} if and only if the window was populated with a
...
@@ -234,6 +228,12 @@ public abstract class Timeline {
...
@@ -234,6 +228,12 @@ public abstract class Timeline {
*/
*/
public
long
durationUs
;
public
long
durationUs
;
/** The index of the first period that belongs to this window. */
public
int
firstPeriodIndex
;
/** The index of the last period that belongs to this window. */
public
int
lastPeriodIndex
;
/**
/**
* The position of the start of this window relative to the start of the first period belonging
* The position of the start of this window relative to the start of the first period belonging
* to it, in microseconds.
* to it, in microseconds.
...
@@ -404,6 +404,142 @@ public abstract class Timeline {
...
@@ -404,6 +404,142 @@ public abstract class Timeline {
result
=
31
*
result
+
(
int
)
(
positionInFirstPeriodUs
^
(
positionInFirstPeriodUs
>>>
32
));
result
=
31
*
result
+
(
int
)
(
positionInFirstPeriodUs
^
(
positionInFirstPeriodUs
>>>
32
));
return
result
;
return
result
;
}
}
// Bundleable implementation.
@Documented
@Retention
(
RetentionPolicy
.
SOURCE
)
@IntDef
({
FIELD_MEDIA_ITEM
,
FIELD_PRESENTATION_START_TIME_MS
,
FIELD_WINDOW_START_TIME_MS
,
FIELD_ELAPSED_REALTIME_EPOCH_OFFSET_MS
,
FIELD_IS_SEEKABLE
,
FIELD_IS_DYNAMIC
,
FIELD_LIVE_CONFIGURATION
,
FIELD_IS_PLACEHOLDER
,
FIELD_DEFAULT_POSITION_US
,
FIELD_DURATION_US
,
FIELD_FIRST_PERIOD_INDEX
,
FIELD_LAST_PERIOD_INDEX
,
FIELD_POSITION_IN_FIRST_PERIOD_US
,
})
private
@interface
FieldNumber
{}
private
static
final
int
FIELD_MEDIA_ITEM
=
1
;
private
static
final
int
FIELD_PRESENTATION_START_TIME_MS
=
2
;
private
static
final
int
FIELD_WINDOW_START_TIME_MS
=
3
;
private
static
final
int
FIELD_ELAPSED_REALTIME_EPOCH_OFFSET_MS
=
4
;
private
static
final
int
FIELD_IS_SEEKABLE
=
5
;
private
static
final
int
FIELD_IS_DYNAMIC
=
6
;
private
static
final
int
FIELD_LIVE_CONFIGURATION
=
7
;
private
static
final
int
FIELD_IS_PLACEHOLDER
=
8
;
private
static
final
int
FIELD_DEFAULT_POSITION_US
=
9
;
private
static
final
int
FIELD_DURATION_US
=
10
;
private
static
final
int
FIELD_FIRST_PERIOD_INDEX
=
11
;
private
static
final
int
FIELD_LAST_PERIOD_INDEX
=
12
;
private
static
final
int
FIELD_POSITION_IN_FIRST_PERIOD_US
=
13
;
/**
* {@inheritDoc}
*
* <p>It omits the {@link #uid} and {@link #manifest} fields. The {@link #uid} of an instance
* restored by {@link #CREATOR} will be a fake {@link Object} and the {@link #manifest} of the
* instance will be {@code null}.
*/
// TODO(b/166765820): See if missing fields would be okay and add them to the Bundle otherwise.
@Override
public
Bundle
toBundle
()
{
Bundle
bundle
=
new
Bundle
();
bundle
.
putBundle
(
keyForField
(
FIELD_MEDIA_ITEM
),
mediaItem
.
toBundle
());
bundle
.
putLong
(
keyForField
(
FIELD_PRESENTATION_START_TIME_MS
),
presentationStartTimeMs
);
bundle
.
putLong
(
keyForField
(
FIELD_WINDOW_START_TIME_MS
),
windowStartTimeMs
);
bundle
.
putLong
(
keyForField
(
FIELD_ELAPSED_REALTIME_EPOCH_OFFSET_MS
),
elapsedRealtimeEpochOffsetMs
);
bundle
.
putBoolean
(
keyForField
(
FIELD_IS_SEEKABLE
),
isSeekable
);
bundle
.
putBoolean
(
keyForField
(
FIELD_IS_DYNAMIC
),
isDynamic
);
@Nullable
MediaItem
.
LiveConfiguration
liveConfiguration
=
this
.
liveConfiguration
;
if
(
liveConfiguration
!=
null
)
{
bundle
.
putBundle
(
keyForField
(
FIELD_LIVE_CONFIGURATION
),
liveConfiguration
.
toBundle
());
}
bundle
.
putBoolean
(
keyForField
(
FIELD_IS_PLACEHOLDER
),
isPlaceholder
);
bundle
.
putLong
(
keyForField
(
FIELD_DEFAULT_POSITION_US
),
defaultPositionUs
);
bundle
.
putLong
(
keyForField
(
FIELD_DURATION_US
),
durationUs
);
bundle
.
putInt
(
keyForField
(
FIELD_FIRST_PERIOD_INDEX
),
firstPeriodIndex
);
bundle
.
putInt
(
keyForField
(
FIELD_LAST_PERIOD_INDEX
),
lastPeriodIndex
);
bundle
.
putLong
(
keyForField
(
FIELD_POSITION_IN_FIRST_PERIOD_US
),
positionInFirstPeriodUs
);
return
bundle
;
}
/**
* Object that can restore {@link Period} from a {@link Bundle}.
*
* <p>The {@link #uid} of a restored instance will be a fake {@link Object} and the {@link
* #manifest} of the instance will be {@code null}.
*/
public
static
final
Creator
<
Window
>
CREATOR
=
Window:
:
fromBundle
;
private
static
Window
fromBundle
(
Bundle
bundle
)
{
@Nullable
Bundle
mediaItemBundle
=
bundle
.
getBundle
(
keyForField
(
FIELD_MEDIA_ITEM
));
@Nullable
MediaItem
mediaItem
=
mediaItemBundle
!=
null
?
MediaItem
.
CREATOR
.
fromBundle
(
mediaItemBundle
)
:
null
;
long
presentationStartTimeMs
=
bundle
.
getLong
(
keyForField
(
FIELD_PRESENTATION_START_TIME_MS
),
/* defaultValue= */
C
.
TIME_UNSET
);
long
windowStartTimeMs
=
bundle
.
getLong
(
keyForField
(
FIELD_WINDOW_START_TIME_MS
),
/* defaultValue= */
C
.
TIME_UNSET
);
long
elapsedRealtimeEpochOffsetMs
=
bundle
.
getLong
(
keyForField
(
FIELD_ELAPSED_REALTIME_EPOCH_OFFSET_MS
),
/* defaultValue= */
C
.
TIME_UNSET
);
boolean
isSeekable
=
bundle
.
getBoolean
(
keyForField
(
FIELD_IS_SEEKABLE
),
/* defaultValue= */
false
);
boolean
isDynamic
=
bundle
.
getBoolean
(
keyForField
(
FIELD_IS_DYNAMIC
),
/* defaultValue= */
false
);
@Nullable
Bundle
liveConfigurationBundle
=
bundle
.
getBundle
(
keyForField
(
FIELD_LIVE_CONFIGURATION
));
@Nullable
MediaItem
.
LiveConfiguration
liveConfiguration
=
liveConfigurationBundle
!=
null
?
MediaItem
.
LiveConfiguration
.
CREATOR
.
fromBundle
(
liveConfigurationBundle
)
:
null
;
boolean
isPlaceHolder
=
bundle
.
getBoolean
(
keyForField
(
FIELD_IS_PLACEHOLDER
),
/* defaultValue= */
false
);
long
defaultPositionUs
=
bundle
.
getLong
(
keyForField
(
FIELD_DEFAULT_POSITION_US
),
/* defaultValue= */
0
);
long
durationUs
=
bundle
.
getLong
(
keyForField
(
FIELD_DURATION_US
),
/* defaultValue= */
C
.
TIME_UNSET
);
int
firstPeriodIndex
=
bundle
.
getInt
(
keyForField
(
FIELD_FIRST_PERIOD_INDEX
),
/* defaultValue= */
0
);
int
lastPeriodIndex
=
bundle
.
getInt
(
keyForField
(
FIELD_LAST_PERIOD_INDEX
),
/* defaultValue= */
0
);
long
positionInFirstPeriodUs
=
bundle
.
getLong
(
keyForField
(
FIELD_POSITION_IN_FIRST_PERIOD_US
),
/* defaultValue= */
0
);
Window
window
=
new
Window
();
window
.
set
(
FAKE_WINDOW_UID
,
mediaItem
,
/* manifest= */
null
,
presentationStartTimeMs
,
windowStartTimeMs
,
elapsedRealtimeEpochOffsetMs
,
isSeekable
,
isDynamic
,
liveConfiguration
,
defaultPositionUs
,
durationUs
,
firstPeriodIndex
,
lastPeriodIndex
,
positionInFirstPeriodUs
);
window
.
isPlaceholder
=
isPlaceHolder
;
return
window
;
}
private
static
String
keyForField
(
@Window
.
FieldNumber
int
field
)
{
return
Integer
.
toString
(
field
,
Character
.
MAX_RADIX
);
}
}
}
/**
/**
...
...
library/common/src/test/java/com/google/android/exoplayer2/TimelineTest.java
View file @
a60ed20f
...
@@ -202,6 +202,39 @@ public class TimelineTest {
...
@@ -202,6 +202,39 @@ public class TimelineTest {
}
}
@Test
@Test
public
void
roundtripViaBundle_ofWindow_yieldsEqualInstanceExceptUidAndManifest
()
{
Timeline
.
Window
window
=
new
Timeline
.
Window
();
window
.
uid
=
new
Object
();
window
.
mediaItem
=
new
MediaItem
.
Builder
().
setMediaId
(
"mediaId"
).
build
();
window
.
manifest
=
new
Object
();
window
.
presentationStartTimeMs
=
111
;
window
.
windowStartTimeMs
=
222
;
window
.
elapsedRealtimeEpochOffsetMs
=
333
;
window
.
isSeekable
=
true
;
window
.
isDynamic
=
true
;
window
.
liveConfiguration
=
new
LiveConfiguration
(
/* targetOffsetMs= */
1
,
/* minOffsetMs= */
2
,
/* maxOffsetMs= */
3
,
/* minPlaybackSpeed= */
0.5f
,
/* maxPlaybackSpeed= */
1.5f
);
window
.
isPlaceholder
=
true
;
window
.
defaultPositionUs
=
444
;
window
.
durationUs
=
555
;
window
.
firstPeriodIndex
=
6
;
window
.
lastPeriodIndex
=
7
;
window
.
positionInFirstPeriodUs
=
888
;
Timeline
.
Window
restoredWindow
=
Timeline
.
Window
.
CREATOR
.
fromBundle
(
window
.
toBundle
());
assertThat
(
restoredWindow
.
manifest
).
isNull
();
window
.
uid
=
restoredWindow
.
uid
;
window
.
manifest
=
null
;
assertThat
(
restoredWindow
).
isEqualTo
(
window
);
}
@Test
public
void
roundtripViaBundle_ofPeriod_yieldsEqualInstanceExceptIds
()
{
public
void
roundtripViaBundle_ofPeriod_yieldsEqualInstanceExceptIds
()
{
Timeline
.
Period
period
=
new
Timeline
.
Period
();
Timeline
.
Period
period
=
new
Timeline
.
Period
();
period
.
id
=
new
Object
();
period
.
id
=
new
Object
();
...
...
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