VideoCodecInfo.cs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using Unity.WebRTC;
  5. namespace Unity.RenderStreaming
  6. {
  7. /// <summary>
  8. ///
  9. /// </summary>
  10. [Serializable]
  11. public class VideoCodecInfo : IEquatable<VideoCodecInfo>
  12. {
  13. static readonly string KeyCodecImplementation = "implementation_name";
  14. [SerializeField]
  15. private string m_MimeType;
  16. [SerializeField]
  17. private string m_SdpFmtpLine;
  18. readonly Dictionary<string, string> m_parameters = new Dictionary<string, string>();
  19. /// <summary>
  20. ///
  21. /// </summary>
  22. public string name { get { return m_MimeType.GetCodecName(); } }
  23. /// <summary>
  24. ///
  25. /// </summary>
  26. public string mimeType { get { return m_MimeType; } }
  27. /// <summary>
  28. ///
  29. /// </summary>
  30. public string codecImplementation { get { return parameters[KeyCodecImplementation]; } }
  31. /// <summary>
  32. ///
  33. /// </summary>
  34. public string sdpFmtpLine { get { return m_SdpFmtpLine; } }
  35. /// <summary>
  36. ///
  37. /// </summary>
  38. /// <param name="other"></param>
  39. /// <returns></returns>
  40. public bool Equals(VideoCodecInfo other)
  41. {
  42. if (other == null)
  43. return false;
  44. return this.mimeType == other.mimeType
  45. && this.sdpFmtpLine == other.sdpFmtpLine;
  46. }
  47. /// <summary>
  48. ///
  49. /// </summary>
  50. /// <param name="obj"></param>
  51. /// <returns></returns>
  52. public override bool Equals(object obj)
  53. {
  54. return obj is VideoCodecInfo ? Equals((VideoCodecInfo)obj) : base.Equals(obj);
  55. }
  56. /// <summary>
  57. ///
  58. /// </summary>
  59. /// <returns></returns>
  60. public override int GetHashCode()
  61. {
  62. return new { mimeType, sdpFmtpLine }.GetHashCode();
  63. }
  64. /// <summary>
  65. ///
  66. /// </summary>
  67. /// <param name="left"></param>
  68. /// <param name="right"></param>
  69. /// <returns></returns>
  70. public static bool operator ==(VideoCodecInfo left, VideoCodecInfo right)
  71. {
  72. if (ReferenceEquals(left, null))
  73. {
  74. return ReferenceEquals(left, null);
  75. }
  76. else
  77. {
  78. return left.Equals(right);
  79. }
  80. }
  81. /// <summary>
  82. ///
  83. /// </summary>
  84. /// <param name="left"></param>
  85. /// <param name="right"></param>
  86. /// <returns></returns>
  87. public static bool operator !=(VideoCodecInfo left, VideoCodecInfo right)
  88. {
  89. return !(left == right);
  90. }
  91. protected Dictionary<string, string> parameters
  92. {
  93. get
  94. {
  95. if (m_parameters != null)
  96. return m_parameters;
  97. if (string.IsNullOrEmpty(m_SdpFmtpLine))
  98. return null;
  99. string[] subs = m_SdpFmtpLine.Split(';');
  100. foreach (string sub in subs)
  101. {
  102. string[] pair = sub.Split('=');
  103. m_parameters.Add(pair[0], pair[1]);
  104. }
  105. return m_parameters;
  106. }
  107. }
  108. static internal VideoCodecInfo Create(RTCRtpCodecCapability caps)
  109. {
  110. switch(caps.mimeType)
  111. {
  112. case "video/H264":
  113. return new H264CodecInfo(caps);
  114. case "video/VP9":
  115. return new VP9CodecInfo(caps);
  116. case "video/AV1":
  117. return new AV1CodecInfo(caps);
  118. default:
  119. return new VideoCodecInfo(caps);
  120. }
  121. }
  122. internal bool Equals(RTCRtpCodecCapability other)
  123. {
  124. if (other == null)
  125. return false;
  126. return this.mimeType == other.mimeType
  127. && this.sdpFmtpLine == other.sdpFmtpLine;
  128. }
  129. internal VideoCodecInfo(RTCRtpCodecCapability caps)
  130. {
  131. m_MimeType = caps.mimeType;
  132. m_SdpFmtpLine = caps.sdpFmtpLine;
  133. string[] subs = m_SdpFmtpLine.Split(';');
  134. foreach(string sub in subs)
  135. {
  136. string[] pair = sub.Split('=');
  137. parameters.Add(pair[0], pair[1]);
  138. }
  139. }
  140. }
  141. /// <summary>
  142. ///
  143. /// </summary>
  144. public enum VP9Profile
  145. {
  146. /// <summary>
  147. ///
  148. /// </summary>
  149. Profile0 = 0,
  150. /// <summary>
  151. ///
  152. /// </summary>
  153. Profile1 = 1,
  154. /// <summary>
  155. ///
  156. /// </summary>
  157. Profile2 = 2,
  158. /// <summary>
  159. ///
  160. /// </summary>
  161. Profile3 = 3,
  162. }
  163. /// <summary>
  164. ///
  165. /// </summary>
  166. public class VP9CodecInfo : VideoCodecInfo
  167. {
  168. const string KeyProfileId = "profile-id";
  169. /// <summary>
  170. ///
  171. /// </summary>
  172. public VP9Profile? profile
  173. {
  174. get
  175. {
  176. if(parameters.TryGetValue(KeyProfileId, out var value))
  177. {
  178. return (VP9Profile)Enum.ToObject(typeof(VP9Profile), Convert.ToInt32(value));
  179. }
  180. return null;
  181. }
  182. }
  183. internal VP9CodecInfo(RTCRtpCodecCapability caps) : base(caps)
  184. {
  185. }
  186. }
  187. /// <summary>
  188. ///
  189. /// </summary>
  190. public enum H264Profile
  191. {
  192. /// <summary>
  193. /// Constrained Baseline Profile.
  194. /// </summary>
  195. ConstrainedBaseline = 0x42e0,
  196. /// <summary>
  197. /// Baseline Profile.
  198. /// </summary>
  199. Baseline = 0x4200,
  200. /// <summary>
  201. /// Main Profile.
  202. /// </summary>
  203. Main = 0x4d00,
  204. /// <summary>
  205. /// Constrained High Profile.
  206. /// </summary>
  207. ConstrainedHigh = 0x640c,
  208. /// <summary>
  209. /// High Profile.
  210. /// </summary>
  211. High = 0x6400,
  212. }
  213. /// <summary>
  214. ///
  215. /// </summary>
  216. public class H264CodecInfo : VideoCodecInfo
  217. {
  218. const string KeyProfileLevelId = "profile-level-id";
  219. /// <summary>
  220. ///
  221. /// </summary>
  222. public H264Profile profile
  223. {
  224. get { return (H264Profile)Enum.ToObject(typeof(H264Profile), Convert.ToInt32(parameters[KeyProfileLevelId], 16) >> 8); }
  225. }
  226. /// <summary>
  227. ///
  228. /// </summary>
  229. public int level { get { return Convert.ToInt32(parameters[KeyProfileLevelId], 16) & 0xFF; } }
  230. internal H264CodecInfo(RTCRtpCodecCapability caps) : base(caps)
  231. {
  232. }
  233. }
  234. /// <summary>
  235. ///
  236. /// </summary>
  237. public enum AV1Profile
  238. {
  239. /// <summary>
  240. ///
  241. /// </summary>
  242. Profile0 = 0,
  243. /// <summary>
  244. ///
  245. /// </summary>
  246. Profile1 = 1,
  247. /// <summary>
  248. ///
  249. /// </summary>
  250. Profile2 = 2,
  251. }
  252. /// <summary>
  253. ///
  254. /// </summary>
  255. public class AV1CodecInfo : VideoCodecInfo
  256. {
  257. const string KeyProfile = "profile";
  258. /// <summary>
  259. ///
  260. /// </summary>
  261. public AV1Profile profile
  262. {
  263. get
  264. {
  265. if (parameters.TryGetValue(KeyProfile, out var value))
  266. {
  267. return (AV1Profile)Enum.ToObject(typeof(AV1Profile), Convert.ToInt32(value));
  268. }
  269. // If the parameter is not present, it MUST be inferred to be 0 (“Main” profile).
  270. // https://aomediacodec.github.io/av1-rtp-spec/#72-sdp-parameters
  271. return AV1Profile.Profile0;
  272. }
  273. }
  274. internal AV1CodecInfo(RTCRtpCodecCapability caps) : base(caps)
  275. {
  276. }
  277. }
  278. }