BdInfoExaminer.cs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Globalization;
  4. using System.Linq;
  5. using BDInfo;
  6. using Jellyfin.Extensions;
  7. using MediaBrowser.Model.Entities;
  8. using MediaBrowser.Model.IO;
  9. using MediaBrowser.Model.MediaInfo;
  10. namespace MediaBrowser.MediaEncoding.BdInfo;
  11. /// <summary>
  12. /// Class BdInfoExaminer.
  13. /// </summary>
  14. public class BdInfoExaminer : IBlurayExaminer
  15. {
  16. private readonly IFileSystem _fileSystem;
  17. /// <summary>
  18. /// Initializes a new instance of the <see cref="BdInfoExaminer" /> class.
  19. /// </summary>
  20. /// <param name="fileSystem">The filesystem.</param>
  21. public BdInfoExaminer(IFileSystem fileSystem)
  22. {
  23. _fileSystem = fileSystem;
  24. }
  25. /// <summary>
  26. /// Gets the disc info.
  27. /// </summary>
  28. /// <param name="path">The path.</param>
  29. /// <returns>BlurayDiscInfo.</returns>
  30. public BlurayDiscInfo GetDiscInfo(string path)
  31. {
  32. if (string.IsNullOrWhiteSpace(path))
  33. {
  34. throw new ArgumentNullException(nameof(path));
  35. }
  36. var bdrom = new BDROM(BdInfoDirectoryInfo.FromFileSystemPath(_fileSystem, path));
  37. bdrom.Scan();
  38. // Get the longest playlist
  39. var playlist = bdrom.PlaylistFiles.Values.OrderByDescending(p => p.TotalLength).FirstOrDefault(p => p.IsValid);
  40. var outputStream = new BlurayDiscInfo
  41. {
  42. MediaStreams = Array.Empty<MediaStream>()
  43. };
  44. if (playlist is null)
  45. {
  46. return outputStream;
  47. }
  48. outputStream.Chapters = playlist.Chapters.ToArray();
  49. outputStream.RunTimeTicks = TimeSpan.FromSeconds(playlist.TotalLength).Ticks;
  50. var sortedStreams = playlist.SortedStreams;
  51. var mediaStreams = new List<MediaStream>(sortedStreams.Count);
  52. for (int i = 0; i < sortedStreams.Count; i++)
  53. {
  54. var stream = sortedStreams[i];
  55. switch (stream)
  56. {
  57. case TSVideoStream videoStream:
  58. AddVideoStream(mediaStreams, i, videoStream);
  59. break;
  60. case TSAudioStream audioStream:
  61. AddAudioStream(mediaStreams, i, audioStream);
  62. break;
  63. case TSTextStream:
  64. case TSGraphicsStream:
  65. AddSubtitleStream(mediaStreams, i, stream);
  66. break;
  67. }
  68. }
  69. outputStream.MediaStreams = mediaStreams.ToArray();
  70. outputStream.PlaylistName = playlist.Name;
  71. if (playlist.StreamClips is not null && playlist.StreamClips.Count > 0)
  72. {
  73. // Get the files in the playlist
  74. outputStream.Files = playlist.StreamClips.Select(i => i.StreamFile.FileInfo.FullName).ToArray();
  75. }
  76. return outputStream;
  77. }
  78. /// <summary>
  79. /// Adds the video stream.
  80. /// </summary>
  81. /// <param name="streams">The streams.</param>
  82. /// <param name="index">The stream index.</param>
  83. /// <param name="videoStream">The video stream.</param>
  84. private void AddVideoStream(List<MediaStream> streams, int index, TSVideoStream videoStream)
  85. {
  86. var mediaStream = new MediaStream
  87. {
  88. BitRate = Convert.ToInt32(videoStream.BitRate),
  89. Width = videoStream.Width,
  90. Height = videoStream.Height,
  91. Codec = GetNormalizedCodec(videoStream),
  92. IsInterlaced = videoStream.IsInterlaced,
  93. Type = MediaStreamType.Video,
  94. Index = index
  95. };
  96. if (videoStream.FrameRateDenominator > 0)
  97. {
  98. float frameRateEnumerator = videoStream.FrameRateEnumerator;
  99. float frameRateDenominator = videoStream.FrameRateDenominator;
  100. mediaStream.AverageFrameRate = mediaStream.RealFrameRate = frameRateEnumerator / frameRateDenominator;
  101. }
  102. streams.Add(mediaStream);
  103. }
  104. /// <summary>
  105. /// Adds the audio stream.
  106. /// </summary>
  107. /// <param name="streams">The streams.</param>
  108. /// <param name="index">The stream index.</param>
  109. /// <param name="audioStream">The audio stream.</param>
  110. private void AddAudioStream(List<MediaStream> streams, int index, TSAudioStream audioStream)
  111. {
  112. var stream = new MediaStream
  113. {
  114. Codec = GetNormalizedCodec(audioStream),
  115. Language = audioStream.LanguageCode,
  116. ChannelLayout = string.Format(CultureInfo.InvariantCulture, "{0:D}.{1:D}", audioStream.ChannelCount, audioStream.LFE),
  117. Channels = audioStream.ChannelCount + audioStream.LFE,
  118. SampleRate = audioStream.SampleRate,
  119. Type = MediaStreamType.Audio,
  120. Index = index
  121. };
  122. var bitrate = Convert.ToInt32(audioStream.BitRate);
  123. if (bitrate > 0)
  124. {
  125. stream.BitRate = bitrate;
  126. }
  127. streams.Add(stream);
  128. }
  129. /// <summary>
  130. /// Adds the subtitle stream.
  131. /// </summary>
  132. /// <param name="streams">The streams.</param>
  133. /// <param name="index">The stream index.</param>
  134. /// <param name="stream">The stream.</param>
  135. private void AddSubtitleStream(List<MediaStream> streams, int index, TSStream stream)
  136. {
  137. streams.Add(new MediaStream
  138. {
  139. Language = stream.LanguageCode,
  140. Codec = GetNormalizedCodec(stream),
  141. Type = MediaStreamType.Subtitle,
  142. Index = index
  143. });
  144. }
  145. private string GetNormalizedCodec(TSStream stream)
  146. => stream.StreamType switch
  147. {
  148. TSStreamType.MPEG1_VIDEO => "mpeg1video",
  149. TSStreamType.MPEG2_VIDEO => "mpeg2video",
  150. TSStreamType.VC1_VIDEO => "vc1",
  151. TSStreamType.AC3_PLUS_AUDIO or TSStreamType.AC3_PLUS_SECONDARY_AUDIO => "eac3",
  152. TSStreamType.DTS_AUDIO or TSStreamType.DTS_HD_AUDIO or TSStreamType.DTS_HD_MASTER_AUDIO or TSStreamType.DTS_HD_SECONDARY_AUDIO => "dts",
  153. TSStreamType.PRESENTATION_GRAPHICS => "pgssub",
  154. _ => stream.CodecShortName
  155. };
  156. }