InternalEncodingTaskFactory.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. using MediaBrowser.Controller.Configuration;
  2. using MediaBrowser.Controller.Dlna;
  3. using MediaBrowser.Controller.Entities;
  4. using MediaBrowser.Controller.Library;
  5. using MediaBrowser.Controller.LiveTv;
  6. using MediaBrowser.Controller.MediaEncoding;
  7. using MediaBrowser.Controller.Persistence;
  8. using MediaBrowser.Model.Configuration;
  9. using MediaBrowser.Model.Entities;
  10. using MediaBrowser.Model.LiveTv;
  11. using System;
  12. using System.Collections.Generic;
  13. using System.IO;
  14. using System.Linq;
  15. using System.Threading;
  16. using System.Threading.Tasks;
  17. namespace MediaBrowser.MediaEncoding.Encoder
  18. {
  19. public class InternalEncodingTaskFactory
  20. {
  21. private readonly ILibraryManager _libraryManager;
  22. private readonly ILiveTvManager _liveTvManager;
  23. private readonly IItemRepository _itemRepo;
  24. private readonly IServerConfigurationManager _config;
  25. public InternalEncodingTaskFactory(ILibraryManager libraryManager, ILiveTvManager liveTvManager, IItemRepository itemRepo, IServerConfigurationManager config)
  26. {
  27. _libraryManager = libraryManager;
  28. _liveTvManager = liveTvManager;
  29. _itemRepo = itemRepo;
  30. _config = config;
  31. }
  32. public async Task<InternalEncodingTask> Create(EncodingOptions request, CancellationToken cancellationToken)
  33. {
  34. ValidateInput(request);
  35. var state = new InternalEncodingTask
  36. {
  37. Request = request
  38. };
  39. var item = string.IsNullOrEmpty(request.MediaSourceId) ?
  40. _libraryManager.GetItemById(new Guid(request.ItemId)) :
  41. _libraryManager.GetItemById(new Guid(request.MediaSourceId));
  42. if (item is ILiveTvRecording)
  43. {
  44. var recording = await _liveTvManager.GetInternalRecording(request.ItemId, cancellationToken).ConfigureAwait(false);
  45. if (string.Equals(recording.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase))
  46. {
  47. state.InputVideoType = VideoType.VideoFile;
  48. }
  49. var path = recording.RecordingInfo.Path;
  50. var mediaUrl = recording.RecordingInfo.Url;
  51. if (string.IsNullOrWhiteSpace(path) && string.IsNullOrWhiteSpace(mediaUrl))
  52. {
  53. var streamInfo = await _liveTvManager.GetRecordingStream(request.ItemId, cancellationToken).ConfigureAwait(false);
  54. state.LiveTvStreamId = streamInfo.Id;
  55. path = streamInfo.Path;
  56. mediaUrl = streamInfo.Url;
  57. }
  58. if (!string.IsNullOrEmpty(path) && File.Exists(path))
  59. {
  60. state.MediaPath = path;
  61. state.IsInputRemote = false;
  62. }
  63. else if (!string.IsNullOrEmpty(mediaUrl))
  64. {
  65. state.MediaPath = mediaUrl;
  66. state.IsInputRemote = true;
  67. }
  68. state.InputRunTimeTicks = recording.RunTimeTicks;
  69. if (recording.RecordingInfo.Status == RecordingStatus.InProgress && !state.IsInputRemote)
  70. {
  71. await Task.Delay(1000, cancellationToken).ConfigureAwait(false);
  72. }
  73. state.ReadInputAtNativeFramerate = recording.RecordingInfo.Status == RecordingStatus.InProgress;
  74. state.AudioSync = "1000";
  75. state.DeInterlace = true;
  76. state.InputVideoSync = "-1";
  77. state.InputAudioSync = "1";
  78. }
  79. else if (item is LiveTvChannel)
  80. {
  81. var channel = _liveTvManager.GetInternalChannel(request.ItemId);
  82. if (string.Equals(channel.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase))
  83. {
  84. state.InputVideoType = VideoType.VideoFile;
  85. }
  86. var streamInfo = await _liveTvManager.GetChannelStream(request.ItemId, cancellationToken).ConfigureAwait(false);
  87. state.LiveTvStreamId = streamInfo.Id;
  88. if (!string.IsNullOrEmpty(streamInfo.Path) && File.Exists(streamInfo.Path))
  89. {
  90. state.MediaPath = streamInfo.Path;
  91. state.IsInputRemote = false;
  92. await Task.Delay(1000, cancellationToken).ConfigureAwait(false);
  93. }
  94. else if (!string.IsNullOrEmpty(streamInfo.Url))
  95. {
  96. state.MediaPath = streamInfo.Url;
  97. state.IsInputRemote = true;
  98. }
  99. state.ReadInputAtNativeFramerate = true;
  100. state.AudioSync = "1000";
  101. state.DeInterlace = true;
  102. state.InputVideoSync = "-1";
  103. state.InputAudioSync = "1";
  104. }
  105. else
  106. {
  107. state.MediaPath = item.Path;
  108. state.IsInputRemote = item.LocationType == LocationType.Remote;
  109. var video = item as Video;
  110. if (video != null)
  111. {
  112. state.InputVideoType = video.VideoType;
  113. state.IsoType = video.IsoType;
  114. state.StreamFileNames = video.PlayableStreamFileNames.ToList();
  115. }
  116. state.InputRunTimeTicks = item.RunTimeTicks;
  117. }
  118. var videoRequest = request as VideoEncodingOptions;
  119. var mediaStreams = _itemRepo.GetMediaStreams(new MediaStreamQuery
  120. {
  121. ItemId = item.Id
  122. }).ToList();
  123. if (videoRequest != null)
  124. {
  125. state.VideoStream = GetMediaStream(mediaStreams, videoRequest.VideoStreamIndex, MediaStreamType.Video);
  126. state.SubtitleStream = GetMediaStream(mediaStreams, videoRequest.SubtitleStreamIndex, MediaStreamType.Subtitle, false);
  127. state.AudioStream = GetMediaStream(mediaStreams, videoRequest.AudioStreamIndex, MediaStreamType.Audio);
  128. if (state.VideoStream != null && state.VideoStream.IsInterlaced)
  129. {
  130. state.DeInterlace = true;
  131. }
  132. }
  133. else
  134. {
  135. state.AudioStream = GetMediaStream(mediaStreams, null, MediaStreamType.Audio, true);
  136. }
  137. state.HasMediaStreams = mediaStreams.Count > 0;
  138. state.SegmentLength = state.ReadInputAtNativeFramerate ? 5 : 10;
  139. state.HlsListSize = state.ReadInputAtNativeFramerate ? 100 : 1440;
  140. state.QualitySetting = GetQualitySetting();
  141. ApplyDeviceProfileSettings(state);
  142. return state;
  143. }
  144. private void ValidateInput(EncodingOptions request)
  145. {
  146. if (string.IsNullOrWhiteSpace(request.ItemId))
  147. {
  148. throw new ArgumentException("ItemId is required.");
  149. }
  150. if (string.IsNullOrWhiteSpace(request.OutputPath))
  151. {
  152. throw new ArgumentException("OutputPath is required.");
  153. }
  154. if (string.IsNullOrWhiteSpace(request.Container))
  155. {
  156. throw new ArgumentException("Container is required.");
  157. }
  158. if (string.IsNullOrWhiteSpace(request.AudioCodec))
  159. {
  160. throw new ArgumentException("AudioCodec is required.");
  161. }
  162. var videoRequest = request as VideoEncodingOptions;
  163. if (videoRequest == null)
  164. {
  165. return;
  166. }
  167. }
  168. /// <summary>
  169. /// Determines which stream will be used for playback
  170. /// </summary>
  171. /// <param name="allStream">All stream.</param>
  172. /// <param name="desiredIndex">Index of the desired.</param>
  173. /// <param name="type">The type.</param>
  174. /// <param name="returnFirstIfNoIndex">if set to <c>true</c> [return first if no index].</param>
  175. /// <returns>MediaStream.</returns>
  176. private MediaStream GetMediaStream(IEnumerable<MediaStream> allStream, int? desiredIndex, MediaStreamType type, bool returnFirstIfNoIndex = true)
  177. {
  178. var streams = allStream.Where(s => s.Type == type).OrderBy(i => i.Index).ToList();
  179. if (desiredIndex.HasValue)
  180. {
  181. var stream = streams.FirstOrDefault(s => s.Index == desiredIndex.Value);
  182. if (stream != null)
  183. {
  184. return stream;
  185. }
  186. }
  187. if (returnFirstIfNoIndex && type == MediaStreamType.Audio)
  188. {
  189. return streams.FirstOrDefault(i => i.Channels.HasValue && i.Channels.Value > 0) ??
  190. streams.FirstOrDefault();
  191. }
  192. // Just return the first one
  193. return returnFirstIfNoIndex ? streams.FirstOrDefault() : null;
  194. }
  195. private void ApplyDeviceProfileSettings(InternalEncodingTask state)
  196. {
  197. var profile = state.Request.DeviceProfile;
  198. if (profile == null)
  199. {
  200. // Don't use settings from the default profile.
  201. // Only use a specific profile if it was requested.
  202. return;
  203. }
  204. var container = state.Request.Container;
  205. var audioCodec = state.Request.AudioCodec;
  206. if (string.Equals(audioCodec, "copy", StringComparison.OrdinalIgnoreCase) && state.AudioStream != null)
  207. {
  208. audioCodec = state.AudioStream.Codec;
  209. }
  210. var videoCodec = state.VideoRequest == null ? null : state.VideoRequest.VideoCodec;
  211. if (string.Equals(videoCodec, "copy", StringComparison.OrdinalIgnoreCase) && state.VideoStream != null)
  212. {
  213. videoCodec = state.VideoStream.Codec;
  214. }
  215. //var mediaProfile = state.VideoRequest == null ?
  216. // profile.GetAudioMediaProfile(container, audioCodec) :
  217. // profile.GetVideoMediaProfile(container, audioCodec, videoCodec, state.AudioStream, state.VideoStream);
  218. //if (mediaProfile != null)
  219. //{
  220. // state.MimeType = mediaProfile.MimeType;
  221. // state.OrgPn = mediaProfile.OrgPn;
  222. //}
  223. //var transcodingProfile = state.VideoRequest == null ?
  224. // profile.GetAudioTranscodingProfile(container, audioCodec) :
  225. // profile.GetVideoTranscodingProfile(container, audioCodec, videoCodec);
  226. //if (transcodingProfile != null)
  227. //{
  228. // //state.EstimateContentLength = transcodingProfile.EstimateContentLength;
  229. // state.EnableMpegtsM2TsMode = transcodingProfile.EnableMpegtsM2TsMode;
  230. // //state.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo;
  231. // if (state.VideoRequest != null && string.IsNullOrWhiteSpace(state.VideoRequest.VideoProfile))
  232. // {
  233. // state.VideoRequest.VideoProfile = transcodingProfile.VideoProfile;
  234. // }
  235. //}
  236. }
  237. private EncodingQuality GetQualitySetting()
  238. {
  239. var quality = _config.Configuration.MediaEncodingQuality;
  240. if (quality == EncodingQuality.Auto)
  241. {
  242. var cpuCount = Environment.ProcessorCount;
  243. if (cpuCount >= 4)
  244. {
  245. //return EncodingQuality.HighQuality;
  246. }
  247. return EncodingQuality.HighSpeed;
  248. }
  249. return quality;
  250. }
  251. }
  252. }