added setting for intel qsv hardware decoding
This commit is contained in:
parent
2acd1665c9
commit
5340bfe8da
|
@ -290,13 +290,6 @@ namespace MediaBrowser.Api.Playback
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
var lib = ApiEntryPoint.Instance.GetEncodingOptions().H264Encoder;
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(lib))
|
|
||||||
{
|
|
||||||
return lib;
|
|
||||||
}
|
|
||||||
|
|
||||||
return "libx264";
|
return "libx264";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -809,6 +802,46 @@ namespace MediaBrowser.Api.Playback
|
||||||
return "copy";
|
return "copy";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name of the output video codec
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="state">The state.</param>
|
||||||
|
/// <returns>System.String.</returns>
|
||||||
|
protected string GetVideoDecoder(StreamState state)
|
||||||
|
{
|
||||||
|
if (string.Equals(ApiEntryPoint.Instance.GetEncodingOptions().HardwareVideoDecoder, "qsv", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
if (state.VideoStream != null && !string.IsNullOrWhiteSpace(state.VideoStream.Codec))
|
||||||
|
{
|
||||||
|
switch (state.MediaSource.VideoStream.Codec.ToLower())
|
||||||
|
{
|
||||||
|
case "avc":
|
||||||
|
case "h264":
|
||||||
|
if (MediaEncoder.SupportsDecoder("h264_qsv"))
|
||||||
|
{
|
||||||
|
return "-c:v h264_qsv ";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "mpeg2video":
|
||||||
|
if (MediaEncoder.SupportsDecoder("mpeg2_qsv"))
|
||||||
|
{
|
||||||
|
return "-c:v mpeg2_qsv ";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "vc1":
|
||||||
|
if (MediaEncoder.SupportsDecoder("vc1_qsv"))
|
||||||
|
{
|
||||||
|
return "-c:v vc1_qsv ";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// leave blank so ffmpeg will decide
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the input argument.
|
/// Gets the input argument.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -816,7 +849,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
protected string GetInputArgument(StreamState state)
|
protected string GetInputArgument(StreamState state)
|
||||||
{
|
{
|
||||||
var arg = "-i " + GetInputPathArgument(state);
|
var arg = string.Format("{1}-i {0}", GetInputPathArgument(state), GetVideoDecoder(state));
|
||||||
|
|
||||||
if (state.SubtitleStream != null)
|
if (state.SubtitleStream != null)
|
||||||
{
|
{
|
||||||
|
@ -826,7 +859,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return arg;
|
return arg.Trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetInputPathArgument(StreamState state)
|
private string GetInputPathArgument(StreamState state)
|
||||||
|
|
|
@ -24,6 +24,13 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
/// <value>The version.</value>
|
/// <value>The version.</value>
|
||||||
string Version { get; }
|
string Version { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Supportses the decoder.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="decoder">The decoder.</param>
|
||||||
|
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
|
||||||
|
bool SupportsDecoder(string decoder);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Extracts the audio image.
|
/// Extracts the audio image.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -97,6 +97,22 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
FFMpegPath = ffMpegPath;
|
FFMpegPath = ffMpegPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetAvailableEncoders(List<string> list)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<string> _decoders = new List<string>();
|
||||||
|
public void SetAvailableDecoders(List<string> list)
|
||||||
|
{
|
||||||
|
_decoders = list.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SupportsDecoder(string decoder)
|
||||||
|
{
|
||||||
|
return _decoders.Contains(decoder, StringComparer.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the encoder path.
|
/// Gets the encoder path.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -6,14 +6,13 @@ namespace MediaBrowser.Model.Configuration
|
||||||
public int EncodingThreadCount { get; set; }
|
public int EncodingThreadCount { get; set; }
|
||||||
public string TranscodingTempPath { get; set; }
|
public string TranscodingTempPath { get; set; }
|
||||||
public double DownMixAudioBoost { get; set; }
|
public double DownMixAudioBoost { get; set; }
|
||||||
public string H264Encoder { get; set; }
|
|
||||||
public bool EnableDebugLogging { get; set; }
|
public bool EnableDebugLogging { get; set; }
|
||||||
public bool EnableThrottling { get; set; }
|
public bool EnableThrottling { get; set; }
|
||||||
public int ThrottleThresholdInSeconds { get; set; }
|
public int ThrottleThresholdInSeconds { get; set; }
|
||||||
|
public string HardwareVideoDecoder { get; set; }
|
||||||
|
|
||||||
public EncodingOptions()
|
public EncodingOptions()
|
||||||
{
|
{
|
||||||
H264Encoder = "libx264";
|
|
||||||
DownMixAudioBoost = 2;
|
DownMixAudioBoost = 2;
|
||||||
EnableThrottling = true;
|
EnableThrottling = true;
|
||||||
ThrottleThresholdInSeconds = 120;
|
ThrottleThresholdInSeconds = 120;
|
||||||
|
|
|
@ -595,9 +595,7 @@ namespace MediaBrowser.Server.Startup.Common
|
||||||
var info = await new FFMpegDownloader(Logger, ApplicationPaths, HttpClient, ZipClient, FileSystemManager, NativeApp.Environment)
|
var info = await new FFMpegDownloader(Logger, ApplicationPaths, HttpClient, ZipClient, FileSystemManager, NativeApp.Environment)
|
||||||
.GetFFMpegInfo(NativeApp.Environment, _startupOptions, progress).ConfigureAwait(false);
|
.GetFFMpegInfo(NativeApp.Environment, _startupOptions, progress).ConfigureAwait(false);
|
||||||
|
|
||||||
new FFmpegValidator(Logger, ApplicationPaths, FileSystemManager).Validate(info);
|
var mediaEncoder = new MediaEncoder(LogManager.GetLogger("MediaEncoder"),
|
||||||
|
|
||||||
MediaEncoder = new MediaEncoder(LogManager.GetLogger("MediaEncoder"),
|
|
||||||
JsonSerializer,
|
JsonSerializer,
|
||||||
info.EncoderPath,
|
info.EncoderPath,
|
||||||
info.ProbePath,
|
info.ProbePath,
|
||||||
|
@ -611,7 +609,17 @@ namespace MediaBrowser.Server.Startup.Common
|
||||||
SessionManager,
|
SessionManager,
|
||||||
() => SubtitleEncoder,
|
() => SubtitleEncoder,
|
||||||
() => MediaSourceManager);
|
() => MediaSourceManager);
|
||||||
|
|
||||||
|
MediaEncoder = mediaEncoder;
|
||||||
RegisterSingleInstance(MediaEncoder);
|
RegisterSingleInstance(MediaEncoder);
|
||||||
|
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
var result = new FFmpegValidator(Logger, ApplicationPaths, FileSystemManager).Validate(info);
|
||||||
|
|
||||||
|
mediaEncoder.SetAvailableDecoders(result.Item1);
|
||||||
|
mediaEncoder.SetAvailableEncoders(result.Item2);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -33,7 +33,7 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
|
||||||
case OperatingSystem.Linux:
|
case OperatingSystem.Linux:
|
||||||
|
|
||||||
info.ArchiveType = "7z";
|
info.ArchiveType = "7z";
|
||||||
info.Version = "20150717";
|
info.Version = "20150917";
|
||||||
break;
|
break;
|
||||||
case OperatingSystem.Osx:
|
case OperatingSystem.Osx:
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
|
||||||
switch (environment.SystemArchitecture)
|
switch (environment.SystemArchitecture)
|
||||||
{
|
{
|
||||||
case Architecture.X86_X64:
|
case Architecture.X86_X64:
|
||||||
info.Version = "20150827";
|
info.Version = "20150917";
|
||||||
break;
|
break;
|
||||||
case Architecture.X86:
|
case Architecture.X86:
|
||||||
info.Version = "20150110";
|
info.Version = "20150110";
|
||||||
|
@ -54,7 +54,7 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
|
||||||
|
|
||||||
info.FFMpegFilename = "ffmpeg.exe";
|
info.FFMpegFilename = "ffmpeg.exe";
|
||||||
info.FFProbeFilename = "ffprobe.exe";
|
info.FFProbeFilename = "ffprobe.exe";
|
||||||
info.Version = "20150717";
|
info.Version = "20150916";
|
||||||
info.ArchiveType = "7z";
|
info.ArchiveType = "7z";
|
||||||
|
|
||||||
switch (environment.SystemArchitecture)
|
switch (environment.SystemArchitecture)
|
||||||
|
@ -83,14 +83,14 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
|
||||||
case Architecture.X86_X64:
|
case Architecture.X86_X64:
|
||||||
return new[]
|
return new[]
|
||||||
{
|
{
|
||||||
"http://ffmpeg.zeranoe.com/builds/win64/static/ffmpeg-20150717-git-8250943-win64-static.7z",
|
"http://ffmpeg.zeranoe.com/builds/win64/static/ffmpeg-20150916-git-cbbd906-win64-static.7z",
|
||||||
"https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/windows/ffmpeg-20150901-git-b54e03c-win64-static.7z"
|
"https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/windows/ffmpeg-20150916-git-cbbd906-win64-static.7z"
|
||||||
};
|
};
|
||||||
case Architecture.X86:
|
case Architecture.X86:
|
||||||
return new[]
|
return new[]
|
||||||
{
|
{
|
||||||
"http://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-20150717-git-8250943-win32-static.7z",
|
"http://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-20150916-git-cbbd906-win32-static.7z",
|
||||||
"https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/windows/ffmpeg-20150901-git-b54e03c-win32-static.7z"
|
"https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/windows/ffmpeg-20150916-git-cbbd906-win32-static.7z"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -102,7 +102,7 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
|
||||||
case Architecture.X86_X64:
|
case Architecture.X86_X64:
|
||||||
return new[]
|
return new[]
|
||||||
{
|
{
|
||||||
"https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/osx/ffmpeg-x64-2.7.2.7z"
|
"https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/osx/ffmpeg-x64-2.8.0.7z"
|
||||||
};
|
};
|
||||||
case Architecture.X86:
|
case Architecture.X86:
|
||||||
return new[]
|
return new[]
|
||||||
|
@ -119,12 +119,12 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
|
||||||
case Architecture.X86_X64:
|
case Architecture.X86_X64:
|
||||||
return new[]
|
return new[]
|
||||||
{
|
{
|
||||||
"https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/linux/ffmpeg-2.7.1-64bit-static.7z"
|
"https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/linux/ffmpeg-2.8.0-64bit-static.7z"
|
||||||
};
|
};
|
||||||
case Architecture.X86:
|
case Architecture.X86:
|
||||||
return new[]
|
return new[]
|
||||||
{
|
{
|
||||||
"https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/linux/ffmpeg-2.7.1-32bit-static.7z"
|
"https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/linux/ffmpeg-2.8.0-32bit-static.7z"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -7,6 +7,7 @@ using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using MediaBrowser.Common.IO;
|
using MediaBrowser.Common.IO;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace MediaBrowser.Server.Startup.Common.FFMpeg
|
namespace MediaBrowser.Server.Startup.Common.FFMpeg
|
||||||
{
|
{
|
||||||
|
@ -23,71 +24,65 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
|
||||||
_fileSystem = fileSystem;
|
_fileSystem = fileSystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Validate(FFMpegInfo info)
|
public Tuple<List<string>,List<string>> Validate(FFMpegInfo info)
|
||||||
{
|
{
|
||||||
_logger.Info("FFMpeg: {0}", info.EncoderPath);
|
_logger.Info("FFMpeg: {0}", info.EncoderPath);
|
||||||
_logger.Info("FFProbe: {0}", info.ProbePath);
|
_logger.Info("FFProbe: {0}", info.ProbePath);
|
||||||
|
|
||||||
string cacheKey;
|
var decoders = GetDecoders(info.EncoderPath);
|
||||||
|
var encoders = GetEncoders(info.EncoderPath);
|
||||||
|
|
||||||
|
return new Tuple<List<string>, List<string>>(decoders, encoders);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<string> GetDecoders(string ffmpegPath)
|
||||||
|
{
|
||||||
|
string output = string.Empty;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
cacheKey = new FileInfo(info.EncoderPath).Length.ToString(CultureInfo.InvariantCulture).GetMD5().ToString("N");
|
output = GetFFMpegOutput(ffmpegPath, "-decoders");
|
||||||
}
|
|
||||||
catch (IOException)
|
|
||||||
{
|
|
||||||
// This could happen if ffmpeg is coming from a Path variable and we don't have the full path
|
|
||||||
cacheKey = Guid.NewGuid().ToString("N");
|
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
cacheKey = Guid.NewGuid().ToString("N");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var cachePath = Path.Combine(_appPaths.CachePath, "1" + cacheKey);
|
var found = new List<string>();
|
||||||
|
var required = new[]
|
||||||
|
{
|
||||||
|
"h264_qsv",
|
||||||
|
"mpeg2_qsv",
|
||||||
|
"vc1_qsv"
|
||||||
|
};
|
||||||
|
|
||||||
ValidateCodecs(info.EncoderPath, cachePath);
|
foreach (var codec in required)
|
||||||
|
{
|
||||||
|
var srch = " " + codec + " ";
|
||||||
|
|
||||||
|
if (output.IndexOf(srch, StringComparison.OrdinalIgnoreCase) == -1)
|
||||||
|
{
|
||||||
|
_logger.Warn("ffmpeg is missing decoder " + codec);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
found.Add(codec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ValidateCodecs(string ffmpegPath, string cachePath)
|
private List<string> GetEncoders(string ffmpegPath)
|
||||||
{
|
{
|
||||||
string output = null;
|
string output = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
output = _fileSystem.ReadAllText(cachePath, Encoding.UTF8);
|
output = GetFFMpegOutput(ffmpegPath, "-encoders");
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(output))
|
var found = new List<string>();
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
output = GetFFMpegOutput(ffmpegPath, "-encoders");
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_fileSystem.CreateDirectory(Path.GetDirectoryName(cachePath));
|
|
||||||
_fileSystem.WriteAllText(cachePath, output, Encoding.UTF8);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ValidateCodecsFromOutput(output);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ValidateCodecsFromOutput(string output)
|
|
||||||
{
|
|
||||||
var required = new[]
|
var required = new[]
|
||||||
{
|
{
|
||||||
"libx264",
|
"libx264",
|
||||||
|
@ -103,16 +98,21 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
|
||||||
"srt"
|
"srt"
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var encoder in required)
|
foreach (var codec in required)
|
||||||
{
|
{
|
||||||
var srch = " " + encoder + " ";
|
var srch = " " + codec + " ";
|
||||||
|
|
||||||
if (output.IndexOf(srch, StringComparison.OrdinalIgnoreCase) == -1)
|
if (output.IndexOf(srch, StringComparison.OrdinalIgnoreCase) == -1)
|
||||||
{
|
{
|
||||||
_logger.Error("ffmpeg is missing encoder " + encoder);
|
_logger.Warn("ffmpeg is missing encoder " + codec);
|
||||||
//throw new ArgumentException("ffmpeg is missing encoder " + encoder);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
found.Add(codec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetFFMpegOutput(string path, string arguments)
|
private string GetFFMpegOutput(string path, string arguments)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user