EncodingUtils.cs 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. using MediaBrowser.Controller.MediaEncoding;
  2. using MediaBrowser.Model.Configuration;
  3. using MediaBrowser.Model.Entities;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Globalization;
  7. using System.Linq;
  8. namespace MediaBrowser.MediaEncoding.Encoder
  9. {
  10. public static class EncodingUtils
  11. {
  12. private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
  13. public static string GetInputArgument(List<string> inputFiles, bool isRemote)
  14. {
  15. if (isRemote)
  16. {
  17. return GetHttpInputArgument(inputFiles);
  18. }
  19. return GetConcatInputArgument(inputFiles);
  20. }
  21. /// <summary>
  22. /// Gets the concat input argument.
  23. /// </summary>
  24. /// <param name="inputFiles">The input files.</param>
  25. /// <returns>System.String.</returns>
  26. private static string GetConcatInputArgument(List<string> inputFiles)
  27. {
  28. // Get all streams
  29. // If there's more than one we'll need to use the concat command
  30. if (inputFiles.Count > 1)
  31. {
  32. var files = string.Join("|", inputFiles);
  33. return string.Format("concat:\"{0}\"", files);
  34. }
  35. // Determine the input path for video files
  36. return GetFileInputArgument(inputFiles[0]);
  37. }
  38. /// <summary>
  39. /// Gets the file input argument.
  40. /// </summary>
  41. /// <param name="path">The path.</param>
  42. /// <returns>System.String.</returns>
  43. private static string GetFileInputArgument(string path)
  44. {
  45. return string.Format("file:\"{0}\"", path);
  46. }
  47. /// <summary>
  48. /// Gets the HTTP input argument.
  49. /// </summary>
  50. /// <param name="inputFiles">The input files.</param>
  51. /// <returns>System.String.</returns>
  52. private static string GetHttpInputArgument(IEnumerable<string> inputFiles)
  53. {
  54. var url = inputFiles.First();
  55. return string.Format("\"{0}\"", url);
  56. }
  57. public static string GetAudioInputModifier(InternalEncodingTask options)
  58. {
  59. return GetCommonInputModifier(options);
  60. }
  61. public static string GetInputModifier(InternalEncodingTask options)
  62. {
  63. var inputModifier = GetCommonInputModifier(options);
  64. //if (state.VideoRequest != null)
  65. //{
  66. // inputModifier += " -fflags genpts";
  67. //}
  68. //if (!string.IsNullOrEmpty(state.InputVideoCodec))
  69. //{
  70. // inputModifier += " -vcodec " + state.InputVideoCodec;
  71. //}
  72. //if (!string.IsNullOrEmpty(state.InputVideoSync))
  73. //{
  74. // inputModifier += " -vsync " + state.InputVideoSync;
  75. //}
  76. return inputModifier;
  77. }
  78. private static string GetCommonInputModifier(InternalEncodingTask options)
  79. {
  80. var inputModifier = string.Empty;
  81. if (options.EnableDebugLogging)
  82. {
  83. inputModifier += "-loglevel debug";
  84. }
  85. var probeSize = GetProbeSizeArgument(options.InputVideoType.HasValue && options.InputVideoType.Value == VideoType.Dvd);
  86. inputModifier += " " + probeSize;
  87. inputModifier = inputModifier.Trim();
  88. if (!string.IsNullOrWhiteSpace(options.UserAgent))
  89. {
  90. inputModifier += " -user-agent \"" + options.UserAgent + "\"";
  91. }
  92. inputModifier += " " + GetFastSeekValue(options.Request);
  93. inputModifier = inputModifier.Trim();
  94. if (!string.IsNullOrEmpty(options.InputFormat))
  95. {
  96. inputModifier += " -f " + options.InputFormat;
  97. }
  98. if (!string.IsNullOrEmpty(options.InputAudioCodec))
  99. {
  100. inputModifier += " -acodec " + options.InputAudioCodec;
  101. }
  102. if (!string.IsNullOrEmpty(options.InputAudioSync))
  103. {
  104. inputModifier += " -async " + options.InputAudioSync;
  105. }
  106. if (options.ReadInputAtNativeFramerate)
  107. {
  108. inputModifier += " -re";
  109. }
  110. return inputModifier;
  111. }
  112. private static string GetFastSeekValue(EncodingOptions options)
  113. {
  114. var time = options.StartTimeTicks;
  115. if (time.HasValue)
  116. {
  117. var seconds = TimeSpan.FromTicks(time.Value).TotalSeconds;
  118. if (seconds > 0)
  119. {
  120. return string.Format("-ss {0}", seconds.ToString(UsCulture));
  121. }
  122. }
  123. return string.Empty;
  124. }
  125. public static string GetProbeSizeArgument(bool isDvd)
  126. {
  127. return isDvd ? "-probesize 1G -analyzeduration 200M" : string.Empty;
  128. }
  129. public static int? GetAudioBitrateParam(InternalEncodingTask task)
  130. {
  131. if (task.Request.AudioBitRate.HasValue)
  132. {
  133. // Make sure we don't request a bitrate higher than the source
  134. var currentBitrate = task.AudioStream == null ? task.Request.AudioBitRate.Value : task.AudioStream.BitRate ?? task.Request.AudioBitRate.Value;
  135. return Math.Min(currentBitrate, task.Request.AudioBitRate.Value);
  136. }
  137. return null;
  138. }
  139. /// <summary>
  140. /// Gets the number of audio channels to specify on the command line
  141. /// </summary>
  142. /// <param name="request">The request.</param>
  143. /// <param name="audioStream">The audio stream.</param>
  144. /// <returns>System.Nullable{System.Int32}.</returns>
  145. public static int? GetNumAudioChannelsParam(EncodingOptions request, MediaStream audioStream)
  146. {
  147. if (audioStream != null)
  148. {
  149. if (audioStream.Channels > 2 && string.Equals(request.AudioCodec, "wma", StringComparison.OrdinalIgnoreCase))
  150. {
  151. // wmav2 currently only supports two channel output
  152. return 2;
  153. }
  154. }
  155. if (request.MaxAudioChannels.HasValue)
  156. {
  157. if (audioStream != null && audioStream.Channels.HasValue)
  158. {
  159. return Math.Min(request.MaxAudioChannels.Value, audioStream.Channels.Value);
  160. }
  161. return request.MaxAudioChannels.Value;
  162. }
  163. return request.AudioChannels;
  164. }
  165. public static int GetNumberOfThreads(InternalEncodingTask state, bool isWebm)
  166. {
  167. // Use more when this is true. -re will keep cpu usage under control
  168. if (state.ReadInputAtNativeFramerate)
  169. {
  170. if (isWebm)
  171. {
  172. return Math.Max(Environment.ProcessorCount - 1, 1);
  173. }
  174. return 0;
  175. }
  176. // Webm: http://www.webmproject.org/docs/encoder-parameters/
  177. // The decoder will usually automatically use an appropriate number of threads according to how many cores are available but it can only use multiple threads
  178. // for the coefficient data if the encoder selected --token-parts > 0 at encode time.
  179. switch (state.QualitySetting)
  180. {
  181. case EncodingQuality.HighSpeed:
  182. return 2;
  183. case EncodingQuality.HighQuality:
  184. return 2;
  185. case EncodingQuality.MaxQuality:
  186. return isWebm ? 2 : 0;
  187. default:
  188. throw new Exception("Unrecognized MediaEncodingQuality value.");
  189. }
  190. }
  191. }
  192. }