aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.MediaEncoding/Encoder
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.MediaEncoding/Encoder')
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs135
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs268
2 files changed, 224 insertions, 179 deletions
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs
index 92f16ab95..60a2d39e5 100644
--- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs
@@ -12,8 +12,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
public class EncoderValidator
{
- private const string DefaultEncoderPath = "ffmpeg";
-
private static readonly string[] _requiredDecoders = new[]
{
"h264",
@@ -89,6 +87,24 @@ namespace MediaBrowser.MediaEncoding.Encoder
"hevc_videotoolbox"
};
+ private static readonly string[] _requiredFilters = new[]
+ {
+ "scale_cuda",
+ "yadif_cuda",
+ "hwupload_cuda",
+ "overlay_cuda",
+ "tonemap_cuda",
+ "tonemap_opencl",
+ "tonemap_vaapi",
+ };
+
+ private static readonly IReadOnlyDictionary<int, string[]> _filterOptionsDict = new Dictionary<int, string[]>
+ {
+ { 0, new string[] { "scale_cuda", "Output format (default \"same\")" } },
+ { 1, new string[] { "tonemap_cuda", "GPU accelerated HDR to SDR tonemapping" } },
+ { 2, new string[] { "tonemap_opencl", "bt2390" } }
+ };
+
// These are the library versions that corresponds to our minimum ffmpeg version 4.x according to the version table below
private static readonly IReadOnlyDictionary<string, Version> _ffmpegMinimumLibraryVersions = new Dictionary<string, Version>
{
@@ -106,7 +122,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
private readonly string _encoderPath;
- public EncoderValidator(ILogger logger, string encoderPath = DefaultEncoderPath)
+ public EncoderValidator(ILogger logger, string encoderPath)
{
_logger = logger;
_encoderPath = encoderPath;
@@ -121,11 +137,11 @@ namespace MediaBrowser.MediaEncoding.Encoder
// When changing this, also change the minimum library versions in _ffmpegMinimumLibraryVersions
public static Version MinVersion { get; } = new Version(4, 0);
- public static Version MaxVersion { get; } = null;
+ public static Version? MaxVersion { get; } = null;
public bool ValidateVersion()
{
- string output = null;
+ string output;
try
{
output = GetProcessOutput(_encoderPath, "-version");
@@ -133,6 +149,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
catch (Exception ex)
{
_logger.LogError(ex, "Error validating encoder");
+ return false;
}
if (string.IsNullOrWhiteSpace(output))
@@ -155,7 +172,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
// Work out what the version under test is
- var version = GetFFmpegVersion(versionOutput);
+ var version = GetFFmpegVersionInternal(versionOutput);
_logger.LogInformation("Found ffmpeg version {Version}", version != null ? version.ToString() : "unknown");
@@ -199,6 +216,34 @@ namespace MediaBrowser.MediaEncoding.Encoder
public IEnumerable<string> GetHwaccels() => GetHwaccelTypes();
+ public IEnumerable<string> GetFilters() => GetFFmpegFilters();
+
+ public IDictionary<int, bool> GetFiltersWithOption() => GetFFmpegFiltersWithOption();
+
+ public Version? GetFFmpegVersion()
+ {
+ string output;
+ try
+ {
+ output = GetProcessOutput(_encoderPath, "-version");
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error validating encoder");
+ return null;
+ }
+
+ if (string.IsNullOrWhiteSpace(output))
+ {
+ _logger.LogError("FFmpeg validation: The process returned no result");
+ return null;
+ }
+
+ _logger.LogDebug("ffmpeg output: {Output}", output);
+
+ return GetFFmpegVersionInternal(output);
+ }
+
/// <summary>
/// Using the output from "ffmpeg -version" work out the FFmpeg version.
/// For pre-built binaries the first line should contain a string like "ffmpeg version x.y", which is easy
@@ -207,7 +252,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// </summary>
/// <param name="output">The output from "ffmpeg -version".</param>
/// <returns>The FFmpeg version.</returns>
- internal Version GetFFmpegVersion(string output)
+ internal Version? GetFFmpegVersionInternal(string output)
{
// For pre-built binaries the FFmpeg version should be mentioned at the very start of the output
var match = Regex.Match(output, @"^ffmpeg version n?((?:[0-9]+\.?)+)");
@@ -275,7 +320,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
private IEnumerable<string> GetHwaccelTypes()
{
- string output = null;
+ string? output = null;
try
{
output = GetProcessOutput(_encoderPath, "-hwaccels");
@@ -296,10 +341,38 @@ namespace MediaBrowser.MediaEncoding.Encoder
return found;
}
+ public bool CheckFilterWithOption(string filter, string option)
+ {
+ if (string.IsNullOrEmpty(filter) || string.IsNullOrEmpty(option))
+ {
+ return false;
+ }
+
+ string output;
+ try
+ {
+ output = GetProcessOutput(_encoderPath, "-h filter=" + filter);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error detecting the given filter");
+ return false;
+ }
+
+ if (output.Contains("Filter " + filter, StringComparison.Ordinal))
+ {
+ return output.Contains(option, StringComparison.Ordinal);
+ }
+
+ _logger.LogWarning("Filter: {Name} with option {Option} is not available", filter, option);
+
+ return false;
+ }
+
private IEnumerable<string> GetCodecs(Codec codec)
{
string codecstr = codec == Codec.Encoder ? "encoders" : "decoders";
- string output = null;
+ string output;
try
{
output = GetProcessOutput(_encoderPath, "-" + codecstr);
@@ -307,6 +380,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
catch (Exception ex)
{
_logger.LogError(ex, "Error detecting available {Codec}", codecstr);
+ return Enumerable.Empty<string>();
}
if (string.IsNullOrWhiteSpace(output))
@@ -327,6 +401,49 @@ namespace MediaBrowser.MediaEncoding.Encoder
return found;
}
+ private IEnumerable<string> GetFFmpegFilters()
+ {
+ string output;
+ try
+ {
+ output = GetProcessOutput(_encoderPath, "-filters");
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error detecting available filters");
+ return Enumerable.Empty<string>();
+ }
+
+ if (string.IsNullOrWhiteSpace(output))
+ {
+ return Enumerable.Empty<string>();
+ }
+
+ var found = Regex
+ .Matches(output, @"^\s\S{3}\s(?<filter>[\w|-]+)\s+.+$", RegexOptions.Multiline)
+ .Cast<Match>()
+ .Select(x => x.Groups["filter"].Value)
+ .Where(x => _requiredFilters.Contains(x));
+
+ _logger.LogInformation("Available filters: {Filters}", found);
+
+ return found;
+ }
+
+ private IDictionary<int, bool> GetFFmpegFiltersWithOption()
+ {
+ IDictionary<int, bool> dict = new Dictionary<int, bool>();
+ for (int i = 0; i < _filterOptionsDict.Count; i++)
+ {
+ if (_filterOptionsDict.TryGetValue(i, out var val) && val.Length == 2)
+ {
+ dict.Add(i, CheckFilterWithOption(val[0], val[1]));
+ }
+ }
+
+ return dict;
+ }
+
private string GetProcessOutput(string path, string arguments)
{
using (var process = new Process()
diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
index fbd08a97c..a7bcaf544 100644
--- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
@@ -1,3 +1,4 @@
+#nullable disable
#pragma warning disable CS1591
using System;
@@ -10,20 +11,18 @@ using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
+using Jellyfin.Extensions.Json;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Json;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.MediaEncoding.Probing;
-using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.MediaInfo;
-using MediaBrowser.Model.System;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
@@ -53,7 +52,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
private readonly IServerConfigurationManager _configurationManager;
private readonly IFileSystem _fileSystem;
private readonly ILocalizationManager _localization;
- private readonly Lazy<EncodingHelper> _encodingHelperFactory;
private readonly string _startupOptionFFmpegPath;
private readonly SemaphoreSlim _thumbnailResourcePool = new SemaphoreSlim(2, 2);
@@ -67,34 +65,32 @@ namespace MediaBrowser.MediaEncoding.Encoder
private List<string> _encoders = new List<string>();
private List<string> _decoders = new List<string>();
private List<string> _hwaccels = new List<string>();
+ private List<string> _filters = new List<string>();
+ private IDictionary<int, bool> _filtersWithOption = new Dictionary<int, bool>();
+ private Version _ffmpegVersion = null;
private string _ffmpegPath = string.Empty;
private string _ffprobePath;
- private int threads;
+ private int _threads;
public MediaEncoder(
ILogger<MediaEncoder> logger,
IServerConfigurationManager configurationManager,
IFileSystem fileSystem,
ILocalizationManager localization,
- Lazy<EncodingHelper> encodingHelperFactory,
IConfiguration config)
{
_logger = logger;
_configurationManager = configurationManager;
_fileSystem = fileSystem;
_localization = localization;
- _encodingHelperFactory = encodingHelperFactory;
_startupOptionFFmpegPath = config.GetValue<string>(Controller.Extensions.ConfigurationExtensions.FfmpegPathKey) ?? string.Empty;
- _jsonSerializerOptions = JsonDefaults.GetOptions();
+ _jsonSerializerOptions = JsonDefaults.Options;
}
/// <inheritdoc />
public string EncoderPath => _ffmpegPath;
- /// <inheritdoc />
- public FFmpegLocation EncoderLocation { get; private set; }
-
/// <summary>
/// Run at startup or if the user removes a Custom path from transcode page.
/// Sets global variables FFmpegPath.
@@ -103,22 +99,25 @@ namespace MediaBrowser.MediaEncoding.Encoder
public void SetFFmpegPath()
{
// 1) Custom path stored in config/encoding xml file under tag <EncoderAppPath> takes precedence
- if (!ValidatePath(_configurationManager.GetConfiguration<EncodingOptions>("encoding").EncoderAppPath, FFmpegLocation.Custom))
+ var ffmpegPath = _configurationManager.GetEncodingOptions().EncoderAppPath;
+ if (string.IsNullOrEmpty(ffmpegPath))
{
// 2) Check if the --ffmpeg CLI switch has been given
- if (!ValidatePath(_startupOptionFFmpegPath, FFmpegLocation.SetByArgument))
+ ffmpegPath = _startupOptionFFmpegPath;
+ if (string.IsNullOrEmpty(ffmpegPath))
{
- // 3) Search system $PATH environment variable for valid FFmpeg
- if (!ValidatePath(ExistsOnSystemPath("ffmpeg"), FFmpegLocation.System))
- {
- EncoderLocation = FFmpegLocation.NotFound;
- _ffmpegPath = null;
- }
+ // 3) Check "ffmpeg"
+ ffmpegPath = "ffmpeg";
}
}
+ if (!ValidatePath(ffmpegPath))
+ {
+ _ffmpegPath = null;
+ }
+
// Write the FFmpeg path to the config/encoding.xml file as <EncoderAppPathDisplay> so it appears in UI
- var config = _configurationManager.GetConfiguration<EncodingOptions>("encoding");
+ var config = _configurationManager.GetEncodingOptions();
config.EncoderAppPathDisplay = _ffmpegPath ?? string.Empty;
_configurationManager.SaveConfiguration("encoding", config);
@@ -133,11 +132,15 @@ namespace MediaBrowser.MediaEncoding.Encoder
SetAvailableDecoders(validator.GetDecoders());
SetAvailableEncoders(validator.GetEncoders());
+ SetAvailableFilters(validator.GetFilters());
+ SetAvailableFiltersWithOption(validator.GetFiltersWithOption());
SetAvailableHwaccels(validator.GetHwaccels());
- threads = EncodingHelper.GetNumberOfThreads(null, _configurationManager.GetEncodingOptions(), null);
+ SetMediaEncoderVersion(validator);
+
+ _threads = EncodingHelper.GetNumberOfThreads(null, _configurationManager.GetEncodingOptions(), null);
}
- _logger.LogInformation("FFmpeg: {EncoderLocation}: {FfmpegPath}", EncoderLocation, _ffmpegPath ?? string.Empty);
+ _logger.LogInformation("FFmpeg: {FfmpegPath}", _ffmpegPath ?? string.Empty);
}
/// <summary>
@@ -156,15 +159,12 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
throw new ArgumentException("Unexpected pathType value");
}
- else if (string.IsNullOrWhiteSpace(path))
+
+ if (string.IsNullOrWhiteSpace(path))
{
// User had cleared the custom path in UI
newPath = string.Empty;
}
- else if (File.Exists(path))
- {
- newPath = path;
- }
else if (Directory.Exists(path))
{
// Given path is directory, so resolve down to filename
@@ -172,12 +172,12 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
else
{
- throw new ResourceNotFoundException();
+ newPath = path;
}
// Write the new ffmpeg path to the xml as <EncoderAppPath>
// This ensures its not lost on next startup
- var config = _configurationManager.GetConfiguration<EncodingOptions>("encoding");
+ var config = _configurationManager.GetEncodingOptions();
config.EncoderAppPath = newPath;
_configurationManager.SaveConfiguration("encoding", config);
@@ -187,36 +187,26 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// <summary>
/// Validates the supplied FQPN to ensure it is a ffmpeg utility.
- /// If checks pass, global variable FFmpegPath and EncoderLocation are updated.
+ /// If checks pass, global variable FFmpegPath is updated.
/// </summary>
/// <param name="path">FQPN to test.</param>
- /// <param name="location">Location (External, Custom, System) of tool.</param>
/// <returns><c>true</c> if the version validation succeeded; otherwise, <c>false</c>.</returns>
- private bool ValidatePath(string path, FFmpegLocation location)
+ private bool ValidatePath(string path)
{
- bool rc = false;
-
- if (!string.IsNullOrEmpty(path))
+ if (string.IsNullOrEmpty(path))
{
- if (File.Exists(path))
- {
- rc = new EncoderValidator(_logger, path).ValidateVersion();
-
- if (!rc)
- {
- _logger.LogWarning("FFmpeg: {Location}: Failed version check: {Path}", location, path);
- }
+ return false;
+ }
- _ffmpegPath = path;
- EncoderLocation = location;
- }
- else
- {
- _logger.LogWarning("FFmpeg: {Location}: File not found: {Path}", location, path);
- }
+ bool rc = new EncoderValidator(_logger, path).ValidateVersion();
+ if (!rc)
+ {
+ _logger.LogWarning("FFmpeg: Failed version check: {Path}", path);
+ return false;
}
- return rc;
+ _ffmpegPath = path;
+ return true;
}
private string GetEncoderPathFromDirectory(string path, string filename, bool recursive = false)
@@ -237,34 +227,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
}
- /// <summary>
- /// Search the system $PATH environment variable looking for given filename.
- /// </summary>
- /// <param name="fileName">The filename.</param>
- /// <returns>The full path to the file.</returns>
- private string ExistsOnSystemPath(string fileName)
- {
- var inJellyfinPath = GetEncoderPathFromDirectory(AppContext.BaseDirectory, fileName, recursive: true);
- if (!string.IsNullOrEmpty(inJellyfinPath))
- {
- return inJellyfinPath;
- }
-
- var values = Environment.GetEnvironmentVariable("PATH");
-
- foreach (var path in values.Split(Path.PathSeparator))
- {
- var candidatePath = GetEncoderPathFromDirectory(path, fileName);
-
- if (!string.IsNullOrEmpty(candidatePath))
- {
- return candidatePath;
- }
- }
-
- return null;
- }
-
public void SetAvailableEncoders(IEnumerable<string> list)
{
_encoders = list.ToList();
@@ -280,6 +242,21 @@ namespace MediaBrowser.MediaEncoding.Encoder
_hwaccels = list.ToList();
}
+ public void SetAvailableFilters(IEnumerable<string> list)
+ {
+ _filters = list.ToList();
+ }
+
+ public void SetAvailableFiltersWithOption(IDictionary<int, bool> dict)
+ {
+ _filtersWithOption = dict;
+ }
+
+ public void SetMediaEncoderVersion(EncoderValidator validator)
+ {
+ _ffmpegVersion = validator.GetFFmpegVersion();
+ }
+
public bool SupportsEncoder(string encoder)
{
return _encoders.Contains(encoder, StringComparer.OrdinalIgnoreCase);
@@ -295,6 +272,26 @@ namespace MediaBrowser.MediaEncoding.Encoder
return _hwaccels.Contains(hwaccel, StringComparer.OrdinalIgnoreCase);
}
+ public bool SupportsFilter(string filter)
+ {
+ return _filters.Contains(filter, StringComparer.OrdinalIgnoreCase);
+ }
+
+ public bool SupportsFilterWithOption(FilterOptionType option)
+ {
+ if (_filtersWithOption.TryGetValue((int)option, out var val))
+ {
+ return val;
+ }
+
+ return false;
+ }
+
+ public Version GetMediaEncoderVersion()
+ {
+ return _ffmpegVersion;
+ }
+
public bool CanEncodeToAudioCodec(string codec)
{
if (string.Equals(codec, "opus", StringComparison.OrdinalIgnoreCase))
@@ -358,7 +355,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
public string GetInputArgument(string inputFile, MediaSourceInfo mediaSource)
{
var prefix = "file";
- if (mediaSource.VideoType == VideoType.BluRay || mediaSource.VideoType == VideoType.Iso)
+ if (mediaSource.VideoType == VideoType.BluRay
+ || mediaSource.IsoType == IsoType.BluRay)
{
prefix = "bluray";
}
@@ -384,7 +382,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
var args = extractChapters
? "{0} -i {1} -threads {2} -v warning -print_format json -show_streams -show_chapters -show_format"
: "{0} -i {1} -threads {2} -v warning -print_format json -show_streams -show_format";
- args = string.Format(CultureInfo.InvariantCulture, args, probeSizeArgument, inputPath, threads).Trim();
+ args = string.Format(CultureInfo.InvariantCulture, args, probeSizeArgument, inputPath, _threads).Trim();
var process = new Process
{
@@ -436,7 +434,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
if (result == null || (result.Streams == null && result.Format == null))
{
- throw new Exception("ffprobe failed - streams and format are both null.");
+ throw new FfmpegException("ffprobe failed - streams and format are both null.");
}
if (result.Streams != null)
@@ -493,15 +491,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
var inputArgument = GetInputArgument(inputFile, mediaSource);
- if (isAudio)
- {
- if (imageStreamIndex.HasValue && imageStreamIndex.Value > 0)
- {
- // It seems for audio files we need to subtract 1 (for the audio stream??)
- imageStreamIndex = imageStreamIndex.Value - 1;
- }
- }
- else
+ if (!isAudio)
{
// The failure of HDR extraction usually occurs when using custom ffmpeg that does not contain the zscale filter.
try
@@ -559,40 +549,26 @@ namespace MediaBrowser.MediaEncoding.Encoder
// apply some filters to thumbnail extracted below (below) crop any black lines that we made and get the correct ar.
// This filter chain may have adverse effects on recorded tv thumbnails if ar changes during presentation ex. commercials @ diff ar
- var vf = string.Empty;
-
- if (threedFormat.HasValue)
+ var vf = threedFormat switch
{
- switch (threedFormat.Value)
- {
- case Video3DFormat.HalfSideBySide:
- vf = "-vf crop=iw/2:ih:0:0,scale=(iw*2):ih,setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1";
- // hsbs crop width in half,scale to correct size, set the display aspect,crop out any black bars we may have made. Work out the correct height based on the display aspect it will maintain the aspect where -1 in this case (3d) may not.
- break;
- case Video3DFormat.FullSideBySide:
- vf = "-vf crop=iw/2:ih:0:0,setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1";
- // fsbs crop width in half,set the display aspect,crop out any black bars we may have made
- break;
- case Video3DFormat.HalfTopAndBottom:
- vf = "-vf crop=iw:ih/2:0:0,scale=(iw*2):ih),setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1";
- // htab crop heigh in half,scale to correct size, set the display aspect,crop out any black bars we may have made
- break;
- case Video3DFormat.FullTopAndBottom:
- vf = "-vf crop=iw:ih/2:0:0,setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1";
- // ftab crop heigt in half, set the display aspect,crop out any black bars we may have made
- break;
- default:
- break;
- }
- }
+ // hsbs crop width in half,scale to correct size, set the display aspect,crop out any black bars we may have made. Work out the correct height based on the display aspect it will maintain the aspect where -1 in this case (3d) may not.
+ Video3DFormat.HalfSideBySide => "-vf crop=iw/2:ih:0:0,scale=(iw*2):ih,setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1",
+ // fsbs crop width in half,set the display aspect,crop out any black bars we may have made
+ Video3DFormat.FullSideBySide => "-vf crop=iw/2:ih:0:0,setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1",
+ // htab crop heigh in half,scale to correct size, set the display aspect,crop out any black bars we may have made
+ Video3DFormat.HalfTopAndBottom => "-vf crop=iw:ih/2:0:0,scale=(iw*2):ih),setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1",
+ // ftab crop heigt in half, set the display aspect,crop out any black bars we may have made
+ Video3DFormat.FullTopAndBottom => "-vf crop=iw:ih/2:0:0,setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1",
+ _ => string.Empty
+ };
- var mapArg = imageStreamIndex.HasValue ? (" -map 0:v:" + imageStreamIndex.Value.ToString(CultureInfo.InvariantCulture)) : string.Empty;
+ var mapArg = imageStreamIndex.HasValue ? (" -map 0:" + imageStreamIndex.Value.ToString(CultureInfo.InvariantCulture)) : string.Empty;
var enableHdrExtraction = allowTonemap && string.Equals(videoStream?.VideoRange, "HDR", StringComparison.OrdinalIgnoreCase);
if (enableHdrExtraction)
{
string tonemapFilters = "zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=hable:desat=0:peak=100,zscale=t=bt709:m=bt709,format=yuv420p";
- if (string.IsNullOrEmpty(vf))
+ if (vf.Length == 0)
{
vf = "-vf " + tonemapFilters;
}
@@ -619,37 +595,13 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
}
- var args = string.Format(CultureInfo.InvariantCulture, "-i {0}{3} -threads {4} -v quiet -vframes 1 {2} -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg, threads);
-
- var probeSizeArgument = string.Empty;
- var analyzeDurationArgument = string.Empty;
-
- if (!string.IsNullOrWhiteSpace(probeSizeArgument))
- {
- args = probeSizeArgument + " " + args;
- }
-
- if (!string.IsNullOrWhiteSpace(analyzeDurationArgument))
- {
- args = analyzeDurationArgument + " " + args;
- }
+ var args = string.Format(CultureInfo.InvariantCulture, "-i {0}{3} -threads {4} -v quiet -vframes 1 {2} -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg, _threads);
if (offset.HasValue)
{
args = string.Format(CultureInfo.InvariantCulture, "-ss {0} ", GetTimeParameter(offset.Value)) + args;
}
- if (videoStream != null)
- {
- /* fix
- var decoder = encodinghelper.GetHardwareAcceleratedVideoDecoder(VideoType.VideoFile, videoStream, GetEncodingOptions());
- if (!string.IsNullOrWhiteSpace(decoder))
- {
- args = decoder + " " + args;
- }
- */
- }
-
if (!string.IsNullOrWhiteSpace(container))
{
var inputFormat = EncodingHelper.GetInputFormat(container);
@@ -711,7 +663,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
_logger.LogError(msg);
- throw new Exception(msg);
+ throw new FfmpegException(msg);
}
return tempExtractPath;
@@ -756,31 +708,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
Directory.CreateDirectory(targetDirectory);
var outputPath = Path.Combine(targetDirectory, filenamePrefix + "%05d.jpg");
- var args = string.Format(CultureInfo.InvariantCulture, "-i {0} -threads {3} -v quiet {2} -f image2 \"{1}\"", inputArgument, outputPath, vf, threads);
-
- var probeSizeArgument = string.Empty;
- var analyzeDurationArgument = string.Empty;
-
- if (!string.IsNullOrWhiteSpace(probeSizeArgument))
- {
- args = probeSizeArgument + " " + args;
- }
-
- if (!string.IsNullOrWhiteSpace(analyzeDurationArgument))
- {
- args = analyzeDurationArgument + " " + args;
- }
-
- if (videoStream != null)
- {
- /* fix
- var decoder = encodinghelper.GetHardwareAcceleratedVideoDecoder(VideoType.VideoFile, videoStream, GetEncodingOptions());
- if (!string.IsNullOrWhiteSpace(decoder))
- {
- args = decoder + " " + args;
- }
- */
- }
+ var args = string.Format(CultureInfo.InvariantCulture, "-i {0} -threads {3} -v quiet {2} -f image2 \"{1}\"", inputArgument, outputPath, vf, _threads);
if (!string.IsNullOrWhiteSpace(container))
{
@@ -860,7 +788,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
_logger.LogError(msg);
- throw new Exception(msg);
+ throw new FfmpegException(msg);
}
}
}