added setting for intel qsv hardware decoding

This commit is contained in:
Luke Pulverenti 2015-09-17 23:08:45 -04:00
parent 2acd1665c9
commit 5340bfe8da
7 changed files with 132 additions and 69 deletions

View File

@ -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)

View File

@ -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>

View File

@ -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>

View File

@ -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;

View File

@ -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>

View File

@ -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;

View File

@ -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)