using System;
using System.Collections.Generic;
using UnityEngine;
using Unity.WebRTC;
namespace Unity.RenderStreaming
{
///
///
///
[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();
///
///
///
public string name { get { return m_MimeType.GetCodecName(); } }
///
///
///
public string mimeType { get { return m_MimeType; } }
///
///
///
public string codecImplementation { get { return parameters[KeyCodecImplementation]; } }
///
///
///
public string sdpFmtpLine { get { return m_SdpFmtpLine; } }
///
///
///
///
///
public bool Equals(VideoCodecInfo other)
{
if (other == null)
return false;
return this.mimeType == other.mimeType
&& this.sdpFmtpLine == other.sdpFmtpLine;
}
///
///
///
///
///
public override bool Equals(object obj)
{
return obj is VideoCodecInfo ? Equals((VideoCodecInfo)obj) : base.Equals(obj);
}
///
///
///
///
public override int GetHashCode()
{
return new { mimeType, sdpFmtpLine }.GetHashCode();
}
///
///
///
///
///
///
public static bool operator ==(VideoCodecInfo left, VideoCodecInfo right)
{
if (ReferenceEquals(left, null))
{
return ReferenceEquals(left, null);
}
else
{
return left.Equals(right);
}
}
///
///
///
///
///
///
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]);
}
}
}
///
///
///
public enum VP9Profile
{
///
///
///
Profile0 = 0,
///
///
///
Profile1 = 1,
///
///
///
Profile2 = 2,
///
///
///
Profile3 = 3,
}
///
///
///
public class VP9CodecInfo : VideoCodecInfo
{
const string KeyProfileId = "profile-id";
///
///
///
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)
{
}
}
///
///
///
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,
}
///
///
///
public class H264CodecInfo : VideoCodecInfo
{
const string KeyProfileLevelId = "profile-level-id";
///
///
///
public H264Profile profile
{
get { return (H264Profile)Enum.ToObject(typeof(H264Profile), Convert.ToInt32(parameters[KeyProfileLevelId], 16) >> 8); }
}
///
///
///
public int level { get { return Convert.ToInt32(parameters[KeyProfileLevelId], 16) & 0xFF; } }
internal H264CodecInfo(RTCRtpCodecCapability caps) : base(caps)
{
}
}
///
///
///
public enum AV1Profile
{
///
///
///
Profile0 = 0,
///
///
///
Profile1 = 1,
///
///
///
Profile2 = 2,
}
///
///
///
public class AV1CodecInfo : VideoCodecInfo
{
const string KeyProfile = "profile";
///
///
///
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)
{
}
}
}