/* * Copyright (C) 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 android.media.metrics; import static com.android.media.editing.flags.Flags.FLAG_ADD_MEDIA_METRICS_EDITING; import android.annotation.FlaggedApi; import android.annotation.FloatRange; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.LongDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.hardware.DataSpace; import android.media.MediaCodec; import android.os.Parcel; import android.os.Parcelable; import android.util.Size; import java.lang.annotation.Retention; import java.util.ArrayList; import java.util.List; import java.util.Objects; /** Represents information about a piece of media (for example, an audio or video file). */ @FlaggedApi(FLAG_ADD_MEDIA_METRICS_EDITING) public final class MediaItemInfo implements Parcelable { /** @hide */ @IntDef( prefix = {"SOURCE_TYPE_"}, value = { SOURCE_TYPE_UNSPECIFIED, SOURCE_TYPE_GALLERY, SOURCE_TYPE_CAMERA, SOURCE_TYPE_EDITING_SESSION, SOURCE_TYPE_LOCAL_FILE, SOURCE_TYPE_REMOTE_FILE, SOURCE_TYPE_REMOTE_LIVE_STREAM, SOURCE_TYPE_GENERATED, }) @Retention(java.lang.annotation.RetentionPolicy.SOURCE) public @interface SourceType {} /** The media item's source is not known. */ public static final int SOURCE_TYPE_UNSPECIFIED = 0; /** The media item came from the device gallery. */ public static final int SOURCE_TYPE_GALLERY = 1; /** The media item came directly from camera capture. */ public static final int SOURCE_TYPE_CAMERA = 2; /** The media item was output by a previous editing session. */ public static final int SOURCE_TYPE_EDITING_SESSION = 3; /** The media item is stored on the local device's file system. */ public static final int SOURCE_TYPE_LOCAL_FILE = 4; /** The media item is a remote file (for example, it's loaded from an HTTP server). */ public static final int SOURCE_TYPE_REMOTE_FILE = 5; /** The media item is a remotely-served live stream. */ public static final int SOURCE_TYPE_REMOTE_LIVE_STREAM = 6; /** The media item was generated by another system. */ public static final int SOURCE_TYPE_GENERATED = 7; /** @hide */ @LongDef( prefix = {"DATA_TYPE_"}, flag = true, value = { DATA_TYPE_IMAGE, DATA_TYPE_VIDEO, DATA_TYPE_AUDIO, DATA_TYPE_METADATA, DATA_TYPE_DEPTH, DATA_TYPE_GAIN_MAP, DATA_TYPE_HIGH_FRAME_RATE, DATA_TYPE_SPEED_SETTING_CUE_POINTS, DATA_TYPE_GAPLESS, DATA_TYPE_SPATIAL_AUDIO, DATA_TYPE_HIGH_DYNAMIC_RANGE_VIDEO, }) @Retention(java.lang.annotation.RetentionPolicy.SOURCE) public @interface DataType {} /** The media item includes image data. */ public static final long DATA_TYPE_IMAGE = 1L; /** The media item includes video data. */ public static final long DATA_TYPE_VIDEO = 1L << 1; /** The media item includes audio data. */ public static final long DATA_TYPE_AUDIO = 1L << 2; /** * The media item includes static media container metadata (for example, capture frame rate or * location information). */ public static final long DATA_TYPE_METADATA = 1L << 3; /** The media item includes depth (z-distance) information. */ public static final long DATA_TYPE_DEPTH = 1L << 4; /** The media item includes gain map information (for example, an Ultra HDR gain map). */ public static final long DATA_TYPE_GAIN_MAP = 1L << 5; /** The media item includes high frame rate video data. */ public static final long DATA_TYPE_HIGH_FRAME_RATE = 1L << 6; /** * The media item includes time-dependent speed information (for example, slow motion cue * points). */ public static final long DATA_TYPE_SPEED_SETTING_CUE_POINTS = 1L << 7; /** The media item includes gapless audio metadata. */ public static final long DATA_TYPE_GAPLESS = 1L << 8; /** The media item includes spatial audio data. */ public static final long DATA_TYPE_SPATIAL_AUDIO = 1L << 9; /** The media item includes high dynamic range (HDR) video. */ public static final long DATA_TYPE_HIGH_DYNAMIC_RANGE_VIDEO = 1L << 10; /** Special value for numerical fields where the value was not specified. */ public static final int VALUE_UNSPECIFIED = -1; private final @SourceType int mSourceType; private final @DataType long mDataTypes; private final long mDurationMillis; private final long mClipDurationMillis; @Nullable private final String mContainerMimeType; private final List mSampleMimeTypes; private final List mCodecNames; private final int mAudioSampleRateHz; private final int mAudioChannelCount; private final long mAudioSampleCount; private final Size mVideoSize; private final int mVideoDataSpace; private final float mVideoFrameRate; private final long mVideoSampleCount; private MediaItemInfo( @SourceType int sourceType, @DataType long dataTypes, long durationMillis, long clipDurationMillis, @Nullable String containerMimeType, List sampleMimeTypes, List codecNames, int audioSampleRateHz, int audioChannelCount, long audioSampleCount, Size videoSize, int videoDataSpace, float videoFrameRate, long videoSampleCount) { mSourceType = sourceType; mDataTypes = dataTypes; mDurationMillis = durationMillis; mClipDurationMillis = clipDurationMillis; mContainerMimeType = containerMimeType; mSampleMimeTypes = sampleMimeTypes; mCodecNames = codecNames; mAudioSampleRateHz = audioSampleRateHz; mAudioChannelCount = audioChannelCount; mAudioSampleCount = audioSampleCount; mVideoSize = videoSize; mVideoDataSpace = videoDataSpace; mVideoFrameRate = videoFrameRate; mVideoSampleCount = videoSampleCount; } /** * Returns where the media item came from, or {@link #SOURCE_TYPE_UNSPECIFIED} if not specified. */ public @SourceType int getSourceType() { return mSourceType; } /** Returns the data types that are present in the media item. */ public @DataType long getDataTypes() { return mDataTypes; } /** * Returns the duration of the media item, in milliseconds, or {@link #VALUE_UNSPECIFIED} if not * specified. */ public long getDurationMillis() { return mDurationMillis; } /** * Returns the duration of the clip taken from the media item, in milliseconds, or {@link * #VALUE_UNSPECIFIED} if not specified. */ public long getClipDurationMillis() { return mClipDurationMillis; } /** Returns the MIME type of the media container, or {@code null} if unspecified. */ @Nullable public String getContainerMimeType() { return mContainerMimeType; } /** * Returns the MIME types of samples stored in the media container, or an empty list if not * known. */ @NonNull public List getSampleMimeTypes() { return new ArrayList<>(mSampleMimeTypes); } /** * Returns the {@linkplain MediaCodec#getName() media codec names} for codecs that were used as * part of encoding/decoding this media item, or an empty list if not known or not applicable. */ @NonNull public List getCodecNames() { return new ArrayList<>(mCodecNames); } /** * Returns the sample rate of audio, in Hertz, or {@link #VALUE_UNSPECIFIED} if not specified. */ public int getAudioSampleRateHz() { return mAudioSampleRateHz; } /** Returns the number of audio channels, or {@link #VALUE_UNSPECIFIED} if not specified. */ public int getAudioChannelCount() { return mAudioChannelCount; } /** * Returns the number of audio frames in the item, after clipping (if applicable), or {@link * #VALUE_UNSPECIFIED} if not specified. */ public long getAudioSampleCount() { return mAudioSampleCount; } /** * Returns the video size, in pixels, or a {@link Size} with width and height set to {@link * #VALUE_UNSPECIFIED} if not specified. */ @NonNull public Size getVideoSize() { return mVideoSize; } /** Returns the {@linkplain DataSpace data space} for video, as a packed integer. */ @SuppressLint("MethodNameUnits") // Packed integer for an android.hardware.DataSpace. public int getVideoDataSpace() { return mVideoDataSpace; } /** * Returns the average video frame rate, in frames per second, or {@link #VALUE_UNSPECIFIED} if * not specified. */ public float getVideoFrameRate() { return mVideoFrameRate; } /** * Returns the number of video frames, aftrer clipping (if applicable), or {@link * #VALUE_UNSPECIFIED} if not specified. */ public long getVideoSampleCount() { return mVideoSampleCount; } /** Builder for {@link MediaItemInfo}. */ @FlaggedApi(FLAG_ADD_MEDIA_METRICS_EDITING) public static final class Builder { private @SourceType int mSourceType; private @DataType long mDataTypes; private long mDurationMillis; private long mClipDurationMillis; @Nullable private String mContainerMimeType; private final ArrayList mSampleMimeTypes; private final ArrayList mCodecNames; private int mAudioSampleRateHz; private int mAudioChannelCount; private long mAudioSampleCount; @Nullable private Size mVideoSize; private int mVideoDataSpace; private float mVideoFrameRate; private long mVideoSampleCount; /** Creates a new builder. */ public Builder() { mSourceType = SOURCE_TYPE_UNSPECIFIED; mDurationMillis = VALUE_UNSPECIFIED; mClipDurationMillis = VALUE_UNSPECIFIED; mSampleMimeTypes = new ArrayList<>(); mCodecNames = new ArrayList<>(); mAudioSampleRateHz = VALUE_UNSPECIFIED; mAudioChannelCount = VALUE_UNSPECIFIED; mAudioSampleCount = VALUE_UNSPECIFIED; mVideoSize = new Size(VALUE_UNSPECIFIED, VALUE_UNSPECIFIED); mVideoFrameRate = VALUE_UNSPECIFIED; mVideoSampleCount = VALUE_UNSPECIFIED; } /** Sets where the media item came from. */ public @NonNull Builder setSourceType(@SourceType int sourceType) { mSourceType = sourceType; return this; } /** Adds an additional data type represented as part of the media item. */ public @NonNull Builder addDataType(@DataType long dataType) { mDataTypes |= dataType; return this; } /** Sets the duration of the media item, in milliseconds. */ public @NonNull Builder setDurationMillis(long durationMillis) { mDurationMillis = durationMillis; return this; } /** Sets the duration of the clip taken from the media item, in milliseconds. */ public @NonNull Builder setClipDurationMillis(long clipDurationMillis) { mClipDurationMillis = clipDurationMillis; return this; } /** Sets the MIME type of the media container. */ public @NonNull Builder setContainerMimeType(@NonNull String containerMimeType) { mContainerMimeType = Objects.requireNonNull(containerMimeType); return this; } /** Adds a sample MIME type stored in the media container. */ public @NonNull Builder addSampleMimeType(@NonNull String mimeType) { mSampleMimeTypes.add(Objects.requireNonNull(mimeType)); return this; } /** * Adds an {@linkplain MediaCodec#getName() media codec name} that was used as part of * decoding/encoding this media item. */ public @NonNull Builder addCodecName(@NonNull String codecName) { mCodecNames.add(Objects.requireNonNull(codecName)); return this; } /** Sets the sample rate of audio, in Hertz. */ public @NonNull Builder setAudioSampleRateHz(@IntRange(from = 0) int audioSampleRateHz) { mAudioSampleRateHz = audioSampleRateHz; return this; } /** Sets the number of audio channels. */ public @NonNull Builder setAudioChannelCount(@IntRange(from = 0) int audioChannelCount) { mAudioChannelCount = audioChannelCount; return this; } /** Sets the number of audio frames in the item, after clipping (if applicable). */ public @NonNull Builder setAudioSampleCount(@IntRange(from = 0) long audioSampleCount) { mAudioSampleCount = audioSampleCount; return this; } /** Sets the video size, in pixels. */ public @NonNull Builder setVideoSize(@NonNull Size videoSize) { mVideoSize = Objects.requireNonNull(videoSize); return this; } /** * Sets the {@link DataSpace} of video frames. * * @param videoDataSpace The data space, returned by {@link DataSpace#pack(int, int, int)}. */ public @NonNull Builder setVideoDataSpace(int videoDataSpace) { mVideoDataSpace = videoDataSpace; return this; } /** Sets the average video frame rate, in frames per second. */ public @NonNull Builder setVideoFrameRate(@FloatRange(from = 0) float videoFrameRate) { mVideoFrameRate = videoFrameRate; return this; } /** Sets the number of video frames, after clipping (if applicable). */ public @NonNull Builder setVideoSampleCount(@IntRange(from = 0) long videoSampleCount) { mVideoSampleCount = videoSampleCount; return this; } /** Builds an instance. */ @NonNull public MediaItemInfo build() { return new MediaItemInfo( mSourceType, mDataTypes, mDurationMillis, mClipDurationMillis, mContainerMimeType, mSampleMimeTypes, mCodecNames, mAudioSampleRateHz, mAudioChannelCount, mAudioSampleCount, mVideoSize, mVideoDataSpace, mVideoFrameRate, mVideoSampleCount); } } @Override @NonNull public String toString() { return "MediaItemInfo { " + "sourceType = " + mSourceType + ", " + "dataTypes = " + mDataTypes + ", " + "durationMillis = " + mDurationMillis + ", " + "clipDurationMillis = " + mClipDurationMillis + ", " + "containerMimeType = " + mContainerMimeType + ", " + "sampleMimeTypes = " + mSampleMimeTypes + ", " + "codecNames = " + mCodecNames + ", " + "audioSampleRateHz = " + mAudioSampleRateHz + ", " + "audioChannelCount = " + mAudioChannelCount + ", " + "audioSampleCount = " + mAudioSampleCount + ", " + "videoSize = " + mVideoSize + ", " + "videoDataSpace = " + mVideoDataSpace + ", " + "videoFrameRate = " + mVideoFrameRate + ", " + "videoSampleCount = " + mVideoSampleCount + " }"; } @Override public boolean equals(@Nullable Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; MediaItemInfo that = (MediaItemInfo) o; return mSourceType == that.mSourceType && mDataTypes == that.mDataTypes && mDurationMillis == that.mDurationMillis && mClipDurationMillis == that.mClipDurationMillis && Objects.equals(mContainerMimeType, that.mContainerMimeType) && mSampleMimeTypes.equals(that.mSampleMimeTypes) && mCodecNames.equals(that.mCodecNames) && mAudioSampleRateHz == that.mAudioSampleRateHz && mAudioChannelCount == that.mAudioChannelCount && mAudioSampleCount == that.mAudioSampleCount && Objects.equals(mVideoSize, that.mVideoSize) && Objects.equals(mVideoDataSpace, that.mVideoDataSpace) && mVideoFrameRate == that.mVideoFrameRate && mVideoSampleCount == that.mVideoSampleCount; } @Override public int hashCode() { return Objects.hash(mSourceType, mDataTypes); } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mSourceType); dest.writeLong(mDataTypes); dest.writeLong(mDurationMillis); dest.writeLong(mClipDurationMillis); dest.writeString(mContainerMimeType); dest.writeStringList(mSampleMimeTypes); dest.writeStringList(mCodecNames); dest.writeInt(mAudioSampleRateHz); dest.writeInt(mAudioChannelCount); dest.writeLong(mAudioSampleCount); dest.writeInt(mVideoSize.getWidth()); dest.writeInt(mVideoSize.getHeight()); dest.writeInt(mVideoDataSpace); dest.writeFloat(mVideoFrameRate); dest.writeLong(mVideoSampleCount); } @Override public int describeContents() { return 0; } private MediaItemInfo(@NonNull Parcel in) { mSourceType = in.readInt(); mDataTypes = in.readLong(); mDurationMillis = in.readLong(); mClipDurationMillis = in.readLong(); mContainerMimeType = in.readString(); mSampleMimeTypes = new ArrayList<>(); in.readStringList(mSampleMimeTypes); mCodecNames = new ArrayList<>(); in.readStringList(mCodecNames); mAudioSampleRateHz = in.readInt(); mAudioChannelCount = in.readInt(); mAudioSampleCount = in.readLong(); int videoSizeWidth = in.readInt(); int videoSizeHeight = in.readInt(); mVideoSize = new Size(videoSizeWidth, videoSizeHeight); mVideoDataSpace = in.readInt(); mVideoFrameRate = in.readFloat(); mVideoSampleCount = in.readLong(); } public static final @NonNull Creator CREATOR = new Creator<>() { @Override public MediaItemInfo[] newArray(int size) { return new MediaItemInfo[size]; } @Override public MediaItemInfo createFromParcel(@NonNull Parcel in) { return new MediaItemInfo(in); } }; }