aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Controller/MediaInfo
diff options
context:
space:
mode:
authorLuke Pulverenti <luke.pulverenti@gmail.com>2014-02-20 11:37:41 -0500
committerLuke Pulverenti <luke.pulverenti@gmail.com>2014-02-20 11:37:41 -0500
commit888b8d619aec031f57cfd03410ccda52edcca958 (patch)
tree143080937fb8811d107c610507a15376d6761955 /MediaBrowser.Controller/MediaInfo
parent160d14208809a13791e34530a3758b079d6b9638 (diff)
added encoding manager interface
Diffstat (limited to 'MediaBrowser.Controller/MediaInfo')
-rw-r--r--MediaBrowser.Controller/MediaInfo/FFMpegManager.cs297
-rw-r--r--MediaBrowser.Controller/MediaInfo/IMediaEncoder.cs108
-rw-r--r--MediaBrowser.Controller/MediaInfo/InternalMediaInfoResult.cs311
-rw-r--r--MediaBrowser.Controller/MediaInfo/MediaEncoderHelpers.cs365
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;
- }
-
- }
-}