diff --git a/library/common/src/main/java/com/google/android/exoplayer2/metadata/mp4/SefSlowMotion.java b/library/common/src/main/java/com/google/android/exoplayer2/metadata/mp4/SefSlowMotion.java
new file mode 100644
index 0000000000..d3e9f29d5c
--- /dev/null
+++ b/library/common/src/main/java/com/google/android/exoplayer2/metadata/mp4/SefSlowMotion.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.exoplayer2.metadata.mp4;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import androidx.annotation.Nullable;
+import com.google.android.exoplayer2.metadata.Metadata;
+import com.google.android.exoplayer2.util.Util;
+import com.google.common.base.Objects;
+import java.util.ArrayList;
+import java.util.List;
+
+/** Holds information about the segments of slow motion playback within a track. */
+public final class SefSlowMotion implements Metadata.Entry {
+
+ /** Holds information about a single segment of slow motion playback within a track. */
+ public static final class Segment implements Parcelable {
+
+ /** The start time, in milliseconds, of the track segment that is intended to be slow motion. */
+ public final int startTimeMs;
+ /** The end time, in milliseconds, of the track segment that is intended to be slow motion. */
+ public final int endTimeMs;
+ /**
+ * The speed reduction factor.
+ *
+ *
For example, 4 would mean the segment should be played at a quarter (1/4) of the normal
+ * speed.
+ */
+ public final int speedDivisor;
+
+ /**
+ * Creates an instance.
+ *
+ * @param startTimeMs See {@link #startTimeMs}.
+ * @param endTimeMs See {@link #endTimeMs}.
+ * @param speedDivisor See {@link #speedDivisor}.
+ */
+ public Segment(int startTimeMs, int endTimeMs, int speedDivisor) {
+ this.startTimeMs = startTimeMs;
+ this.endTimeMs = endTimeMs;
+ this.speedDivisor = speedDivisor;
+ }
+
+ @Override
+ public String toString() {
+ return Util.formatInvariant(
+ "Segment: startTimeMs=%d, endTimeMs=%d, speedDivisor=%d",
+ startTimeMs, endTimeMs, speedDivisor);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Segment segment = (Segment) o;
+ return startTimeMs == segment.startTimeMs
+ && endTimeMs == segment.endTimeMs
+ && speedDivisor == segment.speedDivisor;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(startTimeMs, endTimeMs, speedDivisor);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(startTimeMs);
+ dest.writeInt(endTimeMs);
+ dest.writeInt(speedDivisor);
+ }
+
+ public static final Creator CREATOR =
+ new Creator() {
+
+ @Override
+ public Segment createFromParcel(Parcel in) {
+ int startTimeMs = in.readInt();
+ int endTimeMs = in.readInt();
+ int speedDivisor = in.readInt();
+ return new Segment(startTimeMs, endTimeMs, speedDivisor);
+ }
+
+ @Override
+ public Segment[] newArray(int size) {
+ return new Segment[size];
+ }
+ };
+ }
+
+ public final List segments;
+
+ /** Creates an instance with a list of {@link Segment}s. */
+ public SefSlowMotion(List segments) {
+ this.segments = segments;
+ }
+
+ @Override
+ public String toString() {
+ return "SefSlowMotion: segments=" + segments;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ SefSlowMotion that = (SefSlowMotion) o;
+ return segments.equals(that.segments);
+ }
+
+ @Override
+ public int hashCode() {
+ return segments.hashCode();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeList(segments);
+ }
+
+ public static final Creator CREATOR =
+ new Creator() {
+ @Override
+ public SefSlowMotion createFromParcel(Parcel in) {
+ List slowMotionSegments = new ArrayList<>();
+ in.readList(slowMotionSegments, Segment.class.getClassLoader());
+ return new SefSlowMotion(slowMotionSegments);
+ }
+
+ @Override
+ public SefSlowMotion[] newArray(int size) {
+ return new SefSlowMotion[size];
+ }
+ };
+}
diff --git a/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/mp4/SefSlowMotionTest.java b/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/mp4/SefSlowMotionTest.java
new file mode 100644
index 0000000000..fe602a1790
--- /dev/null
+++ b/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/mp4/SefSlowMotionTest.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.exoplayer2.extractor.mp4;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Parcel;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import com.google.android.exoplayer2.metadata.mp4.SefSlowMotion;
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Unit test for {@link SefSlowMotion} */
+@RunWith(AndroidJUnit4.class)
+public class SefSlowMotionTest {
+
+ @Test
+ public void parcelable() {
+ List segments = new ArrayList<>();
+ segments.add(
+ new SefSlowMotion.Segment(
+ /* startTimeMs= */ 1000, /* endTimeMs= */ 2000, /* speedDivisor= */ 4));
+ segments.add(
+ new SefSlowMotion.Segment(
+ /* startTimeMs= */ 2600, /* endTimeMs= */ 4000, /* speedDivisor= */ 8));
+ segments.add(
+ new SefSlowMotion.Segment(
+ /* startTimeMs= */ 8765, /* endTimeMs= */ 12485, /* speedDivisor= */ 16));
+
+ SefSlowMotion sefSlowMotionToParcel = new SefSlowMotion(segments);
+ Parcel parcel = Parcel.obtain();
+ sefSlowMotionToParcel.writeToParcel(parcel, /* flags= */ 0);
+ parcel.setDataPosition(0);
+
+ SefSlowMotion sefSlowMotionFromParcel = SefSlowMotion.CREATOR.createFromParcel(parcel);
+ assertThat(sefSlowMotionFromParcel).isEqualTo(sefSlowMotionToParcel);
+
+ parcel.recycle();
+ }
+
+ @Test
+ public void segment_parcelable() {
+ SefSlowMotion.Segment segmentToParcel =
+ new SefSlowMotion.Segment(
+ /* startTimeMs= */ 1000, /* endTimeMs= */ 2000, /* speedDivisor= */ 4);
+
+ Parcel parcel = Parcel.obtain();
+ segmentToParcel.writeToParcel(parcel, /* flags= */ 0);
+ parcel.setDataPosition(0);
+
+ SefSlowMotion.Segment segmentFromParcel =
+ SefSlowMotion.Segment.CREATOR.createFromParcel(parcel);
+ assertThat(segmentFromParcel).isEqualTo(segmentToParcel);
+
+ parcel.recycle();
+ }
+}