From aba395ca8b88d16a2bd292462cad5e0623562705 Mon Sep 17 00:00:00 2001 From: sheenachhabra Date: Mon, 11 Mar 2024 06:43:00 -0700 Subject: [PATCH] Add Mp4OrientationData class Mp4Muxer now has a single method to accept different types of metadata. PiperOrigin-RevId: 614646331 --- .../media3/container/Mp4OrientationData.java | 97 +++++++++++++++++++ .../container/Mp4OrientationDataTest.java | 42 ++++++++ .../media3/muxer/MetadataCollector.java | 15 +-- .../media3/muxer/Mp4MoovStructure.java | 2 +- .../java/androidx/media3/muxer/Mp4Muxer.java | 12 ++- .../media3/muxer/Mp4MuxerEndToEndTest.java | 5 +- .../media3/muxer/Mp4MuxerMetadataTest.java | 7 +- .../media3/transformer/InAppMuxer.java | 3 +- 8 files changed, 164 insertions(+), 19 deletions(-) create mode 100644 libraries/container/src/main/java/androidx/media3/container/Mp4OrientationData.java create mode 100644 libraries/container/src/test/java/androidx/media3/container/Mp4OrientationDataTest.java diff --git a/libraries/container/src/main/java/androidx/media3/container/Mp4OrientationData.java b/libraries/container/src/main/java/androidx/media3/container/Mp4OrientationData.java new file mode 100644 index 0000000000..d8145620ca --- /dev/null +++ b/libraries/container/src/main/java/androidx/media3/container/Mp4OrientationData.java @@ -0,0 +1,97 @@ +/* + * Copyright 2024 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 androidx.media3.container; + +import static androidx.media3.common.util.Assertions.checkArgument; + +import android.os.Parcel; +import android.os.Parcelable; +import androidx.annotation.Nullable; +import androidx.media3.common.Metadata; +import androidx.media3.common.util.UnstableApi; + +/** Stores the orientation hint for the video playback. */ +@UnstableApi +public final class Mp4OrientationData implements Metadata.Entry { + public final int orientation; + + /** + * Creates an instance. + * + * @param orientation The orientation, in degrees. The supported values are 0, 90, 180 and 270 + * (degrees). + */ + public Mp4OrientationData(int orientation) { + checkArgument( + orientation == 0 || orientation == 90 || orientation == 180 || orientation == 270, + "Unsupported orientation"); + this.orientation = orientation; + } + + private Mp4OrientationData(Parcel in) { + orientation = in.readInt(); + } + + @Override + public boolean equals(@Nullable Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof Mp4OrientationData)) { + return false; + } + Mp4OrientationData other = (Mp4OrientationData) obj; + return orientation == other.orientation; + } + + @Override + public int hashCode() { + int result = 17; + result = 31 * result + Integer.hashCode(orientation); + return result; + } + + @Override + public String toString() { + return "Orientation= " + orientation; + } + + // Parcelable implementation. + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(orientation); + } + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + + @Override + public Mp4OrientationData createFromParcel(Parcel in) { + return new Mp4OrientationData(in); + } + + @Override + public Mp4OrientationData[] newArray(int size) { + return new Mp4OrientationData[size]; + } + }; +} diff --git a/libraries/container/src/test/java/androidx/media3/container/Mp4OrientationDataTest.java b/libraries/container/src/test/java/androidx/media3/container/Mp4OrientationDataTest.java new file mode 100644 index 0000000000..da4f6feb8c --- /dev/null +++ b/libraries/container/src/test/java/androidx/media3/container/Mp4OrientationDataTest.java @@ -0,0 +1,42 @@ +/* + * Copyright 2024 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 androidx.media3.container; + +import static com.google.common.truth.Truth.assertThat; + +import android.os.Parcel; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** Test for {@link Mp4OrientationData}. */ +@RunWith(AndroidJUnit4.class) +public final class Mp4OrientationDataTest { + + @Test + public void parcelable() { + Mp4OrientationData mp4OrientationData = new Mp4OrientationData(/* orientation= */ 90); + + Parcel parcel = Parcel.obtain(); + mp4OrientationData.writeToParcel(parcel, /* flags= */ 0); + parcel.setDataPosition(0); + + Mp4OrientationData mp4OrientationDataFromParcel = + Mp4OrientationData.CREATOR.createFromParcel(parcel); + assertThat(mp4OrientationDataFromParcel).isEqualTo(mp4OrientationData); + parcel.recycle(); + } +} diff --git a/libraries/muxer/src/main/java/androidx/media3/muxer/MetadataCollector.java b/libraries/muxer/src/main/java/androidx/media3/muxer/MetadataCollector.java index b4ecad0631..0863405733 100644 --- a/libraries/muxer/src/main/java/androidx/media3/muxer/MetadataCollector.java +++ b/libraries/muxer/src/main/java/androidx/media3/muxer/MetadataCollector.java @@ -20,6 +20,7 @@ import static androidx.media3.container.Mp4TimestampData.unixTimeToMp4TimeSecond import androidx.media3.common.Metadata; import androidx.media3.container.MdtaMetadataEntry; import androidx.media3.container.Mp4LocationData; +import androidx.media3.container.Mp4OrientationData; import androidx.media3.container.Mp4TimestampData; import androidx.media3.container.XmpData; import java.util.ArrayList; @@ -28,14 +29,15 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; /** Collects and provides metadata: location, FPS, XMP data, etc. */ /* package */ final class MetadataCollector { - public int orientation; + public Mp4OrientationData orientationData; public @MonotonicNonNull Mp4LocationData locationData; public List metadataEntries; public Mp4TimestampData timestampData; public @MonotonicNonNull XmpData xmpData; + /** Creates an instance. */ public MetadataCollector() { - orientation = 0; + orientationData = new Mp4OrientationData(/* orientation= */ 0); metadataEntries = new ArrayList<>(); long currentTimeInMp4TimeSeconds = unixTimeToMp4TimeSeconds(System.currentTimeMillis()); timestampData = @@ -44,12 +46,11 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; /* modificationTimestampSeconds= */ currentTimeInMp4TimeSeconds); } - public void setOrientation(int orientation) { - this.orientation = orientation; - } - + /** Adds metadata for the output file. */ public void addMetadata(Metadata.Entry metadata) { - if (metadata instanceof Mp4LocationData) { + if (metadata instanceof Mp4OrientationData) { + orientationData = (Mp4OrientationData) metadata; + } else if (metadata instanceof Mp4LocationData) { locationData = (Mp4LocationData) metadata; } else if (metadata instanceof Mp4TimestampData) { timestampData = (Mp4TimestampData) metadata; diff --git a/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4MoovStructure.java b/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4MoovStructure.java index ec71e235cc..b0cfb1ba46 100644 --- a/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4MoovStructure.java +++ b/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4MoovStructure.java @@ -157,7 +157,7 @@ import org.checkerframework.checker.nullness.qual.PolyNull; (int) Mp4Utils.vuFromUs(trackDurationUs, MVHD_TIMEBASE), creationTimestampSeconds, modificationTimestampSeconds, - metadataCollector.orientation, + metadataCollector.orientationData.orientation, format), Boxes.mdia( Boxes.mdhd( diff --git a/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Muxer.java b/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Muxer.java index cdbb55ae92..12a5a213fd 100644 --- a/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Muxer.java +++ b/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Muxer.java @@ -31,6 +31,7 @@ import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; import androidx.media3.container.MdtaMetadataEntry; import androidx.media3.container.Mp4LocationData; +import androidx.media3.container.Mp4OrientationData; import androidx.media3.container.Mp4TimestampData; import androidx.media3.container.XmpData; import com.google.common.collect.ImmutableList; @@ -216,7 +217,8 @@ public final class Mp4Muxer { *

