VideoService.cs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. using MediaBrowser.Common.IO;
  2. using MediaBrowser.Common.Net;
  3. using MediaBrowser.Controller.Configuration;
  4. using MediaBrowser.Controller.Devices;
  5. using MediaBrowser.Controller.Diagnostics;
  6. using MediaBrowser.Controller.Dlna;
  7. using MediaBrowser.Controller.Drawing;
  8. using MediaBrowser.Controller.Library;
  9. using MediaBrowser.Controller.LiveTv;
  10. using MediaBrowser.Controller.MediaEncoding;
  11. using MediaBrowser.Model.IO;
  12. using ServiceStack;
  13. using System;
  14. using System.IO;
  15. namespace MediaBrowser.Api.Playback.Progressive
  16. {
  17. /// <summary>
  18. /// Class GetAudioStream
  19. /// </summary>
  20. [Route("/Videos/{Id}/stream.ts", "GET")]
  21. [Route("/Videos/{Id}/stream.webm", "GET")]
  22. [Route("/Videos/{Id}/stream.asf", "GET")]
  23. [Route("/Videos/{Id}/stream.wmv", "GET")]
  24. [Route("/Videos/{Id}/stream.ogv", "GET")]
  25. [Route("/Videos/{Id}/stream.mp4", "GET")]
  26. [Route("/Videos/{Id}/stream.m4v", "GET")]
  27. [Route("/Videos/{Id}/stream.mkv", "GET")]
  28. [Route("/Videos/{Id}/stream.mpeg", "GET")]
  29. [Route("/Videos/{Id}/stream.mpg", "GET")]
  30. [Route("/Videos/{Id}/stream.avi", "GET")]
  31. [Route("/Videos/{Id}/stream.m2ts", "GET")]
  32. [Route("/Videos/{Id}/stream.3gp", "GET")]
  33. [Route("/Videos/{Id}/stream.wmv", "GET")]
  34. [Route("/Videos/{Id}/stream.wtv", "GET")]
  35. [Route("/Videos/{Id}/stream.mov", "GET")]
  36. [Route("/Videos/{Id}/stream", "GET")]
  37. [Route("/Videos/{Id}/stream.ts", "HEAD")]
  38. [Route("/Videos/{Id}/stream.webm", "HEAD")]
  39. [Route("/Videos/{Id}/stream.asf", "HEAD")]
  40. [Route("/Videos/{Id}/stream.wmv", "HEAD")]
  41. [Route("/Videos/{Id}/stream.ogv", "HEAD")]
  42. [Route("/Videos/{Id}/stream.mp4", "HEAD")]
  43. [Route("/Videos/{Id}/stream.m4v", "HEAD")]
  44. [Route("/Videos/{Id}/stream.mkv", "HEAD")]
  45. [Route("/Videos/{Id}/stream.mpeg", "HEAD")]
  46. [Route("/Videos/{Id}/stream.mpg", "HEAD")]
  47. [Route("/Videos/{Id}/stream.avi", "HEAD")]
  48. [Route("/Videos/{Id}/stream.3gp", "HEAD")]
  49. [Route("/Videos/{Id}/stream.wmv", "HEAD")]
  50. [Route("/Videos/{Id}/stream.wtv", "HEAD")]
  51. [Route("/Videos/{Id}/stream.m2ts", "HEAD")]
  52. [Route("/Videos/{Id}/stream.mov", "HEAD")]
  53. [Route("/Videos/{Id}/stream", "HEAD")]
  54. [Api(Description = "Gets a video stream")]
  55. public class GetVideoStream : VideoStreamRequest
  56. {
  57. }
  58. /// <summary>
  59. /// Class VideoService
  60. /// </summary>
  61. public class VideoService : BaseProgressiveStreamingService
  62. {
  63. public VideoService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IProcessManager processManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, subtitleEncoder, deviceManager, processManager, mediaSourceManager, zipClient, imageProcessor, httpClient)
  64. {
  65. }
  66. /// <summary>
  67. /// Gets the specified request.
  68. /// </summary>
  69. /// <param name="request">The request.</param>
  70. /// <returns>System.Object.</returns>
  71. public object Get(GetVideoStream request)
  72. {
  73. return ProcessRequest(request, false);
  74. }
  75. /// <summary>
  76. /// Heads the specified request.
  77. /// </summary>
  78. /// <param name="request">The request.</param>
  79. /// <returns>System.Object.</returns>
  80. public object Head(GetVideoStream request)
  81. {
  82. return ProcessRequest(request, true);
  83. }
  84. protected override string GetCommandLineArguments(string outputPath, string transcodingJobId, StreamState state, bool isEncoding)
  85. {
  86. // Get the output codec name
  87. var videoCodec = state.OutputVideoCodec;
  88. var format = string.Empty;
  89. var keyFrame = string.Empty;
  90. if (string.Equals(Path.GetExtension(outputPath), ".mp4", StringComparison.OrdinalIgnoreCase))
  91. {
  92. // Comparison: https://github.com/jansmolders86/mediacenterjs/blob/master/lib/transcoding/desktop.js
  93. format = " -f mp4 -movflags frag_keyframe+empty_moov";
  94. }
  95. var threads = GetNumberOfThreads(state, string.Equals(videoCodec, "libvpx", StringComparison.OrdinalIgnoreCase));
  96. var inputModifier = GetInputModifier(state);
  97. return string.Format("{0} {1}{2} {3} {4} -map_metadata -1 -threads {5} {6}{7} -y \"{8}\"",
  98. inputModifier,
  99. GetInputArgument(transcodingJobId, state),
  100. keyFrame,
  101. GetMapArgs(state),
  102. GetVideoArguments(state, videoCodec),
  103. threads,
  104. GetAudioArguments(state),
  105. format,
  106. outputPath
  107. ).Trim();
  108. }
  109. /// <summary>
  110. /// Gets video arguments to pass to ffmpeg
  111. /// </summary>
  112. /// <param name="state">The state.</param>
  113. /// <param name="codec">The video codec.</param>
  114. /// <returns>System.String.</returns>
  115. private string GetVideoArguments(StreamState state, string codec)
  116. {
  117. var args = "-codec:v:0 " + codec;
  118. if (state.EnableMpegtsM2TsMode)
  119. {
  120. args += " -mpegts_m2ts_mode 1";
  121. }
  122. // See if we can save come cpu cycles by avoiding encoding
  123. if (codec.Equals("copy", StringComparison.OrdinalIgnoreCase))
  124. {
  125. return state.VideoStream != null && IsH264(state.VideoStream) && string.Equals(state.OutputContainer, "ts", StringComparison.OrdinalIgnoreCase) ?
  126. args + " -bsf:v h264_mp4toannexb" :
  127. args;
  128. }
  129. var keyFrameArg = string.Format(" -force_key_frames expr:gte(t,n_forced*{0})",
  130. 5.ToString(UsCulture));
  131. args += keyFrameArg;
  132. var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream;
  133. // Add resolution params, if specified
  134. if (!hasGraphicalSubs)
  135. {
  136. args += GetOutputSizeParam(state, codec);
  137. }
  138. var qualityParam = GetVideoQualityParam(state, codec, false);
  139. if (!string.IsNullOrEmpty(qualityParam))
  140. {
  141. args += " " + qualityParam.Trim();
  142. }
  143. // This is for internal graphical subs
  144. if (hasGraphicalSubs)
  145. {
  146. args += GetGraphicalSubtitleParam(state, codec);
  147. }
  148. return args;
  149. }
  150. /// <summary>
  151. /// Gets audio arguments to pass to ffmpeg
  152. /// </summary>
  153. /// <param name="state">The state.</param>
  154. /// <returns>System.String.</returns>
  155. private string GetAudioArguments(StreamState state)
  156. {
  157. // If the video doesn't have an audio stream, return a default.
  158. if (state.AudioStream == null && state.VideoStream != null)
  159. {
  160. return string.Empty;
  161. }
  162. // Get the output codec name
  163. var codec = state.OutputAudioCodec;
  164. var args = "-codec:a:0 " + codec;
  165. if (codec.Equals("copy", StringComparison.OrdinalIgnoreCase))
  166. {
  167. return args;
  168. }
  169. // Add the number of audio channels
  170. var channels = state.OutputAudioChannels;
  171. if (channels.HasValue)
  172. {
  173. args += " -ac " + channels.Value;
  174. }
  175. var bitrate = state.OutputAudioBitrate;
  176. if (bitrate.HasValue)
  177. {
  178. args += " -ab " + bitrate.Value.ToString(UsCulture);
  179. }
  180. args += " " + GetAudioFilterParam(state, false);
  181. return args;
  182. }
  183. }
  184. }