diff options
| author | Luke Pulverenti <luke.pulverenti@gmail.com> | 2014-02-20 11:37:41 -0500 |
|---|---|---|
| committer | Luke Pulverenti <luke.pulverenti@gmail.com> | 2014-02-20 11:37:41 -0500 |
| commit | 888b8d619aec031f57cfd03410ccda52edcca958 (patch) | |
| tree | 143080937fb8811d107c610507a15376d6761955 /MediaBrowser.Controller/MediaInfo | |
| parent | 160d14208809a13791e34530a3758b079d6b9638 (diff) | |
added encoding manager interface
Diffstat (limited to 'MediaBrowser.Controller/MediaInfo')
| -rw-r--r-- | MediaBrowser.Controller/MediaInfo/FFMpegManager.cs | 297 | ||||
| -rw-r--r-- | MediaBrowser.Controller/MediaInfo/IMediaEncoder.cs | 108 | ||||
| -rw-r--r-- | MediaBrowser.Controller/MediaInfo/InternalMediaInfoResult.cs | 311 | ||||
| -rw-r--r-- | MediaBrowser.Controller/MediaInfo/MediaEncoderHelpers.cs | 365 |
4 files changed, 0 insertions, 1081 deletions
diff --git a/MediaBrowser.Controller/MediaInfo/FFMpegManager.cs b/MediaBrowser.Controller/MediaInfo/FFMpegManager.cs deleted file mode 100644 index e3604eb0e2..0000000000 --- a/MediaBrowser.Controller/MediaInfo/FFMpegManager.cs +++ /dev/null @@ -1,297 +0,0 @@ -using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Movies; -using MediaBrowser.Controller.Entities.TV; -using MediaBrowser.Controller.Persistence; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Logging; -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -namespace MediaBrowser.Controller.MediaInfo -{ - /// <summary> - /// Class FFMpegManager - /// </summary> - public class FFMpegManager - { - private readonly IServerConfigurationManager _config; - private readonly IMediaEncoder _encoder; - private readonly ILogger _logger; - private readonly IItemRepository _itemRepo; - - private readonly IFileSystem _fileSystem; - - public static FFMpegManager Instance { get; private set; } - - /// <summary> - /// Initializes a new instance of the <see cref="FFMpegManager" /> class. - /// </summary> - /// <param name="encoder">The encoder.</param> - /// <param name="logger">The logger.</param> - /// <param name="itemRepo">The item repo.</param> - /// <exception cref="System.ArgumentNullException">zipClient</exception> - public FFMpegManager(IMediaEncoder encoder, ILogger logger, IItemRepository itemRepo, IFileSystem fileSystem, IServerConfigurationManager config) - { - _encoder = encoder; - _logger = logger; - _itemRepo = itemRepo; - _fileSystem = fileSystem; - _config = config; - - // TODO: Remove this static instance - Instance = this; - } - - /// <summary> - /// Gets the chapter images data path. - /// </summary> - /// <value>The chapter images data path.</value> - public string ChapterImagesPath - { - get - { - return Path.Combine(_config.ApplicationPaths.DataPath, "chapter-images"); - } - } - - /// <summary> - /// Gets the subtitle cache path. - /// </summary> - /// <value>The subtitle cache path.</value> - private string SubtitleCachePath - { - get - { - return Path.Combine(_config.ApplicationPaths.CachePath, "subtitles"); - } - } - - /// <summary> - /// Determines whether [is eligible for chapter image extraction] [the specified video]. - /// </summary> - /// <param name="video">The video.</param> - /// <returns><c>true</c> if [is eligible for chapter image extraction] [the specified video]; otherwise, <c>false</c>.</returns> - private bool IsEligibleForChapterImageExtraction(Video video) - { - if (video is Movie) - { - if (!_config.Configuration.EnableMovieChapterImageExtraction) - { - return false; - } - } - else if (video is Episode) - { - if (!_config.Configuration.EnableEpisodeChapterImageExtraction) - { - return false; - } - } - else - { - if (!_config.Configuration.EnableOtherVideoChapterImageExtraction) - { - return false; - } - } - - // Can't extract images if there are no video streams - return video.DefaultVideoStreamIndex.HasValue; - } - - /// <summary> - /// The first chapter ticks - /// </summary> - private static readonly long FirstChapterTicks = TimeSpan.FromSeconds(15).Ticks; - - /// <summary> - /// Extracts the chapter images. - /// </summary> - /// <param name="video">The video.</param> - /// <param name="chapters">The chapters.</param> - /// <param name="extractImages">if set to <c>true</c> [extract images].</param> - /// <param name="saveChapters">if set to <c>true</c> [save chapters].</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> - /// <exception cref="System.ArgumentNullException"></exception> - public async Task<bool> PopulateChapterImages(Video video, List<ChapterInfo> chapters, bool extractImages, bool saveChapters, CancellationToken cancellationToken) - { - if (!IsEligibleForChapterImageExtraction(video)) - { - extractImages = false; - } - - var success = true; - var changesMade = false; - - var runtimeTicks = video.RunTimeTicks ?? 0; - - var currentImages = GetSavedChapterImages(video); - - foreach (var chapter in chapters) - { - if (chapter.StartPositionTicks >= runtimeTicks) - { - _logger.Info("Stopping chapter extraction for {0} because a chapter was found with a position greater than the runtime.", video.Name); - break; - } - - var path = GetChapterImagePath(video, chapter.StartPositionTicks); - - if (!currentImages.Contains(path, StringComparer.OrdinalIgnoreCase)) - { - if (extractImages) - { - if (video.VideoType == VideoType.HdDvd || video.VideoType == VideoType.Iso) - { - continue; - } - - if (video.VideoType == VideoType.BluRay) - { - // Can only extract reliably on single file blurays - if (video.PlayableStreamFileNames == null || video.PlayableStreamFileNames.Count != 1) - { - continue; - } - } - - // Add some time for the first chapter to make sure we don't end up with a black image - var time = chapter.StartPositionTicks == 0 ? TimeSpan.FromTicks(Math.Min(FirstChapterTicks, video.RunTimeTicks ?? 0)) : TimeSpan.FromTicks(chapter.StartPositionTicks); - - InputType type; - - var inputPath = MediaEncoderHelpers.GetInputArgument(video.Path, false, video.VideoType, video.IsoType, null, video.PlayableStreamFileNames, out type); - - try - { - var parentPath = Path.GetDirectoryName(path); - - Directory.CreateDirectory(parentPath); - - using (var stream = await _encoder.ExtractImage(inputPath, type, false, video.Video3DFormat, time, cancellationToken).ConfigureAwait(false)) - { - using (var fileStream = _fileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, true)) - { - await stream.CopyToAsync(fileStream).ConfigureAwait(false); - } - } - - chapter.ImagePath = path; - changesMade = true; - } - catch - { - success = false; - break; - } - } - else if (!string.IsNullOrEmpty(chapter.ImagePath)) - { - chapter.ImagePath = null; - changesMade = true; - } - } - else if (!string.Equals(path, chapter.ImagePath, StringComparison.OrdinalIgnoreCase)) - { - chapter.ImagePath = path; - changesMade = true; - } - } - - if (saveChapters && changesMade) - { - await _itemRepo.SaveChapters(video.Id, chapters, cancellationToken).ConfigureAwait(false); - } - - DeleteDeadImages(currentImages, chapters); - - return success; - } - - private void DeleteDeadImages(IEnumerable<string> images, IEnumerable<ChapterInfo> chapters) - { - var deadImages = images - .Except(chapters.Select(i => i.ImagePath).Where(i => !string.IsNullOrEmpty(i)), StringComparer.OrdinalIgnoreCase) - .Where(i => BaseItem.SupportedImageExtensions.Contains(Path.GetExtension(i), StringComparer.OrdinalIgnoreCase)) - .ToList(); - - foreach (var image in deadImages) - { - _logger.Debug("Deleting dead chapter image {0}", image); - - try - { - File.Delete(image); - } - catch (IOException ex) - { - _logger.ErrorException("Error deleting {0}.", ex, image); - } - } - } - - private readonly CultureInfo _usCulture = new CultureInfo("en-US"); - - /// <summary> - /// Gets the subtitle cache path. - /// </summary> - /// <param name="mediaPath">The media path.</param> - /// <param name="subtitleStream">The subtitle stream.</param> - /// <param name="outputExtension">The output extension.</param> - /// <returns>System.String.</returns> - public string GetSubtitleCachePath(string mediaPath, MediaStream subtitleStream, string outputExtension) - { - var ticksParam = string.Empty; - - if (subtitleStream.IsExternal) - { - ticksParam += _fileSystem.GetLastWriteTimeUtc(subtitleStream.Path).Ticks; - } - - var date = _fileSystem.GetLastWriteTimeUtc(mediaPath); - - var filename = (mediaPath + "_" + subtitleStream.Index.ToString(_usCulture) + "_" + date.Ticks.ToString(_usCulture) + ticksParam).GetMD5() + outputExtension; - - var prefix = filename.Substring(0, 1); - - return Path.Combine(SubtitleCachePath, prefix, filename); - } - - public string GetChapterImagePath(Video video, long chapterPositionTicks) - { - var filename = video.DateModified.Ticks.ToString(_usCulture) + "_" + chapterPositionTicks.ToString(_usCulture) + ".jpg"; - - var videoId = video.Id.ToString(); - var prefix = videoId.Substring(0, 1); - - return Path.Combine(ChapterImagesPath, prefix, videoId, filename); - } - - public List<string> GetSavedChapterImages(Video video) - { - var videoId = video.Id.ToString(); - var prefix = videoId.Substring(0, 1); - - var path = Path.Combine(ChapterImagesPath, prefix, videoId); - - try - { - return Directory.EnumerateFiles(path) - .ToList(); - } - catch (DirectoryNotFoundException) - { - return new List<string>(); - } - } - } -} diff --git a/MediaBrowser.Controller/MediaInfo/IMediaEncoder.cs b/MediaBrowser.Controller/MediaInfo/IMediaEncoder.cs deleted file mode 100644 index d8cad48b3e..0000000000 --- a/MediaBrowser.Controller/MediaInfo/IMediaEncoder.cs +++ /dev/null @@ -1,108 +0,0 @@ -using MediaBrowser.Model.Entities; -using System; -using System.IO; -using System.Threading; -using System.Threading.Tasks; - -namespace MediaBrowser.Controller.MediaInfo -{ - /// <summary> - /// Interface IMediaEncoder - /// </summary> - public interface IMediaEncoder - { - /// <summary> - /// Gets the encoder path. - /// </summary> - /// <value>The encoder path.</value> - string EncoderPath { get; } - - /// <summary> - /// Gets the version. - /// </summary> - /// <value>The version.</value> - string Version { get; } - - /// <summary> - /// Extracts the image. - /// </summary> - /// <param name="inputFiles">The input files.</param> - /// <param name="type">The type.</param> - /// <param name="isAudio">if set to <c>true</c> [is audio].</param> - /// <param name="threedFormat">The threed format.</param> - /// <param name="offset">The offset.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task{Stream}.</returns> - Task<Stream> ExtractImage(string[] inputFiles, InputType type, bool isAudio, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken); - - /// <summary> - /// Extracts the text subtitle. - /// </summary> - /// <param name="inputFiles">The input files.</param> - /// <param name="type">The type.</param> - /// <param name="subtitleStreamIndex">Index of the subtitle stream.</param> - /// <param name="copySubtitleStream">if set to true, copy stream instead of converting.</param> - /// <param name="outputPath">The output path.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> - Task ExtractTextSubtitle(string[] inputFiles, InputType type, int subtitleStreamIndex, bool copySubtitleStream, string outputPath, CancellationToken cancellationToken); - - /// <summary> - /// Converts the text subtitle to ass. - /// </summary> - /// <param name="inputPath">The input path.</param> - /// <param name="outputPath">The output path.</param> - /// <param name="language">The language.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> - Task ConvertTextSubtitleToAss(string inputPath, string outputPath, string language, CancellationToken cancellationToken); - - /// <summary> - /// Gets the media info. - /// </summary> - /// <param name="inputFiles">The input files.</param> - /// <param name="type">The type.</param> - /// <param name="isAudio">if set to <c>true</c> [is audio].</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> - Task<InternalMediaInfoResult> GetMediaInfo(string[] inputFiles, InputType type, bool isAudio, CancellationToken cancellationToken); - - /// <summary> - /// Gets the probe size argument. - /// </summary> - /// <param name="type">The type.</param> - /// <returns>System.String.</returns> - string GetProbeSizeArgument(InputType type); - - /// <summary> - /// Gets the input argument. - /// </summary> - /// <param name="inputFiles">The input files.</param> - /// <param name="type">The type.</param> - /// <returns>System.String.</returns> - string GetInputArgument(string[] inputFiles, InputType type); - } - - /// <summary> - /// Enum InputType - /// </summary> - public enum InputType - { - /// <summary> - /// The file - /// </summary> - File, - /// <summary> - /// The bluray - /// </summary> - Bluray, - /// <summary> - /// The DVD - /// </summary> - Dvd, - /// <summary> - /// The URL - /// </summary> - Url - } -} diff --git a/MediaBrowser.Controller/MediaInfo/InternalMediaInfoResult.cs b/MediaBrowser.Controller/MediaInfo/InternalMediaInfoResult.cs deleted file mode 100644 index 3ceec1b90e..0000000000 --- a/MediaBrowser.Controller/MediaInfo/InternalMediaInfoResult.cs +++ /dev/null @@ -1,311 +0,0 @@ -using System.Collections.Generic; -using MediaBrowser.Model.Entities; - -namespace MediaBrowser.Controller.MediaInfo -{ - /// <summary> - /// Class MediaInfoResult - /// </summary> - public class InternalMediaInfoResult - { - /// <summary> - /// Gets or sets the streams. - /// </summary> - /// <value>The streams.</value> - public MediaStreamInfo[] streams { get; set; } - - /// <summary> - /// Gets or sets the format. - /// </summary> - /// <value>The format.</value> - public MediaFormatInfo format { get; set; } - - /// <summary> - /// Gets or sets the chapters. - /// </summary> - /// <value>The chapters.</value> - public List<ChapterInfo> Chapters { get; set; } - } - - /// <summary> - /// Represents a stream within the output - /// </summary> - public class MediaStreamInfo - { - /// <summary> - /// Gets or sets the index. - /// </summary> - /// <value>The index.</value> - public int index { get; set; } - - /// <summary> - /// Gets or sets the profile. - /// </summary> - /// <value>The profile.</value> - public string profile { get; set; } - - /// <summary> - /// Gets or sets the codec_name. - /// </summary> - /// <value>The codec_name.</value> - public string codec_name { get; set; } - - /// <summary> - /// Gets or sets the codec_long_name. - /// </summary> - /// <value>The codec_long_name.</value> - public string codec_long_name { get; set; } - - /// <summary> - /// Gets or sets the codec_type. - /// </summary> - /// <value>The codec_type.</value> - public string codec_type { get; set; } - - /// <summary> - /// Gets or sets the sample_rate. - /// </summary> - /// <value>The sample_rate.</value> - public string sample_rate { get; set; } - - /// <summary> - /// Gets or sets the channels. - /// </summary> - /// <value>The channels.</value> - public int channels { get; set; } - - /// <summary> - /// Gets or sets the channel_layout. - /// </summary> - /// <value>The channel_layout.</value> - public string channel_layout { get; set; } - - /// <summary> - /// Gets or sets the avg_frame_rate. - /// </summary> - /// <value>The avg_frame_rate.</value> - public string avg_frame_rate { get; set; } - - /// <summary> - /// Gets or sets the duration. - /// </summary> - /// <value>The duration.</value> - public string duration { get; set; } - - /// <summary> - /// Gets or sets the bit_rate. - /// </summary> - /// <value>The bit_rate.</value> - public string bit_rate { get; set; } - - /// <summary> - /// Gets or sets the width. - /// </summary> - /// <value>The width.</value> - public int width { get; set; } - - /// <summary> - /// Gets or sets the height. - /// </summary> - /// <value>The height.</value> - public int height { get; set; } - - /// <summary> - /// Gets or sets the display_aspect_ratio. - /// </summary> - /// <value>The display_aspect_ratio.</value> - public string display_aspect_ratio { get; set; } - - /// <summary> - /// Gets or sets the tags. - /// </summary> - /// <value>The tags.</value> - public Dictionary<string, string> tags { get; set; } - - /// <summary> - /// Gets or sets the bits_per_sample. - /// </summary> - /// <value>The bits_per_sample.</value> - public int bits_per_sample { get; set; } - - /// <summary> - /// Gets or sets the r_frame_rate. - /// </summary> - /// <value>The r_frame_rate.</value> - public string r_frame_rate { get; set; } - - /// <summary> - /// Gets or sets the has_b_frames. - /// </summary> - /// <value>The has_b_frames.</value> - public int has_b_frames { get; set; } - - /// <summary> - /// Gets or sets the sample_aspect_ratio. - /// </summary> - /// <value>The sample_aspect_ratio.</value> - public string sample_aspect_ratio { get; set; } - - /// <summary> - /// Gets or sets the pix_fmt. - /// </summary> - /// <value>The pix_fmt.</value> - public string pix_fmt { get; set; } - - /// <summary> - /// Gets or sets the level. - /// </summary> - /// <value>The level.</value> - public int level { get; set; } - - /// <summary> - /// Gets or sets the time_base. - /// </summary> - /// <value>The time_base.</value> - public string time_base { get; set; } - - /// <summary> - /// Gets or sets the start_time. - /// </summary> - /// <value>The start_time.</value> - public string start_time { get; set; } - - /// <summary> - /// Gets or sets the codec_time_base. - /// </summary> - /// <value>The codec_time_base.</value> - public string codec_time_base { get; set; } - - /// <summary> - /// Gets or sets the codec_tag. - /// </summary> - /// <value>The codec_tag.</value> - public string codec_tag { get; set; } - - /// <summary> - /// Gets or sets the codec_tag_string. - /// </summary> - /// <value>The codec_tag_string.</value> - public string codec_tag_string { get; set; } - - /// <summary> - /// Gets or sets the sample_fmt. - /// </summary> - /// <value>The sample_fmt.</value> - public string sample_fmt { get; set; } - - /// <summary> - /// Gets or sets the dmix_mode. - /// </summary> - /// <value>The dmix_mode.</value> - public string dmix_mode { get; set; } - - /// <summary> - /// Gets or sets the start_pts. - /// </summary> - /// <value>The start_pts.</value> - public string start_pts { get; set; } - - /// <summary> - /// Gets or sets the is_avc. - /// </summary> - /// <value>The is_avc.</value> - public string is_avc { get; set; } - - /// <summary> - /// Gets or sets the nal_length_size. - /// </summary> - /// <value>The nal_length_size.</value> - public string nal_length_size { get; set; } - - /// <summary> - /// Gets or sets the ltrt_cmixlev. - /// </summary> - /// <value>The ltrt_cmixlev.</value> - public string ltrt_cmixlev { get; set; } - - /// <summary> - /// Gets or sets the ltrt_surmixlev. - /// </summary> - /// <value>The ltrt_surmixlev.</value> - public string ltrt_surmixlev { get; set; } - - /// <summary> - /// Gets or sets the loro_cmixlev. - /// </summary> - /// <value>The loro_cmixlev.</value> - public string loro_cmixlev { get; set; } - - /// <summary> - /// Gets or sets the loro_surmixlev. - /// </summary> - /// <value>The loro_surmixlev.</value> - public string loro_surmixlev { get; set; } - - /// <summary> - /// Gets or sets the disposition. - /// </summary> - /// <value>The disposition.</value> - public Dictionary<string, string> disposition { get; set; } - } - - /// <summary> - /// Class MediaFormat - /// </summary> - public class MediaFormatInfo - { - /// <summary> - /// Gets or sets the filename. - /// </summary> - /// <value>The filename.</value> - public string filename { get; set; } - - /// <summary> - /// Gets or sets the nb_streams. - /// </summary> - /// <value>The nb_streams.</value> - public int nb_streams { get; set; } - - /// <summary> - /// Gets or sets the format_name. - /// </summary> - /// <value>The format_name.</value> - public string format_name { get; set; } - - /// <summary> - /// Gets or sets the format_long_name. - /// </summary> - /// <value>The format_long_name.</value> - public string format_long_name { get; set; } - - /// <summary> - /// Gets or sets the start_time. - /// </summary> - /// <value>The start_time.</value> - public string start_time { get; set; } - - /// <summary> - /// Gets or sets the duration. - /// </summary> - /// <value>The duration.</value> - public string duration { get; set; } - - /// <summary> - /// Gets or sets the size. - /// </summary> - /// <value>The size.</value> - public string size { get; set; } - - /// <summary> - /// Gets or sets the bit_rate. - /// </summary> - /// <value>The bit_rate.</value> - public string bit_rate { get; set; } - - /// <summary> - /// Gets or sets the tags. - /// </summary> - /// <value>The tags.</value> - public Dictionary<string, string> tags { get; set; } - } -} diff --git a/MediaBrowser.Controller/MediaInfo/MediaEncoderHelpers.cs b/MediaBrowser.Controller/MediaInfo/MediaEncoderHelpers.cs deleted file mode 100644 index 300071b7b2..0000000000 --- a/MediaBrowser.Controller/MediaInfo/MediaEncoderHelpers.cs +++ /dev/null @@ -1,365 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.IO; - -namespace MediaBrowser.Controller.MediaInfo -{ - /// <summary> - /// Class MediaEncoderHelpers - /// </summary> - public static class MediaEncoderHelpers - { - /// <summary> - /// Gets the input argument. - /// </summary> - /// <param name="videoPath">The video path.</param> - /// <param name="isRemote">if set to <c>true</c> [is remote].</param> - /// <param name="videoType">Type of the video.</param> - /// <param name="isoType">Type of the iso.</param> - /// <param name="isoMount">The iso mount.</param> - /// <param name="playableStreamFileNames">The playable stream file names.</param> - /// <param name="type">The type.</param> - /// <returns>System.String[][].</returns> - public static string[] GetInputArgument(string videoPath, bool isRemote, VideoType videoType, IsoType? isoType, IIsoMount isoMount, IEnumerable<string> playableStreamFileNames, out InputType type) - { - var inputPath = isoMount == null ? new[] { videoPath } : new[] { isoMount.MountedPath }; - - type = InputType.File; - - switch (videoType) - { - case VideoType.BluRay: - type = InputType.Bluray; - break; - case VideoType.Dvd: - type = InputType.Dvd; - inputPath = GetPlayableStreamFiles(inputPath[0], playableStreamFileNames).ToArray(); - break; - case VideoType.Iso: - if (isoType.HasValue) - { - switch (isoType.Value) - { - case IsoType.BluRay: - type = InputType.Bluray; - break; - case IsoType.Dvd: - type = InputType.Dvd; - inputPath = GetPlayableStreamFiles(inputPath[0], playableStreamFileNames).ToArray(); - break; - } - } - break; - case VideoType.VideoFile: - { - if (isRemote) - { - type = InputType.Url; - } - break; - } - } - - return inputPath; - } - - public static List<string> GetPlayableStreamFiles(string rootPath, IEnumerable<string> filenames) - { - var allFiles = Directory - .EnumerateFiles(rootPath, "*", SearchOption.AllDirectories) - .ToList(); - - return filenames.Select(name => allFiles.FirstOrDefault(f => string.Equals(Path.GetFileName(f), name, StringComparison.OrdinalIgnoreCase))) - .Where(f => !string.IsNullOrEmpty(f)) - .ToList(); - } - - /// <summary> - /// Gets the type of the input. - /// </summary> - /// <param name="videoType">Type of the video.</param> - /// <param name="isoType">Type of the iso.</param> - /// <returns>InputType.</returns> - public static InputType GetInputType(VideoType? videoType, IsoType? isoType) - { - var type = InputType.File; - - if (videoType.HasValue) - { - switch (videoType.Value) - { - case VideoType.BluRay: - type = InputType.Bluray; - break; - case VideoType.Dvd: - type = InputType.Dvd; - break; - case VideoType.Iso: - if (isoType.HasValue) - { - switch (isoType.Value) - { - case IsoType.BluRay: - type = InputType.Bluray; - break; - case IsoType.Dvd: - type = InputType.Dvd; - break; - } - } - break; - } - } - - return type; - } - - public static Model.Entities.MediaInfo GetMediaInfo(InternalMediaInfoResult data) - { - var internalStreams = data.streams ?? new MediaStreamInfo[] { }; - - var info = new Model.Entities.MediaInfo(); - - info.MediaStreams = internalStreams.Select(s => GetMediaStream(s, data.format)) - .Where(i => i != null) - .ToList(); - - if (data.format != null) - { - info.Format = data.format.format_name; - } - - return info; - } - - private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - - /// <summary> - /// Converts ffprobe stream info to our MediaStream class - /// </summary> - /// <param name="streamInfo">The stream info.</param> - /// <param name="formatInfo">The format info.</param> - /// <returns>MediaStream.</returns> - private static MediaStream GetMediaStream(MediaStreamInfo streamInfo, MediaFormatInfo formatInfo) - { - var stream = new MediaStream - { - Codec = streamInfo.codec_name, - Profile = streamInfo.profile, - Level = streamInfo.level, - Index = streamInfo.index - }; - - if (streamInfo.tags != null) - { - stream.Language = GetDictionaryValue(streamInfo.tags, "language"); - } - - if (string.Equals(streamInfo.codec_type, "audio", StringComparison.OrdinalIgnoreCase)) - { - stream.Type = MediaStreamType.Audio; - - stream.Channels = streamInfo.channels; - - if (!string.IsNullOrEmpty(streamInfo.sample_rate)) - { - stream.SampleRate = int.Parse(streamInfo.sample_rate, UsCulture); - } - - stream.ChannelLayout = ParseChannelLayout(streamInfo.channel_layout); - } - else if (string.Equals(streamInfo.codec_type, "subtitle", StringComparison.OrdinalIgnoreCase)) - { - stream.Type = MediaStreamType.Subtitle; - } - else if (string.Equals(streamInfo.codec_type, "video", StringComparison.OrdinalIgnoreCase)) - { - stream.Type = MediaStreamType.Video; - - stream.Width = streamInfo.width; - stream.Height = streamInfo.height; - stream.AspectRatio = GetAspectRatio(streamInfo); - - stream.AverageFrameRate = GetFrameRate(streamInfo.avg_frame_rate); - stream.RealFrameRate = GetFrameRate(streamInfo.r_frame_rate); - } - else - { - return null; - } - - // Get stream bitrate - if (stream.Type != MediaStreamType.Subtitle) - { - var bitrate = 0; - - if (!string.IsNullOrEmpty(streamInfo.bit_rate)) - { - bitrate = int.Parse(streamInfo.bit_rate, UsCulture); - } - else if (formatInfo != null && !string.IsNullOrEmpty(formatInfo.bit_rate)) - { - // If the stream info doesn't have a bitrate get the value from the media format info - bitrate = int.Parse(formatInfo.bit_rate, UsCulture); - } - - if (bitrate > 0) - { - stream.BitRate = bitrate; - } - } - - if (streamInfo.disposition != null) - { - var isDefault = GetDictionaryValue(streamInfo.disposition, "default"); - var isForced = GetDictionaryValue(streamInfo.disposition, "forced"); - - stream.IsDefault = string.Equals(isDefault, "1", StringComparison.OrdinalIgnoreCase); - - stream.IsForced = string.Equals(isForced, "1", StringComparison.OrdinalIgnoreCase); - } - - return stream; - } - - /// <summary> - /// Gets a string from an FFProbeResult tags dictionary - /// </summary> - /// <param name="tags">The tags.</param> - /// <param name="key">The key.</param> - /// <returns>System.String.</returns> - private static string GetDictionaryValue(Dictionary<string, string> tags, string key) - { - if (tags == null) - { - return null; - } - - string val; - - tags.TryGetValue(key, out val); - return val; - } - - private static string ParseChannelLayout(string input) - { - if (string.IsNullOrEmpty(input)) - { - return input; - } - - return input.Split('(').FirstOrDefault(); - } - - private static string GetAspectRatio(MediaStreamInfo info) - { - var original = info.display_aspect_ratio; - - int height; - int width; - - var parts = (original ?? string.Empty).Split(':'); - if (!(parts.Length == 2 && - int.TryParse(parts[0], NumberStyles.Any, UsCulture, out width) && - int.TryParse(parts[1], NumberStyles.Any, UsCulture, out height) && - width > 0 && - height > 0)) - { - width = info.width; - height = info.height; - } - - if (width > 0 && height > 0) - { - double ratio = width; - ratio /= height; - - if (IsClose(ratio, 1.777777778, .03)) - { - return "16:9"; - } - - if (IsClose(ratio, 1.3333333333, .05)) - { - return "4:3"; - } - - if (IsClose(ratio, 1.41)) - { - return "1.41:1"; - } - - if (IsClose(ratio, 1.5)) - { - return "1.5:1"; - } - - if (IsClose(ratio, 1.6)) - { - return "1.6:1"; - } - - if (IsClose(ratio, 1.66666666667)) - { - return "5:3"; - } - - if (IsClose(ratio, 1.85, .02)) - { - return "1.85:1"; - } - - if (IsClose(ratio, 2.35, .025)) - { - return "2.35:1"; - } - - if (IsClose(ratio, 2.4, .025)) - { - return "2.40:1"; - } - } - - return original; - } - - private static bool IsClose(double d1, double d2, double variance = .005) - { - return Math.Abs(d1 - d2) <= variance; - } - - /// <summary> - /// Gets a frame rate from a string value in ffprobe output - /// This could be a number or in the format of 2997/125. - /// </summary> - /// <param name="value">The value.</param> - /// <returns>System.Nullable{System.Single}.</returns> - private static float? GetFrameRate(string value) - { - if (!string.IsNullOrEmpty(value)) - { - var parts = value.Split('/'); - - float result; - - if (parts.Length == 2) - { - result = float.Parse(parts[0], UsCulture) / float.Parse(parts[1], UsCulture); - } - else - { - result = float.Parse(parts[0], UsCulture); - } - - return float.IsNaN(result) ? (float?)null : result; - } - - return null; - } - - } -} |
