Implement Bundleable for MediaItem and MediaMetadata
PiperOrigin-RevId: 357656504
This commit is contained in:
parent
9de6a75891
commit
2326b56132
@ -19,10 +19,14 @@ import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
|
|||||||
import static com.google.android.exoplayer2.util.Assertions.checkState;
|
import static com.google.android.exoplayer2.util.Assertions.checkState;
|
||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import androidx.annotation.IntDef;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.offline.StreamKey;
|
import com.google.android.exoplayer2.offline.StreamKey;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -32,7 +36,7 @@ import java.util.Map;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/** Representation of a media item. */
|
/** Representation of a media item. */
|
||||||
public final class MediaItem {
|
public final class MediaItem implements Bundleable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a {@link MediaItem} for the given URI.
|
* Creates a {@link MediaItem} for the given URI.
|
||||||
@ -836,7 +840,7 @@ public final class MediaItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Live playback configuration. */
|
/** Live playback configuration. */
|
||||||
public static final class LiveConfiguration {
|
public static final class LiveConfiguration implements Bundleable {
|
||||||
|
|
||||||
/** A live playback configuration with unset values. */
|
/** A live playback configuration with unset values. */
|
||||||
public static final LiveConfiguration UNSET =
|
public static final LiveConfiguration UNSET =
|
||||||
@ -930,6 +934,52 @@ public final class MediaItem {
|
|||||||
result = 31 * result + (maxPlaybackSpeed != 0 ? Float.floatToIntBits(maxPlaybackSpeed) : 0);
|
result = 31 * result + (maxPlaybackSpeed != 0 ? Float.floatToIntBits(maxPlaybackSpeed) : 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bundleable implementation.
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
@IntDef({
|
||||||
|
FIELD_TARGET_OFFSET_MS,
|
||||||
|
FIELD_MIN_OFFSET_MS,
|
||||||
|
FIELD_MAX_OFFSET_MS,
|
||||||
|
FIELD_MIN_PLAYBACK_SPEED,
|
||||||
|
FIELD_MAX_PLAYBACK_SPEED
|
||||||
|
})
|
||||||
|
private @interface FieldNumber {}
|
||||||
|
|
||||||
|
private static final int FIELD_TARGET_OFFSET_MS = 0;
|
||||||
|
private static final int FIELD_MIN_OFFSET_MS = 1;
|
||||||
|
private static final int FIELD_MAX_OFFSET_MS = 2;
|
||||||
|
private static final int FIELD_MIN_PLAYBACK_SPEED = 3;
|
||||||
|
private static final int FIELD_MAX_PLAYBACK_SPEED = 4;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bundle toBundle() {
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putLong(keyForField(FIELD_TARGET_OFFSET_MS), targetOffsetMs);
|
||||||
|
bundle.putLong(keyForField(FIELD_MIN_OFFSET_MS), minOffsetMs);
|
||||||
|
bundle.putLong(keyForField(FIELD_MAX_OFFSET_MS), maxOffsetMs);
|
||||||
|
bundle.putFloat(keyForField(FIELD_MIN_PLAYBACK_SPEED), minPlaybackSpeed);
|
||||||
|
bundle.putFloat(keyForField(FIELD_MAX_PLAYBACK_SPEED), maxPlaybackSpeed);
|
||||||
|
return bundle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Object that can restore {@link LiveConfiguration} from a {@link Bundle}. */
|
||||||
|
public static final Creator<LiveConfiguration> CREATOR =
|
||||||
|
bundle ->
|
||||||
|
new LiveConfiguration(
|
||||||
|
bundle.getLong(
|
||||||
|
keyForField(FIELD_TARGET_OFFSET_MS), /* defaultValue= */ C.TIME_UNSET),
|
||||||
|
bundle.getLong(keyForField(FIELD_MIN_OFFSET_MS), /* defaultValue= */ C.TIME_UNSET),
|
||||||
|
bundle.getLong(keyForField(FIELD_MAX_OFFSET_MS), /* defaultValue= */ C.TIME_UNSET),
|
||||||
|
bundle.getFloat(
|
||||||
|
keyForField(FIELD_MIN_PLAYBACK_SPEED), /* defaultValue= */ C.RATE_UNSET),
|
||||||
|
bundle.getFloat(
|
||||||
|
keyForField(FIELD_MAX_PLAYBACK_SPEED), /* defaultValue= */ C.RATE_UNSET));
|
||||||
|
|
||||||
|
private static String keyForField(@LiveConfiguration.FieldNumber int field) {
|
||||||
|
return Integer.toString(field, Character.MAX_RADIX);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Properties for a text track. */
|
/** Properties for a text track. */
|
||||||
@ -1029,7 +1079,7 @@ public final class MediaItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Optionally clips the media item to a custom start and end position. */
|
/** Optionally clips the media item to a custom start and end position. */
|
||||||
public static final class ClippingProperties {
|
public static final class ClippingProperties implements Bundleable {
|
||||||
|
|
||||||
/** The start position in milliseconds. This is a value larger than or equal to zero. */
|
/** The start position in milliseconds. This is a value larger than or equal to zero. */
|
||||||
public final long startPositionMs;
|
public final long startPositionMs;
|
||||||
@ -1095,6 +1145,50 @@ public final class MediaItem {
|
|||||||
result = 31 * result + (startsAtKeyFrame ? 1 : 0);
|
result = 31 * result + (startsAtKeyFrame ? 1 : 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bundleable implementation.
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
@IntDef({
|
||||||
|
FIELD_START_POSITION_MS,
|
||||||
|
FIELD_END_POSITION_MS,
|
||||||
|
FIELD_RELATIVE_TO_LIVE_WINDOW,
|
||||||
|
FIELD_RELATIVE_TO_DEFAULT_POSITION,
|
||||||
|
FIELD_STARTS_AT_KEY_FRAME
|
||||||
|
})
|
||||||
|
private @interface FieldNumber {}
|
||||||
|
|
||||||
|
private static final int FIELD_START_POSITION_MS = 0;
|
||||||
|
private static final int FIELD_END_POSITION_MS = 1;
|
||||||
|
private static final int FIELD_RELATIVE_TO_LIVE_WINDOW = 2;
|
||||||
|
private static final int FIELD_RELATIVE_TO_DEFAULT_POSITION = 3;
|
||||||
|
private static final int FIELD_STARTS_AT_KEY_FRAME = 4;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bundle toBundle() {
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putLong(keyForField(FIELD_START_POSITION_MS), startPositionMs);
|
||||||
|
bundle.putLong(keyForField(FIELD_END_POSITION_MS), endPositionMs);
|
||||||
|
bundle.putBoolean(keyForField(FIELD_RELATIVE_TO_LIVE_WINDOW), relativeToLiveWindow);
|
||||||
|
bundle.putBoolean(keyForField(FIELD_RELATIVE_TO_DEFAULT_POSITION), relativeToDefaultPosition);
|
||||||
|
bundle.putBoolean(keyForField(FIELD_STARTS_AT_KEY_FRAME), startsAtKeyFrame);
|
||||||
|
return bundle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Object that can restore {@link ClippingProperties} from a {@link Bundle}. */
|
||||||
|
public static final Creator<ClippingProperties> CREATOR =
|
||||||
|
bundle ->
|
||||||
|
new ClippingProperties(
|
||||||
|
bundle.getLong(keyForField(FIELD_START_POSITION_MS), /* defaultValue= */ 0),
|
||||||
|
bundle.getLong(
|
||||||
|
keyForField(FIELD_END_POSITION_MS), /* defaultValue= */ C.TIME_END_OF_SOURCE),
|
||||||
|
bundle.getBoolean(keyForField(FIELD_RELATIVE_TO_LIVE_WINDOW), false),
|
||||||
|
bundle.getBoolean(keyForField(FIELD_RELATIVE_TO_DEFAULT_POSITION), false),
|
||||||
|
bundle.getBoolean(keyForField(FIELD_STARTS_AT_KEY_FRAME), false));
|
||||||
|
|
||||||
|
private static String keyForField(@ClippingProperties.FieldNumber int field) {
|
||||||
|
return Integer.toString(field, Character.MAX_RADIX);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Identifies the media item. */
|
/** Identifies the media item. */
|
||||||
@ -1157,4 +1251,75 @@ public final class MediaItem {
|
|||||||
result = 31 * result + mediaMetadata.hashCode();
|
result = 31 * result + mediaMetadata.hashCode();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bundleable implementation.
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
@IntDef({
|
||||||
|
FIELD_MEDIA_ID,
|
||||||
|
FIELD_LIVE_CONFIGURATION,
|
||||||
|
FIELD_MEDIA_METADATA,
|
||||||
|
FIELD_CLIPPING_PROPERTIES
|
||||||
|
})
|
||||||
|
private @interface FieldNumber {}
|
||||||
|
|
||||||
|
private static final int FIELD_MEDIA_ID = 0;
|
||||||
|
private static final int FIELD_LIVE_CONFIGURATION = 1;
|
||||||
|
private static final int FIELD_MEDIA_METADATA = 2;
|
||||||
|
private static final int FIELD_CLIPPING_PROPERTIES = 3;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bundle toBundle() {
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putString(keyForField(FIELD_MEDIA_ID), mediaId);
|
||||||
|
bundle.putBundle(keyForField(FIELD_LIVE_CONFIGURATION), liveConfiguration.toBundle());
|
||||||
|
bundle.putBundle(keyForField(FIELD_MEDIA_METADATA), mediaMetadata.toBundle());
|
||||||
|
bundle.putBundle(keyForField(FIELD_CLIPPING_PROPERTIES), clippingProperties.toBundle());
|
||||||
|
return bundle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Object that can restore {@link MediaItem} from a {@link Bundle}. */
|
||||||
|
public static final Creator<MediaItem> CREATOR =
|
||||||
|
bundle -> {
|
||||||
|
String mediaId = checkNotNull(bundle.getString(keyForField(FIELD_MEDIA_ID)));
|
||||||
|
@Nullable
|
||||||
|
Bundle liveConfigurationBundle = bundle.getBundle(keyForField(FIELD_LIVE_CONFIGURATION));
|
||||||
|
LiveConfiguration liveConfiguration;
|
||||||
|
if (liveConfigurationBundle == null) {
|
||||||
|
liveConfiguration = LiveConfiguration.UNSET;
|
||||||
|
} else {
|
||||||
|
liveConfiguration = LiveConfiguration.CREATOR.fromBundle(liveConfigurationBundle);
|
||||||
|
}
|
||||||
|
@Nullable Bundle mediaMetadataBundle = bundle.getBundle(keyForField(FIELD_MEDIA_METADATA));
|
||||||
|
MediaMetadata mediaMetadata;
|
||||||
|
if (mediaMetadataBundle == null) {
|
||||||
|
mediaMetadata = new MediaMetadata.Builder().build();
|
||||||
|
} else {
|
||||||
|
mediaMetadata = MediaMetadata.CREATOR.fromBundle(mediaMetadataBundle);
|
||||||
|
}
|
||||||
|
@Nullable
|
||||||
|
Bundle clippingPropertiesBundle = bundle.getBundle(keyForField(FIELD_CLIPPING_PROPERTIES));
|
||||||
|
ClippingProperties clippingProperties;
|
||||||
|
if (clippingPropertiesBundle == null) {
|
||||||
|
clippingProperties =
|
||||||
|
new ClippingProperties(
|
||||||
|
/* startPositionMs= */ 0,
|
||||||
|
/* endPositionMs= */ C.TIME_END_OF_SOURCE,
|
||||||
|
/* relativeToLiveWindow= */ false,
|
||||||
|
/* relativeToDefaultPosition= */ false,
|
||||||
|
/* startsAtKeyFrame= */ false);
|
||||||
|
} else {
|
||||||
|
clippingProperties = ClippingProperties.CREATOR.fromBundle(clippingPropertiesBundle);
|
||||||
|
}
|
||||||
|
return new MediaItem(
|
||||||
|
mediaId,
|
||||||
|
clippingProperties,
|
||||||
|
/* playbackProperties= */ null,
|
||||||
|
liveConfiguration,
|
||||||
|
mediaMetadata);
|
||||||
|
};
|
||||||
|
|
||||||
|
private static String keyForField(@FieldNumber int field) {
|
||||||
|
return Integer.toString(field, Character.MAX_RADIX);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,11 +15,15 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2;
|
package com.google.android.exoplayer2;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import androidx.annotation.IntDef;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
/** Metadata of the {@link MediaItem}. */
|
/** Metadata of the {@link MediaItem}. */
|
||||||
public final class MediaMetadata {
|
public final class MediaMetadata implements Bundleable {
|
||||||
|
|
||||||
/** A builder for {@link MediaMetadata} instances. */
|
/** A builder for {@link MediaMetadata} instances. */
|
||||||
public static final class Builder {
|
public static final class Builder {
|
||||||
@ -62,4 +66,29 @@ public final class MediaMetadata {
|
|||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return title == null ? 0 : title.hashCode();
|
return title == null ? 0 : title.hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bundleable implementation.
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
@IntDef({
|
||||||
|
FIELD_TITLE,
|
||||||
|
})
|
||||||
|
private @interface FieldNumber {}
|
||||||
|
|
||||||
|
private static final int FIELD_TITLE = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bundle toBundle() {
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putString(keyForField(FIELD_TITLE), title);
|
||||||
|
return bundle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Object that can restore {@link MediaMetadata} from a {@link Bundle}. */
|
||||||
|
public static final Creator<MediaMetadata> CREATOR =
|
||||||
|
bundle -> new MediaMetadata(bundle.getString(keyForField(FIELD_TITLE)));
|
||||||
|
|
||||||
|
private static String keyForField(@FieldNumber int field) {
|
||||||
|
return Integer.toString(field, Character.MAX_RADIX);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -393,4 +393,34 @@ public class MediaItemTest {
|
|||||||
|
|
||||||
assertThat(copy).isEqualTo(mediaItem);
|
assertThat(copy).isEqualTo(mediaItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void roundtripViaBundle_withoutPlaybackProperties_yieldsEqualInstance() {
|
||||||
|
MediaItem mediaItem =
|
||||||
|
new MediaItem.Builder()
|
||||||
|
.setMediaId("mediaId")
|
||||||
|
.setLiveTargetOffsetMs(20_000)
|
||||||
|
.setLiveMinOffsetMs(2_222)
|
||||||
|
.setLiveMaxOffsetMs(4_444)
|
||||||
|
.setLiveMinPlaybackSpeed(.9f)
|
||||||
|
.setLiveMaxPlaybackSpeed(1.1f)
|
||||||
|
.setMediaMetadata(new MediaMetadata.Builder().setTitle("title").build())
|
||||||
|
.setClipStartPositionMs(100)
|
||||||
|
.setClipEndPositionMs(1_000)
|
||||||
|
.setClipRelativeToDefaultPosition(true)
|
||||||
|
.setClipRelativeToLiveWindow(true)
|
||||||
|
.setClipStartsAtKeyFrame(true)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assertThat(mediaItem.playbackProperties).isNull();
|
||||||
|
assertThat(MediaItem.CREATOR.fromBundle(mediaItem.toBundle())).isEqualTo(mediaItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void roundtripViaBundle_withPlaybackProperties_dropsPlaybackProperties() {
|
||||||
|
MediaItem mediaItem = new MediaItem.Builder().setUri(URI_STRING).build();
|
||||||
|
|
||||||
|
assertThat(mediaItem.playbackProperties).isNotNull();
|
||||||
|
assertThat(MediaItem.CREATOR.fromBundle(mediaItem.toBundle()).playbackProperties).isNull();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,4 +40,11 @@ public class MediaMetadataTest {
|
|||||||
|
|
||||||
assertThat(mediaMetadata.title).isEqualTo(title);
|
assertThat(mediaMetadata.title).isEqualTo(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void roundtripViaBundle_yieldsEqualInstance() {
|
||||||
|
MediaMetadata mediaMetadata = new MediaMetadata.Builder().setTitle("title").build();
|
||||||
|
|
||||||
|
assertThat(MediaMetadata.CREATOR.fromBundle(mediaMetadata.toBundle())).isEqualTo(mediaMetadata);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user