/* * Copyright (C) 2016 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; import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.Nullable; import com.google.android.exoplayer2.drm.DrmInitData; import com.google.android.exoplayer2.metadata.Metadata; import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.video.ColorInfo; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; /** * Representation of a media format. */ public final class Format implements Parcelable { /** * A value for various fields to indicate that the field's value is unknown or not applicable. */ public static final int NO_VALUE = -1; /** * A value for {@link #subsampleOffsetUs} to indicate that subsample timestamps are relative to * the timestamps of their parent samples. */ public static final long OFFSET_SAMPLE_RELATIVE = Long.MAX_VALUE; /** An identifier for the format, or null if unknown or not applicable. */ public final @Nullable String id; /** The human readable label, or null if unknown or not applicable. */ public final @Nullable String label; /** * The average bandwidth in bits per second, or {@link #NO_VALUE} if unknown or not applicable. */ public final int bitrate; /** Codecs of the format as described in RFC 6381, or null if unknown or not applicable. */ public final @Nullable String codecs; /** Metadata, or null if unknown or not applicable. */ public final @Nullable Metadata metadata; // Container specific. /** The mime type of the container, or null if unknown or not applicable. */ public final @Nullable String containerMimeType; // Elementary stream specific. /** * The mime type of the elementary stream (i.e. the individual samples), or null if unknown or not * applicable. */ public final @Nullable String sampleMimeType; /** * The maximum size of a buffer of data (typically one sample), or {@link #NO_VALUE} if unknown or * not applicable. */ public final int maxInputSize; /** * Initialization data that must be provided to the decoder. Will not be null, but may be empty * if initialization data is not required. */ public final List<byte[]> initializationData; /** DRM initialization data if the stream is protected, or null otherwise. */ public final @Nullable DrmInitData drmInitData; /** * For samples that contain subsamples, this is an offset that should be added to subsample * timestamps. A value of {@link #OFFSET_SAMPLE_RELATIVE} indicates that subsample timestamps are * relative to the timestamps of their parent samples. */ public final long subsampleOffsetUs; // Video specific. /** * The width of the video in pixels, or {@link #NO_VALUE} if unknown or not applicable. */ public final int width; /** * The height of the video in pixels, or {@link #NO_VALUE} if unknown or not applicable. */ public final int height; /** * The frame rate in frames per second, or {@link #NO_VALUE} if unknown or not applicable. */ public final float frameRate; /** * The clockwise rotation that should be applied to the video for it to be rendered in the correct * orientation, or 0 if unknown or not applicable. Only 0, 90, 180 and 270 are supported. */ public final int rotationDegrees; /** The width to height ratio of pixels in the video, or 1.0 if unknown or not applicable. */ public final float pixelWidthHeightRatio; /** * The stereo layout for 360/3D/VR video, or {@link #NO_VALUE} if not applicable. Valid stereo * modes are {@link C#STEREO_MODE_MONO}, {@link C#STEREO_MODE_TOP_BOTTOM}, {@link * C#STEREO_MODE_LEFT_RIGHT}, {@link C#STEREO_MODE_STEREO_MESH}. */ @C.StereoMode public final int stereoMode; /** The projection data for 360/VR video, or null if not applicable. */ public final @Nullable byte[] projectionData; /** The color metadata associated with the video, helps with accurate color reproduction. */ public final @Nullable ColorInfo colorInfo; // Audio specific. /** * The number of audio channels, or {@link #NO_VALUE} if unknown or not applicable. */ public final int channelCount; /** * The audio sampling rate in Hz, or {@link #NO_VALUE} if unknown or not applicable. */ public final int sampleRate; /** * The encoding for PCM audio streams. If {@link #sampleMimeType} is {@link MimeTypes#AUDIO_RAW} * then one of {@link C#ENCODING_PCM_8BIT}, {@link C#ENCODING_PCM_16BIT}, {@link * C#ENCODING_PCM_24BIT}, {@link C#ENCODING_PCM_32BIT}, {@link C#ENCODING_PCM_FLOAT}, {@link * C#ENCODING_PCM_MU_LAW} or {@link C#ENCODING_PCM_A_LAW}. Set to {@link #NO_VALUE} for other * media types. */ public final @C.PcmEncoding int pcmEncoding; /** * The number of frames to trim from the start of the decoded audio stream, or 0 if not * applicable. */ public final int encoderDelay; /** * The number of frames to trim from the end of the decoded audio stream, or 0 if not applicable. */ public final int encoderPadding; // Audio and text specific. /** * Track selection flags. */ @C.SelectionFlags public final int selectionFlags; /** The language, or null if unknown or not applicable. */ public final @Nullable String language; /** * The Accessibility channel, or {@link #NO_VALUE} if not known or applicable. */ public final int accessibilityChannel; // Lazily initialized hashcode. private int hashCode; // Video. @Deprecated public static Format createVideoContainerFormat( @Nullable String id, @Nullable String containerMimeType, String sampleMimeType, String codecs, int bitrate, int width, int height, float frameRate, @Nullable List<byte[]> initializationData, @C.SelectionFlags int selectionFlags) { return createVideoContainerFormat( id, /* label= */ null, containerMimeType, sampleMimeType, codecs, bitrate, width, height, frameRate, initializationData, selectionFlags); } public static Format createVideoContainerFormat( @Nullable String id, @Nullable String label, @Nullable String containerMimeType, String sampleMimeType, String codecs, int bitrate, int width, int height, float frameRate, @Nullable List<byte[]> initializationData, @C.SelectionFlags int selectionFlags) { return new Format( id, label, containerMimeType, sampleMimeType, codecs, bitrate, /* maxInputSize= */ NO_VALUE, width, height, frameRate, /* rotationDegrees= */ NO_VALUE, /* pixelWidthHeightRatio= */ NO_VALUE, /* projectionData= */ null, /* stereoMode= */ NO_VALUE, /* colorInfo= */ null, /* channelCount= */ NO_VALUE, /* sampleRate= */ NO_VALUE, /* pcmEncoding= */ NO_VALUE, /* encoderDelay= */ NO_VALUE, /* encoderPadding= */ NO_VALUE, selectionFlags, /* language= */ null, /* accessibilityChannel= */ NO_VALUE, OFFSET_SAMPLE_RELATIVE, initializationData, /* drmInitData= */ null, /* metadata= */ null); } public static Format createVideoSampleFormat( @Nullable String id, @Nullable String sampleMimeType, @Nullable String codecs, int bitrate, int maxInputSize, int width, int height, float frameRate, @Nullable List<byte[]> initializationData, @Nullable DrmInitData drmInitData) { return createVideoSampleFormat( id, sampleMimeType, codecs, bitrate, maxInputSize, width, height, frameRate, initializationData, /* rotationDegrees= */ NO_VALUE, /* pixelWidthHeightRatio= */ NO_VALUE, drmInitData); } public static Format createVideoSampleFormat( @Nullable String id, @Nullable String sampleMimeType, @Nullable String codecs, int bitrate, int maxInputSize, int width, int height, float frameRate, @Nullable List<byte[]> initializationData, int rotationDegrees, float pixelWidthHeightRatio, @Nullable DrmInitData drmInitData) { return createVideoSampleFormat( id, sampleMimeType, codecs, bitrate, maxInputSize, width, height, frameRate, initializationData, rotationDegrees, pixelWidthHeightRatio, /* projectionData= */ null, /* stereoMode= */ NO_VALUE, /* colorInfo= */ null, drmInitData); } public static Format createVideoSampleFormat( @Nullable String id, @Nullable String sampleMimeType, @Nullable String codecs, int bitrate, int maxInputSize, int width, int height, float frameRate, @Nullable List<byte[]> initializationData, int rotationDegrees, float pixelWidthHeightRatio, byte[] projectionData, @C.StereoMode int stereoMode, @Nullable ColorInfo colorInfo, @Nullable DrmInitData drmInitData) { return new Format( id, /* label= */ null, /* containerMimeType= */ null, sampleMimeType, codecs, bitrate, maxInputSize, width, height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData, stereoMode, colorInfo, /* channelCount= */ NO_VALUE, /* sampleRate= */ NO_VALUE, /* pcmEncoding= */ NO_VALUE, /* encoderDelay= */ NO_VALUE, /* encoderPadding= */ NO_VALUE, /* selectionFlags= */ 0, /* language= */ null, /* accessibilityChannel= */ NO_VALUE, OFFSET_SAMPLE_RELATIVE, initializationData, drmInitData, /* metadata= */ null); } // Audio. @Deprecated public static Format createAudioContainerFormat( @Nullable String id, @Nullable String containerMimeType, @Nullable String sampleMimeType, @Nullable String codecs, int bitrate, int channelCount, int sampleRate, @Nullable List<byte[]> initializationData, @C.SelectionFlags int selectionFlags, @Nullable String language) { return createAudioContainerFormat( id, /* label= */ null, containerMimeType, sampleMimeType, codecs, bitrate, channelCount, sampleRate, initializationData, selectionFlags, language); } public static Format createAudioContainerFormat( @Nullable String id, @Nullable String label, @Nullable String containerMimeType, @Nullable String sampleMimeType, @Nullable String codecs, int bitrate, int channelCount, int sampleRate, @Nullable List<byte[]> initializationData, @C.SelectionFlags int selectionFlags, @Nullable String language) { return new Format( id, label, containerMimeType, sampleMimeType, codecs, bitrate, /* maxInputSize= */ NO_VALUE, /* width= */ NO_VALUE, /* height= */ NO_VALUE, /* frameRate= */ NO_VALUE, /* rotationDegrees= */ NO_VALUE, /* pixelWidthHeightRatio= */ NO_VALUE, /* projectionData= */ null, /* stereoMode= */ NO_VALUE, /* colorInfo= */ null, channelCount, sampleRate, /* pcmEncoding= */ NO_VALUE, /* encoderDelay= */ NO_VALUE, /* encoderPadding= */ NO_VALUE, selectionFlags, language, /* accessibilityChannel= */ NO_VALUE, OFFSET_SAMPLE_RELATIVE, initializationData, /* drmInitData= */ null, /* metadata= */ null); } public static Format createAudioSampleFormat( @Nullable String id, @Nullable String sampleMimeType, @Nullable String codecs, int bitrate, int maxInputSize, int channelCount, int sampleRate, @Nullable List<byte[]> initializationData, @Nullable DrmInitData drmInitData, @C.SelectionFlags int selectionFlags, @Nullable String language) { return createAudioSampleFormat( id, sampleMimeType, codecs, bitrate, maxInputSize, channelCount, sampleRate, /* pcmEncoding= */ NO_VALUE, initializationData, drmInitData, selectionFlags, language); } public static Format createAudioSampleFormat( @Nullable String id, @Nullable String sampleMimeType, @Nullable String codecs, int bitrate, int maxInputSize, int channelCount, int sampleRate, @C.PcmEncoding int pcmEncoding, @Nullable List<byte[]> initializationData, @Nullable DrmInitData drmInitData, @C.SelectionFlags int selectionFlags, @Nullable String language) { return createAudioSampleFormat( id, sampleMimeType, codecs, bitrate, maxInputSize, channelCount, sampleRate, pcmEncoding, /* encoderDelay= */ NO_VALUE, /* encoderPadding= */ NO_VALUE, initializationData, drmInitData, selectionFlags, language, /* metadata= */ null); } public static Format createAudioSampleFormat( @Nullable String id, @Nullable String sampleMimeType, @Nullable String codecs, int bitrate, int maxInputSize, int channelCount, int sampleRate, @C.PcmEncoding int pcmEncoding, int encoderDelay, int encoderPadding, @Nullable List<byte[]> initializationData, @Nullable DrmInitData drmInitData, @C.SelectionFlags int selectionFlags, @Nullable String language, @Nullable Metadata metadata) { return new Format( id, /* label= */ null, /* containerMimeType= */ null, sampleMimeType, codecs, bitrate, maxInputSize, /* width= */ NO_VALUE, /* height= */ NO_VALUE, /* frameRate= */ NO_VALUE, /* rotationDegrees= */ NO_VALUE, /* pixelWidthHeightRatio= */ NO_VALUE, /* projectionData= */ null, /* stereoMode= */ NO_VALUE, /* colorInfo= */ null, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding, selectionFlags, language, /* accessibilityChannel= */ NO_VALUE, OFFSET_SAMPLE_RELATIVE, initializationData, drmInitData, metadata); } // Text. @Deprecated public static Format createTextContainerFormat( @Nullable String id, @Nullable String containerMimeType, @Nullable String sampleMimeType, @Nullable String codecs, int bitrate, @C.SelectionFlags int selectionFlags, @Nullable String language) { return createTextContainerFormat( id, /* label= */ null, containerMimeType, sampleMimeType, codecs, bitrate, selectionFlags, language); } public static Format createTextContainerFormat( @Nullable String id, @Nullable String label, @Nullable String containerMimeType, @Nullable String sampleMimeType, @Nullable String codecs, int bitrate, @C.SelectionFlags int selectionFlags, @Nullable String language) { return createTextContainerFormat( id, label, containerMimeType, sampleMimeType, codecs, bitrate, selectionFlags, language, /* accessibilityChannel= */ NO_VALUE); } public static Format createTextContainerFormat( @Nullable String id, @Nullable String label, @Nullable String containerMimeType, @Nullable String sampleMimeType, @Nullable String codecs, int bitrate, @C.SelectionFlags int selectionFlags, @Nullable String language, int accessibilityChannel) { return new Format( id, label, containerMimeType, sampleMimeType, codecs, bitrate, /* maxInputSize= */ NO_VALUE, /* width= */ NO_VALUE, /* height= */ NO_VALUE, /* frameRate= */ NO_VALUE, /* rotationDegrees= */ NO_VALUE, /* pixelWidthHeightRatio= */ NO_VALUE, /* projectionData= */ null, /* stereoMode= */ NO_VALUE, /* colorInfo= */ null, /* channelCount= */ NO_VALUE, /* sampleRate= */ NO_VALUE, /* pcmEncoding= */ NO_VALUE, /* encoderDelay= */ NO_VALUE, /* encoderPadding= */ NO_VALUE, selectionFlags, language, accessibilityChannel, OFFSET_SAMPLE_RELATIVE, /* initializationData= */ null, /* drmInitData= */ null, /* metadata= */ null); } public static Format createTextSampleFormat( @Nullable String id, String sampleMimeType, @C.SelectionFlags int selectionFlags, @Nullable String language) { return createTextSampleFormat(id, sampleMimeType, selectionFlags, language, null); } public static Format createTextSampleFormat( @Nullable String id, String sampleMimeType, @C.SelectionFlags int selectionFlags, @Nullable String language, @Nullable DrmInitData drmInitData) { return createTextSampleFormat( id, sampleMimeType, /* codecs= */ null, /* bitrate= */ NO_VALUE, selectionFlags, language, NO_VALUE, drmInitData, OFFSET_SAMPLE_RELATIVE, Collections.emptyList()); } public static Format createTextSampleFormat( @Nullable String id, @Nullable String sampleMimeType, @Nullable String codecs, int bitrate, @C.SelectionFlags int selectionFlags, @Nullable String language, int accessibilityChannel, @Nullable DrmInitData drmInitData) { return createTextSampleFormat( id, sampleMimeType, codecs, bitrate, selectionFlags, language, accessibilityChannel, drmInitData, OFFSET_SAMPLE_RELATIVE, Collections.emptyList()); } public static Format createTextSampleFormat( @Nullable String id, @Nullable String sampleMimeType, @Nullable String codecs, int bitrate, @C.SelectionFlags int selectionFlags, @Nullable String language, @Nullable DrmInitData drmInitData, long subsampleOffsetUs) { return createTextSampleFormat( id, sampleMimeType, codecs, bitrate, selectionFlags, language, /* accessibilityChannel= */ NO_VALUE, drmInitData, subsampleOffsetUs, Collections.emptyList()); } public static Format createTextSampleFormat( @Nullable String id, @Nullable String sampleMimeType, @Nullable String codecs, int bitrate, @C.SelectionFlags int selectionFlags, @Nullable String language, int accessibilityChannel, @Nullable DrmInitData drmInitData, long subsampleOffsetUs, List<byte[]> initializationData) { return new Format( id, /* label= */ null, /* containerMimeType= */ null, sampleMimeType, codecs, bitrate, /* maxInputSize= */ NO_VALUE, /* width= */ NO_VALUE, /* height= */ NO_VALUE, /* frameRate= */ NO_VALUE, /* rotationDegrees= */ NO_VALUE, /* pixelWidthHeightRatio= */ NO_VALUE, /* projectionData= */ null, /* stereoMode= */ NO_VALUE, /* colorInfo= */ null, /* channelCount= */ NO_VALUE, /* sampleRate= */ NO_VALUE, /* pcmEncoding= */ NO_VALUE, /* encoderDelay= */ NO_VALUE, /* encoderPadding= */ NO_VALUE, selectionFlags, language, accessibilityChannel, subsampleOffsetUs, initializationData, drmInitData, /* metadata= */ null); } // Image. public static Format createImageSampleFormat( @Nullable String id, @Nullable String sampleMimeType, @Nullable String codecs, int bitrate, @C.SelectionFlags int selectionFlags, @Nullable List<byte[]> initializationData, @Nullable String language, @Nullable DrmInitData drmInitData) { return new Format( id, /* label= */ null, /* containerMimeType= */ null, sampleMimeType, codecs, bitrate, /* maxInputSize= */ NO_VALUE, /* width= */ NO_VALUE, /* height= */ NO_VALUE, /* frameRate= */ NO_VALUE, /* rotationDegrees= */ NO_VALUE, /* pixelWidthHeightRatio= */ NO_VALUE, /* projectionData= */ null, /* stereoMode= */ NO_VALUE, /* colorInfo= */ null, /* channelCount= */ NO_VALUE, /* sampleRate= */ NO_VALUE, /* pcmEncoding= */ NO_VALUE, /* encoderDelay= */ NO_VALUE, /* encoderPadding= */ NO_VALUE, selectionFlags, language, /* accessibilityChannel= */ NO_VALUE, OFFSET_SAMPLE_RELATIVE, initializationData, drmInitData, /* metadata=*/ null); } // Generic. @Deprecated public static Format createContainerFormat( @Nullable String id, @Nullable String containerMimeType, @Nullable String sampleMimeType, @Nullable String codecs, int bitrate, @C.SelectionFlags int selectionFlags, @Nullable String language) { return createContainerFormat( id, /* label= */ null, containerMimeType, sampleMimeType, codecs, bitrate, selectionFlags, language); } public static Format createContainerFormat( @Nullable String id, @Nullable String label, @Nullable String containerMimeType, @Nullable String sampleMimeType, @Nullable String codecs, int bitrate, @C.SelectionFlags int selectionFlags, @Nullable String language) { return new Format( id, label, containerMimeType, sampleMimeType, codecs, bitrate, /* maxInputSize= */ NO_VALUE, /* width= */ NO_VALUE, /* height= */ NO_VALUE, /* frameRate= */ NO_VALUE, /* rotationDegrees= */ NO_VALUE, /* pixelWidthHeightRatio= */ NO_VALUE, /* projectionData= */ null, /* stereoMode= */ NO_VALUE, /* colorInfo= */ null, /* channelCount= */ NO_VALUE, /* sampleRate= */ NO_VALUE, /* pcmEncoding= */ NO_VALUE, /* encoderDelay= */ NO_VALUE, /* encoderPadding= */ NO_VALUE, selectionFlags, language, /* accessibilityChannel= */ NO_VALUE, OFFSET_SAMPLE_RELATIVE, /* initializationData= */ null, /* drmInitData= */ null, /* metadata= */ null); } public static Format createSampleFormat( @Nullable String id, @Nullable String sampleMimeType, long subsampleOffsetUs) { return new Format( id, /* label= */ null, /* containerMimeType= */ null, sampleMimeType, /* codecs= */ null, /* bitrate= */ NO_VALUE, /* maxInputSize= */ NO_VALUE, /* width= */ NO_VALUE, /* height= */ NO_VALUE, /* frameRate= */ NO_VALUE, /* rotationDegrees= */ NO_VALUE, /* pixelWidthHeightRatio= */ NO_VALUE, /* projectionData= */ null, /* stereoMode= */ NO_VALUE, /* colorInfo= */ null, /* channelCount= */ NO_VALUE, /* sampleRate= */ NO_VALUE, /* pcmEncoding= */ NO_VALUE, /* encoderDelay= */ NO_VALUE, /* encoderPadding= */ NO_VALUE, /* selectionFlags= */ 0, /* language= */ null, /* accessibilityChannel= */ NO_VALUE, subsampleOffsetUs, /* initializationData= */ null, /* drmInitData= */ null, /* metadata= */ null); } public static Format createSampleFormat( @Nullable String id, @Nullable String sampleMimeType, @Nullable String codecs, int bitrate, @Nullable DrmInitData drmInitData) { return new Format( id, /* label= */ null, /* containerMimeType= */ null, sampleMimeType, codecs, bitrate, /* maxInputSize= */ NO_VALUE, /* width= */ NO_VALUE, /* height= */ NO_VALUE, /* frameRate= */ NO_VALUE, /* rotationDegrees= */ NO_VALUE, /* pixelWidthHeightRatio= */ NO_VALUE, /* projectionData= */ null, /* stereoMode= */ NO_VALUE, /* colorInfo= */ null, /* channelCount= */ NO_VALUE, /* sampleRate= */ NO_VALUE, /* pcmEncoding= */ NO_VALUE, /* encoderDelay= */ NO_VALUE, /* encoderPadding= */ NO_VALUE, /* selectionFlags= */ 0, /* language= */ null, /* accessibilityChannel= */ NO_VALUE, OFFSET_SAMPLE_RELATIVE, /* initializationData= */ null, drmInitData, /* metadata= */ null); } /* package */ Format( @Nullable String id, @Nullable String label, @Nullable String containerMimeType, @Nullable String sampleMimeType, @Nullable String codecs, int bitrate, int maxInputSize, int width, int height, float frameRate, int rotationDegrees, float pixelWidthHeightRatio, @Nullable byte[] projectionData, @C.StereoMode int stereoMode, @Nullable ColorInfo colorInfo, int channelCount, int sampleRate, @C.PcmEncoding int pcmEncoding, int encoderDelay, int encoderPadding, @C.SelectionFlags int selectionFlags, @Nullable String language, int accessibilityChannel, long subsampleOffsetUs, @Nullable List<byte[]> initializationData, @Nullable DrmInitData drmInitData, @Nullable Metadata metadata) { this.id = id; this.label = label; this.containerMimeType = containerMimeType; this.sampleMimeType = sampleMimeType; this.codecs = codecs; this.bitrate = bitrate; this.maxInputSize = maxInputSize; this.width = width; this.height = height; this.frameRate = frameRate; this.rotationDegrees = rotationDegrees == Format.NO_VALUE ? 0 : rotationDegrees; this.pixelWidthHeightRatio = pixelWidthHeightRatio == Format.NO_VALUE ? 1 : pixelWidthHeightRatio; this.projectionData = projectionData; this.stereoMode = stereoMode; this.colorInfo = colorInfo; this.channelCount = channelCount; this.sampleRate = sampleRate; this.pcmEncoding = pcmEncoding; this.encoderDelay = encoderDelay == Format.NO_VALUE ? 0 : encoderDelay; this.encoderPadding = encoderPadding == Format.NO_VALUE ? 0 : encoderPadding; this.selectionFlags = selectionFlags; this.language = language; this.accessibilityChannel = accessibilityChannel; this.subsampleOffsetUs = subsampleOffsetUs; this.initializationData = initializationData == null ? Collections.emptyList() : initializationData; this.drmInitData = drmInitData; this.metadata = metadata; } @SuppressWarnings("ResourceType") /* package */ Format(Parcel in) { id = in.readString(); label = in.readString(); containerMimeType = in.readString(); sampleMimeType = in.readString(); codecs = in.readString(); bitrate = in.readInt(); maxInputSize = in.readInt(); width = in.readInt(); height = in.readInt(); frameRate = in.readFloat(); rotationDegrees = in.readInt(); pixelWidthHeightRatio = in.readFloat(); boolean hasProjectionData = Util.readBoolean(in); projectionData = hasProjectionData ? in.createByteArray() : null; stereoMode = in.readInt(); colorInfo = in.readParcelable(ColorInfo.class.getClassLoader()); channelCount = in.readInt(); sampleRate = in.readInt(); pcmEncoding = in.readInt(); encoderDelay = in.readInt(); encoderPadding = in.readInt(); selectionFlags = in.readInt(); language = in.readString(); accessibilityChannel = in.readInt(); subsampleOffsetUs = in.readLong(); int initializationDataSize = in.readInt(); initializationData = new ArrayList<>(initializationDataSize); for (int i = 0; i < initializationDataSize; i++) { initializationData.add(in.createByteArray()); } drmInitData = in.readParcelable(DrmInitData.class.getClassLoader()); metadata = in.readParcelable(Metadata.class.getClassLoader()); } public Format copyWithMaxInputSize(int maxInputSize) { return new Format( id, label, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize, width, height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData, stereoMode, colorInfo, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding, selectionFlags, language, accessibilityChannel, subsampleOffsetUs, initializationData, drmInitData, metadata); } public Format copyWithSubsampleOffsetUs(long subsampleOffsetUs) { return new Format( id, label, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize, width, height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData, stereoMode, colorInfo, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding, selectionFlags, language, accessibilityChannel, subsampleOffsetUs, initializationData, drmInitData, metadata); } public Format copyWithContainerInfo( @Nullable String id, @Nullable String label, @Nullable String sampleMimeType, @Nullable String codecs, int bitrate, int width, int height, @C.SelectionFlags int selectionFlags, @Nullable String language) { return new Format( id, label, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize, width, height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData, stereoMode, colorInfo, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding, selectionFlags, language, accessibilityChannel, subsampleOffsetUs, initializationData, drmInitData, metadata); } @SuppressWarnings("ReferenceEquality") public Format copyWithManifestFormatInfo(Format manifestFormat) { if (this == manifestFormat) { // No need to copy from ourselves. return this; } int trackType = MimeTypes.getTrackType(sampleMimeType); // Use manifest value only. String id = manifestFormat.id; // Prefer manifest values, but fill in from sample format if missing. String label = manifestFormat.label != null ? manifestFormat.label : this.label; String language = this.language; if ((trackType == C.TRACK_TYPE_TEXT || trackType == C.TRACK_TYPE_AUDIO) && manifestFormat.language != null) { language = manifestFormat.language; } // Prefer sample format values, but fill in from manifest if missing. int bitrate = this.bitrate == NO_VALUE ? manifestFormat.bitrate : this.bitrate; String codecs = this.codecs; if (codecs == null) { // The manifest format may be muxed, so filter only codecs of this format's type. If we still // have more than one codec then we're unable to uniquely identify which codec to fill in. String codecsOfType = Util.getCodecsOfType(manifestFormat.codecs, trackType); if (Util.splitCodecs(codecsOfType).length == 1) { codecs = codecsOfType; } } float frameRate = this.frameRate; if (frameRate == NO_VALUE && trackType == C.TRACK_TYPE_VIDEO) { frameRate = manifestFormat.frameRate; } // Merge manifest and sample format values. @C.SelectionFlags int selectionFlags = this.selectionFlags | manifestFormat.selectionFlags; DrmInitData drmInitData = DrmInitData.createSessionCreationData(manifestFormat.drmInitData, this.drmInitData); return new Format( id, label, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize, width, height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData, stereoMode, colorInfo, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding, selectionFlags, language, accessibilityChannel, subsampleOffsetUs, initializationData, drmInitData, metadata); } public Format copyWithGaplessInfo(int encoderDelay, int encoderPadding) { return new Format( id, label, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize, width, height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData, stereoMode, colorInfo, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding, selectionFlags, language, accessibilityChannel, subsampleOffsetUs, initializationData, drmInitData, metadata); } public Format copyWithDrmInitData(@Nullable DrmInitData drmInitData) { return new Format( id, label, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize, width, height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData, stereoMode, colorInfo, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding, selectionFlags, language, accessibilityChannel, subsampleOffsetUs, initializationData, drmInitData, metadata); } public Format copyWithMetadata(@Nullable Metadata metadata) { return new Format( id, label, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize, width, height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData, stereoMode, colorInfo, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding, selectionFlags, language, accessibilityChannel, subsampleOffsetUs, initializationData, drmInitData, metadata); } public Format copyWithRotationDegrees(int rotationDegrees) { return new Format( id, label, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize, width, height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData, stereoMode, colorInfo, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding, selectionFlags, language, accessibilityChannel, subsampleOffsetUs, initializationData, drmInitData, metadata); } /** * Returns the number of pixels if this is a video format whose {@link #width} and {@link #height} * are known, or {@link #NO_VALUE} otherwise */ public int getPixelCount() { return width == NO_VALUE || height == NO_VALUE ? NO_VALUE : (width * height); } @Override public String toString() { return "Format(" + id + ", " + label + ", " + containerMimeType + ", " + sampleMimeType + ", " + codecs + ", " + bitrate + ", " + language + ", [" + width + ", " + height + ", " + frameRate + "]" + ", [" + channelCount + ", " + sampleRate + "])"; } @Override public int hashCode() { if (hashCode == 0) { int result = 17; result = 31 * result + (id == null ? 0 : id.hashCode()); result = 31 * result + (containerMimeType == null ? 0 : containerMimeType.hashCode()); result = 31 * result + (sampleMimeType == null ? 0 : sampleMimeType.hashCode()); result = 31 * result + (codecs == null ? 0 : codecs.hashCode()); result = 31 * result + bitrate; result = 31 * result + width; result = 31 * result + height; result = 31 * result + channelCount; result = 31 * result + sampleRate; result = 31 * result + (language == null ? 0 : language.hashCode()); result = 31 * result + accessibilityChannel; result = 31 * result + (drmInitData == null ? 0 : drmInitData.hashCode()); result = 31 * result + (metadata == null ? 0 : metadata.hashCode()); hashCode = result; } return hashCode; } @Override public boolean equals(@Nullable Object obj) { if (this == obj) { return true; } if (obj == null || getClass() != obj.getClass()) { return false; } Format other = (Format) obj; return bitrate == other.bitrate && maxInputSize == other.maxInputSize && width == other.width && height == other.height && frameRate == other.frameRate && rotationDegrees == other.rotationDegrees && pixelWidthHeightRatio == other.pixelWidthHeightRatio && stereoMode == other.stereoMode && channelCount == other.channelCount && sampleRate == other.sampleRate && pcmEncoding == other.pcmEncoding && encoderDelay == other.encoderDelay && encoderPadding == other.encoderPadding && subsampleOffsetUs == other.subsampleOffsetUs && selectionFlags == other.selectionFlags && Util.areEqual(id, other.id) && Util.areEqual(label, other.label) && Util.areEqual(language, other.language) && accessibilityChannel == other.accessibilityChannel && Util.areEqual(containerMimeType, other.containerMimeType) && Util.areEqual(sampleMimeType, other.sampleMimeType) && Util.areEqual(codecs, other.codecs) && Util.areEqual(drmInitData, other.drmInitData) && Util.areEqual(metadata, other.metadata) && Util.areEqual(colorInfo, other.colorInfo) && Arrays.equals(projectionData, other.projectionData) && initializationDataEquals(other); } /** * Returns whether the {@link #initializationData}s belonging to this format and {@code other} are * equal. * * @param other The other format whose {@link #initializationData} is being compared. * @return Whether the {@link #initializationData}s belonging to this format and {@code other} are * equal. */ public boolean initializationDataEquals(Format other) { if (initializationData.size() != other.initializationData.size()) { return false; } for (int i = 0; i < initializationData.size(); i++) { if (!Arrays.equals(initializationData.get(i), other.initializationData.get(i))) { return false; } } return true; } // Utility methods /** * Returns a prettier {@link String} than {@link #toString()}, intended for logging. */ public static String toLogString(Format format) { if (format == null) { return "null"; } StringBuilder builder = new StringBuilder(); builder.append("id=").append(format.id).append(", mimeType=").append(format.sampleMimeType); if (format.bitrate != Format.NO_VALUE) { builder.append(", bitrate=").append(format.bitrate); } if (format.codecs != null) { builder.append(", codecs=").append(format.codecs); } if (format.width != Format.NO_VALUE && format.height != Format.NO_VALUE) { builder.append(", res=").append(format.width).append("x").append(format.height); } if (format.frameRate != Format.NO_VALUE) { builder.append(", fps=").append(format.frameRate); } if (format.channelCount != Format.NO_VALUE) { builder.append(", channels=").append(format.channelCount); } if (format.sampleRate != Format.NO_VALUE) { builder.append(", sample_rate=").append(format.sampleRate); } if (format.language != null) { builder.append(", language=").append(format.language); } if (format.label != null) { builder.append(", label=").append(format.label); } return builder.toString(); } // Parcelable implementation. @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(id); dest.writeString(label); dest.writeString(containerMimeType); dest.writeString(sampleMimeType); dest.writeString(codecs); dest.writeInt(bitrate); dest.writeInt(maxInputSize); dest.writeInt(width); dest.writeInt(height); dest.writeFloat(frameRate); dest.writeInt(rotationDegrees); dest.writeFloat(pixelWidthHeightRatio); Util.writeBoolean(dest, projectionData != null); if (projectionData != null) { dest.writeByteArray(projectionData); } dest.writeInt(stereoMode); dest.writeParcelable(colorInfo, flags); dest.writeInt(channelCount); dest.writeInt(sampleRate); dest.writeInt(pcmEncoding); dest.writeInt(encoderDelay); dest.writeInt(encoderPadding); dest.writeInt(selectionFlags); dest.writeString(language); dest.writeInt(accessibilityChannel); dest.writeLong(subsampleOffsetUs); int initializationDataSize = initializationData.size(); dest.writeInt(initializationDataSize); for (int i = 0; i < initializationDataSize; i++) { dest.writeByteArray(initializationData.get(i)); } dest.writeParcelable(drmInitData, 0); dest.writeParcelable(metadata, 0); } public static final Creator<Format> CREATOR = new Creator<Format>() { @Override public Format createFromParcel(Parcel in) { return new Format(in); } @Override public Format[] newArray(int size) { return new Format[size]; } }; }