For the list of supported metadata refer to {@link Mp4Muxer#addMetadata(Metadata.Entry)}. */ public static boolean isMetadataSupported(Metadata.Entry metadata) { - return metadata instanceof Mp4LocationData + return metadata instanceof Mp4OrientationData + || metadata instanceof Mp4LocationData || (metadata instanceof Mp4TimestampData && isMp4TimestampDataSupported((Mp4TimestampData) metadata)) || (metadata instanceof MdtaMetadataEntry @@ -225,12 +227,11 @@ public final class Mp4Muxer { } /** - * Sets the orientation hint for the video playback. - * - * @param orientation The orientation, in degrees. + * @deprecated Use {@link #addMetadata(Metadata.Entry)} with {@link Mp4OrientationData} instead. */ + @Deprecated public void setOrientation(int orientation) { - metadataCollector.setOrientation(orientation); + addMetadata(new Mp4OrientationData(orientation)); } /** @@ -289,6 +290,7 @@ public final class Mp4Muxer { *

List of supported {@linkplain Metadata.Entry metadata entries}: * *

    + *
  • {@link Mp4OrientationData} *
  • {@link Mp4LocationData} *
  • {@link Mp4TimestampData} *
  • {@link MdtaMetadataEntry}: Only {@linkplain MdtaMetadataEntry#TYPE_INDICATOR_STRING diff --git a/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerEndToEndTest.java b/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerEndToEndTest.java index daaef7a59c..55cca99ff2 100644 --- a/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerEndToEndTest.java +++ b/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerEndToEndTest.java @@ -27,6 +27,7 @@ import android.util.Pair; import androidx.media3.common.util.Util; import androidx.media3.container.MdtaMetadataEntry; import androidx.media3.container.Mp4LocationData; +import androidx.media3.container.Mp4OrientationData; import androidx.media3.container.Mp4TimestampData; import androidx.media3.container.XmpData; import androidx.media3.extractor.mp4.Mp4Extractor; @@ -59,7 +60,7 @@ public class Mp4MuxerEndToEndTest { try { mp4Muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT); - mp4Muxer.setOrientation(90); + mp4Muxer.addMetadata(new Mp4OrientationData(/* orientation= */ 90)); mp4Muxer.addMetadata( new MdtaMetadataEntry( "key", @@ -219,7 +220,7 @@ public class Mp4MuxerEndToEndTest { byte[] xmpBytes = TestUtil.getByteArray(context, XMP_SAMPLE_DATA); try { - muxer.setOrientation(90); + muxer.addMetadata(new Mp4OrientationData(/* orientation= */ 90)); muxer.addMetadata(new Mp4LocationData(/* latitude= */ 33.0f, /* longitude= */ -120f)); float captureFps = 120.0f; muxer.addMetadata( diff --git a/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerMetadataTest.java b/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerMetadataTest.java index dc51f165ae..66a7bb7b6f 100644 --- a/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerMetadataTest.java +++ b/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerMetadataTest.java @@ -21,6 +21,7 @@ import static androidx.media3.muxer.MuxerTestUtil.XMP_SAMPLE_DATA; import android.content.Context; import android.media.MediaCodec.BufferInfo; import android.util.Pair; +import androidx.media3.container.Mp4OrientationData; import androidx.media3.container.Mp4TimestampData; import androidx.media3.extractor.mp4.Mp4Extractor; import androidx.media3.muxer.Mp4Muxer.TrackToken; @@ -84,7 +85,7 @@ public class Mp4MuxerMetadataTest { TrackToken token = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT); muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second); - muxer.setOrientation(90); + muxer.addMetadata(new Mp4OrientationData(/* orientation= */ 90)); } finally { muxer.close(); } @@ -111,7 +112,7 @@ public class Mp4MuxerMetadataTest { TrackToken token = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT); muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second); - muxer.setOrientation(180); + muxer.addMetadata(new Mp4OrientationData(/* orientation= */ 180)); } finally { muxer.close(); } @@ -138,7 +139,7 @@ public class Mp4MuxerMetadataTest { TrackToken token = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT); muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second); - muxer.setOrientation(270); + muxer.addMetadata(new Mp4OrientationData(/* orientation= */ 270)); } finally { muxer.close(); } diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/InAppMuxer.java b/libraries/transformer/src/main/java/androidx/media3/transformer/InAppMuxer.java index 8ad031574a..5ded6bd4a3 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/InAppMuxer.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/InAppMuxer.java @@ -24,6 +24,7 @@ import androidx.media3.common.Format; import androidx.media3.common.Metadata; import androidx.media3.common.MimeTypes; import androidx.media3.common.util.UnstableApi; +import androidx.media3.container.Mp4OrientationData; import androidx.media3.muxer.Mp4Muxer; import androidx.media3.muxer.Mp4Muxer.TrackToken; import com.google.common.collect.ImmutableList; @@ -184,7 +185,7 @@ public final class InAppMuxer implements Muxer { trackTokenList.add(trackToken); if (MimeTypes.isVideo(format.sampleMimeType)) { - mp4Muxer.setOrientation(format.rotationDegrees); + mp4Muxer.addMetadata(new Mp4OrientationData(format.rotationDegrees)); } return trackTokenList.size() - 1;