Tracks.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. //-----------------------------------------------------------------------------
  4. // Copyright 2015-2021 RenderHeads Ltd. All rights reserved.
  5. //-----------------------------------------------------------------------------
  6. namespace RenderHeads.Media.AVProVideo
  7. {
  8. public enum TrackType
  9. {
  10. Video,
  11. Audio,
  12. Text,
  13. }
  14. public class TrackBase
  15. {
  16. protected TrackBase() { }
  17. internal TrackBase(TrackType trackType, int uid, string name, string language, bool isDefault)
  18. {
  19. TrackType = trackType;
  20. Uid = uid;
  21. Name = name;
  22. Language = language;
  23. IsDefault = isDefault;
  24. DisplayName = CreateDisplayName();
  25. }
  26. // The UID is unique to the media
  27. internal int Uid { get; private set; }
  28. public TrackType TrackType { get; private set; }
  29. public string DisplayName { get; private set; }
  30. // Optional
  31. public string Name { get; private set; }
  32. // Optional
  33. public string Language { get; private set; }
  34. // Optional
  35. public bool IsDefault { get; private set; }
  36. protected string CreateDisplayName()
  37. {
  38. string result;
  39. if (!string.IsNullOrEmpty(Name))
  40. {
  41. result = Name;
  42. }
  43. else
  44. {
  45. result = "Track " + Uid.ToString();
  46. }
  47. if (!string.IsNullOrEmpty(Language))
  48. {
  49. result = string.Format("{0} ({1})", result, Language);
  50. }
  51. return result;
  52. }
  53. }
  54. public abstract class TrackCollection : IEnumerable
  55. {
  56. public virtual TrackType TrackType { get; private set; }
  57. public abstract int Count { get; }
  58. public abstract IEnumerator GetEnumerator();
  59. internal abstract void Clear();
  60. internal abstract void Add(TrackBase track);
  61. internal abstract bool HasActiveTrack();
  62. internal abstract bool IsActiveTrack(TrackBase track);
  63. internal abstract void SetActiveTrack(TrackBase track);
  64. internal abstract void SetFirstTrackActive();
  65. }
  66. public class TrackCollection<T> : TrackCollection where T : TrackBase
  67. {
  68. internal TrackCollection() {}
  69. public override IEnumerator GetEnumerator()
  70. {
  71. return _tracks.GetEnumerator();
  72. }
  73. public T this[int index]
  74. {
  75. get
  76. {
  77. return _tracks[index];
  78. }
  79. }
  80. internal T ActiveTrack { get; set; }
  81. internal override bool HasActiveTrack() { return ActiveTrack != null; }
  82. internal override bool IsActiveTrack(TrackBase track)
  83. {
  84. return (ActiveTrack == track);
  85. }
  86. internal override void Clear()
  87. {
  88. _tracks.Clear();
  89. ActiveTrack = null;
  90. }
  91. internal override void Add(TrackBase track)
  92. {
  93. _tracks.Add(track as T);
  94. }
  95. internal override void SetActiveTrack(TrackBase track)
  96. {
  97. ActiveTrack = track as T;
  98. }
  99. internal override void SetFirstTrackActive()
  100. {
  101. if (_tracks.Count > 0)
  102. {
  103. ActiveTrack = _tracks[0];
  104. }
  105. }
  106. public override int Count { get{ return _tracks.Count; } }
  107. internal List<T> _tracks = new List<T>(4);
  108. }
  109. public class VideoTracks : TrackCollection<VideoTrack>
  110. {
  111. public override TrackType TrackType { get { return TrackType.Video; } }
  112. }
  113. public class AudioTracks : TrackCollection<AudioTrack>
  114. {
  115. public override TrackType TrackType { get { return TrackType.Audio; } }
  116. }
  117. public class TextTracks : TrackCollection<TextTrack>
  118. {
  119. public override TrackType TrackType { get { return TrackType.Text; } }
  120. }
  121. public class VideoTrack : TrackBase
  122. {
  123. private VideoTrack() { }
  124. internal VideoTrack(int uid, string name, string language, bool isDefault)
  125. : base(TrackType.Video, uid, name, language, isDefault) { }
  126. // Optional
  127. public int Bitrate { get; set; }
  128. }
  129. public class AudioTrack : TrackBase
  130. {
  131. private AudioTrack() { }
  132. internal AudioTrack(int uid, string name, string language, bool isDefault)
  133. : base(TrackType.Audio, uid, name, language, isDefault) { }
  134. // Optional
  135. public int Bitrate { get; private set; }
  136. // Optional
  137. public int ChannelCount { get; private set; }
  138. }
  139. public class TextTrack : TrackBase
  140. {
  141. private TextTrack() { }
  142. internal TextTrack(int uid, string name, string language, bool isDefault)
  143. : base(TrackType.Text, uid, name, language, isDefault) { }
  144. }
  145. public interface IVideoTracks
  146. {
  147. VideoTracks GetVideoTracks();
  148. VideoTrack GetActiveVideoTrack();
  149. void SetActiveVideoTrack(VideoTrack track);
  150. }
  151. public interface IAudioTracks
  152. {
  153. AudioTracks GetAudioTracks();
  154. AudioTrack GetActiveAudioTrack();
  155. void SetActiveAudioTrack(AudioTrack track);
  156. }
  157. public interface ITextTracks
  158. {
  159. TextTracks GetTextTracks();
  160. TextTrack GetActiveTextTrack();
  161. void SetActiveTextTrack(TextTrack track);
  162. TextCue GetCurrentTextCue();
  163. }
  164. public partial class BaseMediaPlayer : IVideoTracks, IAudioTracks, ITextTracks
  165. {
  166. protected VideoTracks _videoTracks = new VideoTracks();
  167. protected AudioTracks _audioTracks = new AudioTracks();
  168. protected TextTracks _textTracks = new TextTracks();
  169. protected TrackCollection[] _trackCollections;
  170. public VideoTracks GetVideoTracks() { return _videoTracks; }
  171. public AudioTracks GetAudioTracks() { return _audioTracks; }
  172. public TextTracks GetTextTracks() { return _textTracks; }
  173. public VideoTrack GetActiveVideoTrack() { return _videoTracks.ActiveTrack; }
  174. public AudioTrack GetActiveAudioTrack() { return _audioTracks.ActiveTrack; }
  175. public TextTrack GetActiveTextTrack() { return _textTracks.ActiveTrack; }
  176. public void SetActiveVideoTrack(VideoTrack track) { if (track != null) SetActiveTrack(_videoTracks, track); }
  177. public void SetActiveAudioTrack(AudioTrack track) { if (track != null) SetActiveTrack(_audioTracks, track); }
  178. public void SetActiveTextTrack(TextTrack track) { SetActiveTrack(_textTracks, track); }
  179. internal abstract bool InternalIsChangedTracks(TrackType trackType);
  180. internal abstract int InternalGetTrackCount(TrackType trackType);
  181. internal abstract bool InternalSetActiveTrack(TrackType trackType, int trackUid);
  182. internal abstract TrackBase InternalGetTrackInfo(TrackType trackType, int trackIndex, ref bool isActiveTrack);
  183. private void InitTracks()
  184. {
  185. _trackCollections = new TrackCollection[3] { _videoTracks, _audioTracks, _textTracks };
  186. }
  187. protected void UpdateTracks()
  188. {
  189. foreach (TrackCollection trackCollection in _trackCollections)
  190. {
  191. if (InternalIsChangedTracks(trackCollection.TrackType))
  192. {
  193. PopulateTrackCollection(trackCollection);
  194. }
  195. }
  196. }
  197. private void PopulateTrackCollection(TrackCollection collection)
  198. {
  199. collection.Clear();
  200. int trackCount = InternalGetTrackCount(collection.TrackType);
  201. for (int i = 0; i < trackCount; i++)
  202. {
  203. bool isActiveTrack = false;
  204. TrackBase track = InternalGetTrackInfo(collection.TrackType, i, ref isActiveTrack);
  205. if (track != null)
  206. {
  207. collection.Add(track);
  208. if (isActiveTrack)
  209. {
  210. collection.SetActiveTrack(track);
  211. }
  212. }
  213. else
  214. {
  215. UnityEngine.Debug.LogWarning(string.Format("[AVProVideo] Failed to enumerate {0} track {1} ", collection.TrackType, i));
  216. }
  217. }
  218. }
  219. private void SetActiveTrack(TrackCollection collection, TrackBase track)
  220. {
  221. // Check if this is already the active track
  222. if (collection.IsActiveTrack(track)) return;
  223. // Convert from TextTrack to uid
  224. int trackUid = -1;
  225. if (track != null)
  226. {
  227. trackUid = track.Uid;
  228. }
  229. // Set track based on uid (-1 is no active track)
  230. // NOTE: TrackType is pulled from collection as track may be null
  231. if (InternalSetActiveTrack(collection.TrackType, trackUid))
  232. {
  233. collection.SetActiveTrack(track);
  234. switch (collection.TrackType)
  235. {
  236. case TrackType.Text:
  237. UpdateTextCue(force:true);
  238. break;
  239. }
  240. }
  241. }
  242. }
  243. }