using System; using System.Collections.Generic; using Unity.WebRTC; using UnityEngine; namespace Unity.RenderStreaming { /// /// Represents information about a video codec, including its MIME type, SDP format parameters. /// [Serializable] public class VideoCodecInfo : IEquatable { static readonly string KeyCodecImplementation = "implementation_name"; [SerializeField] private string m_MimeType; [SerializeField] private string m_SdpFmtpLine; readonly Dictionary m_parameters = new Dictionary(); /// /// Gets the name of the video codec. /// public string name { get { return m_MimeType.GetCodecName(); } } /// /// Gets the MIME type of the video codec. /// public string mimeType { get { return m_MimeType; } } /// /// Gets the codec implementation name. /// public string codecImplementation { get { return parameters[KeyCodecImplementation]; } } /// /// Gets the SDP format parameters line. /// public string sdpFmtpLine { get { return m_SdpFmtpLine; } } /// /// Determines whether the specified is equal to the current . /// /// /// /// /// /// /// The to compare with the current . /// True if the specified is equal to the current ; otherwise, false. public bool Equals(VideoCodecInfo other) { if (other == null) return false; return this.mimeType == other.mimeType && this.sdpFmtpLine == other.sdpFmtpLine; } /// /// Determines whether the specified object is equal to the current . /// /// The object to compare with the current . /// True if the specified object is equal to the current ; otherwise, false. public override bool Equals(object obj) { return obj is VideoCodecInfo ? Equals((VideoCodecInfo)obj) : base.Equals(obj); } /// /// Returns a hash code for the . /// The hash code is based on the MIME type and SDP format parameters line properties. /// /// A hash code for the current . public override int GetHashCode() { return new { mimeType, sdpFmtpLine }.GetHashCode(); } /// /// Determines whether two specified instances of are equal. /// /// The first to compare. /// The second to compare. /// True if the two instances are equal; otherwise, false. public static bool operator ==(VideoCodecInfo left, VideoCodecInfo right) { if (ReferenceEquals(left, null)) { return ReferenceEquals(left, null); } else { return left.Equals(right); } } /// /// Determines whether two specified instances of are not equal. /// /// The first to compare. /// The second to compare. /// True if the two instances are not equal; otherwise, false. public static bool operator !=(VideoCodecInfo left, VideoCodecInfo right) { return !(left == right); } protected Dictionary parameters { get { if (m_parameters != null) return m_parameters; if (string.IsNullOrEmpty(m_SdpFmtpLine)) return null; string[] subs = m_SdpFmtpLine.Split(';'); foreach (string sub in subs) { string[] pair = sub.Split('='); m_parameters.Add(pair[0], pair[1]); } return m_parameters; } } static internal VideoCodecInfo Create(RTCRtpCodecCapability caps) { switch (caps.mimeType) { case "video/H264": return new H264CodecInfo(caps); case "video/VP9": return new VP9CodecInfo(caps); case "video/AV1": return new AV1CodecInfo(caps); default: return new VideoCodecInfo(caps); } } internal bool Equals(RTCRtpCodecCapability other) { if (other == null) return false; return this.mimeType == other.mimeType && this.sdpFmtpLine == other.sdpFmtpLine; } internal VideoCodecInfo(RTCRtpCodecCapability caps) { m_MimeType = caps.mimeType; m_SdpFmtpLine = caps.sdpFmtpLine; string[] subs = m_SdpFmtpLine.Split(';'); foreach (string sub in subs) { string[] pair = sub.Split('='); parameters.Add(pair[0], pair[1]); } } } /// /// Represents the profiles for the VP9 video codec. /// public enum VP9Profile { /// /// Profile 0. /// Profile0 = 0, /// /// Profile 1. /// Profile1 = 1, /// /// Profile 2. /// Profile2 = 2, /// /// Profile 3. /// Profile3 = 3, } /// /// Represents information about the VP9 video codec. /// public class VP9CodecInfo : VideoCodecInfo { const string KeyProfileId = "profile-id"; /// /// Gets the profile of the VP9 video codec. /// public VP9Profile? profile { get { if (parameters.TryGetValue(KeyProfileId, out var value)) { return (VP9Profile)Enum.ToObject(typeof(VP9Profile), Convert.ToInt32(value)); } return null; } } internal VP9CodecInfo(RTCRtpCodecCapability caps) : base(caps) { } } /// /// Represents the profiles for the H264 video codec. /// public enum H264Profile { /// /// Constrained Baseline Profile. /// ConstrainedBaseline = 0x42e0, /// /// Baseline Profile. /// Baseline = 0x4200, /// /// Main Profile. /// Main = 0x4d00, /// /// Constrained High Profile. /// ConstrainedHigh = 0x640c, /// /// High Profile. /// High = 0x6400, } /// /// Represents information about the H264 video codec. /// public class H264CodecInfo : VideoCodecInfo { const string KeyProfileLevelId = "profile-level-id"; /// /// Gets the profile of the H264 video codec. /// public H264Profile profile { get { return (H264Profile)Enum.ToObject(typeof(H264Profile), Convert.ToInt32(parameters[KeyProfileLevelId], 16) >> 8); } } /// /// Gets the level of the H264 video codec. /// public int level { get { return Convert.ToInt32(parameters[KeyProfileLevelId], 16) & 0xFF; } } internal H264CodecInfo(RTCRtpCodecCapability caps) : base(caps) { } } /// /// Represents the profiles for the AV1 video codec. /// public enum AV1Profile { /// /// Profile 0. /// Profile0 = 0, /// /// Profile 1. /// Profile1 = 1, /// /// Profile 2. /// Profile2 = 2, } /// /// Represents information about the AV1 video codec. /// public class AV1CodecInfo : VideoCodecInfo { const string KeyProfile = "profile"; /// /// Gets the profile of the AV1 video codec. /// public AV1Profile profile { get { if (parameters.TryGetValue(KeyProfile, out var value)) { return (AV1Profile)Enum.ToObject(typeof(AV1Profile), Convert.ToInt32(value)); } // If the parameter is not present, it MUST be inferred to be 0 (“Main” profile). // https://aomediacodec.github.io/av1-rtp-spec/#72-sdp-parameters return AV1Profile.Profile0; } } internal AV1CodecInfo(RTCRtpCodecCapability caps) : base(caps) { } } }