Add Mp4OrientationData class
Mp4Muxer now has a single method to accept different types of metadata. PiperOrigin-RevId: 614646331
This commit is contained in:
parent
e4a55844d0
commit
aba395ca8b
@ -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<Mp4OrientationData> CREATOR =
|
||||
new Parcelable.Creator<Mp4OrientationData>() {
|
||||
|
||||
@Override
|
||||
public Mp4OrientationData createFromParcel(Parcel in) {
|
||||
return new Mp4OrientationData(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mp4OrientationData[] newArray(int size) {
|
||||
return new Mp4OrientationData[size];
|
||||
}
|
||||
};
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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<MdtaMetadataEntry> 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;
|
||||
|
@ -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(
|
||||
|
@ -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 {
|
||||
* <p>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 {
|
||||
* <p>List of supported {@linkplain Metadata.Entry metadata entries}:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link Mp4OrientationData}
|
||||
* <li>{@link Mp4LocationData}
|
||||
* <li>{@link Mp4TimestampData}
|
||||
* <li>{@link MdtaMetadataEntry}: Only {@linkplain MdtaMetadataEntry#TYPE_INDICATOR_STRING
|
||||
|
@ -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(
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user