diff options
| author | Luke Pulverenti <luke.pulverenti@gmail.com> | 2014-11-09 13:24:57 -0500 |
|---|---|---|
| committer | Luke Pulverenti <luke.pulverenti@gmail.com> | 2014-11-09 13:24:57 -0500 |
| commit | 1a80362a0f04c3cc571456af64f9de19c0c30d2a (patch) | |
| tree | 31916eea422d8ac861aa36a47cae832eee168ad8 /MediaBrowser.ServerApplication/FFMpeg | |
| parent | 40897bac1494791e1ec6abcfe85cda27d4664a32 (diff) | |
created common startup project for mono & windows
Diffstat (limited to 'MediaBrowser.ServerApplication/FFMpeg')
3 files changed, 0 insertions, 692 deletions
diff --git a/MediaBrowser.ServerApplication/FFMpeg/FFMpegDownloadInfo.cs b/MediaBrowser.ServerApplication/FFMpeg/FFMpegDownloadInfo.cs deleted file mode 100644 index 2ca9107861..0000000000 --- a/MediaBrowser.ServerApplication/FFMpeg/FFMpegDownloadInfo.cs +++ /dev/null @@ -1,252 +0,0 @@ -using Mono.Unix.Native; -using System; -using System.IO; -using System.Text.RegularExpressions; - -namespace MediaBrowser.ServerApplication.FFMpeg -{ - public static class FFMpegDownloadInfo - { - // Windows builds: http://ffmpeg.zeranoe.com/builds/ - // Linux builds: http://ffmpeg.gusari.org/static/ - // OS X builds: http://ffmpegmac.net/ - // OS X x64: http://www.evermeet.cx/ffmpeg/ - - public static string Version = getFfmpegValue("Version"); - - public static string FFMpegFilename = getFfmpegValue("FFMpegFilename"); - public static string FFProbeFilename = getFfmpegValue("FFProbeFilename"); - - public static string ArchiveType = getFfmpegValue("ArchiveType"); - - private static string getFfmpegValue(string arg) - { - OperatingSystem os = Environment.OSVersion; - PlatformID pid = os.Platform; - switch (pid) - { - case PlatformID.Win32NT: - switch (arg) - { - case "Version": - return "20141005"; - case "FFMpegFilename": - return "ffmpeg.exe"; - case "FFProbeFilename": - return "ffprobe.exe"; - case "ArchiveType": - return "7z"; - } - break; - - case PlatformID.Unix: - if (PlatformDetection.IsMac) - { - if (PlatformDetection.IsX86_64) - { - switch (arg) - { - case "Version": - return "20140923"; - case "FFMpegFilename": - return "ffmpeg"; - case "FFProbeFilename": - return "ffprobe"; - case "ArchiveType": - return "7z"; - } - } - if (PlatformDetection.IsX86) - { - switch (arg) - { - case "Version": - return "20140910"; - case "FFMpegFilename": - return "ffmpeg"; - case "FFProbeFilename": - return "ffprobe"; - case "ArchiveType": - return "7z"; - } - } - } - else if (PlatformDetection.IsLinux) - { - if (PlatformDetection.IsX86) - { - switch (arg) - { - case "Version": - return "20140716"; - case "FFMpegFilename": - return "ffmpeg"; - case "FFProbeFilename": - return "ffprobe"; - case "ArchiveType": - return "gz"; - } - } - - else if (PlatformDetection.IsX86_64) - { - // Linux on x86 or x86_64 - switch (arg) - { - case "Version": - return "20140716"; - case "FFMpegFilename": - return "ffmpeg"; - case "FFProbeFilename": - return "ffprobe"; - case "ArchiveType": - return "gz"; - } - } - } - - break; - } - - switch (arg) - { - case "Version": - return "path"; - case "FFMpegFilename": - return "ffmpeg"; - case "FFProbeFilename": - return "ffprobe"; - case "ArchiveType": - return ""; - default: - return string.Empty; - } - } - - public static string[] GetDownloadUrls() - { - var pid = Environment.OSVersion.Platform; - - switch (pid) - { - case PlatformID.Win32NT: - if (PlatformDetection.IsX86_64) - { - return new[] - { - "http://ffmpeg.zeranoe.com/builds/win64/static/ffmpeg-20141005-git-e079d43-win64-static.7z", - "https://github.com/MediaBrowser/MediaBrowser.Resources/raw/master/ffmpeg/windows/ffmpeg-20141005-git-e079d43-win64-static.7z" - }; - } - - return new[] - { - "http://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-20141005-git-e079d43-win32-static.7z", - "https://github.com/MediaBrowser/MediaBrowser.Resources/raw/master/ffmpeg/windows/ffmpeg-20141005-git-e079d43-win32-static.7z" - }; - - case PlatformID.Unix: - if (PlatformDetection.IsMac && PlatformDetection.IsX86) - { - return new[] - { - "https://github.com/MediaBrowser/MediaBrowser.Resources/raw/master/ffmpeg/osx/ffmpeg-x86-2.4.2.7z" - }; - } - - if (PlatformDetection.IsMac && PlatformDetection.IsX86_64) - { - return new[] - { - "https://github.com/MediaBrowser/MediaBrowser.Resources/raw/master/ffmpeg/osx/ffmpeg-x64-2.4.1.7z" - }; - } - - if (PlatformDetection.IsLinux) - { - if (PlatformDetection.IsX86) - { - return new[] - { - "http://ffmpeg.gusari.org/static/32bit/ffmpeg.static.32bit.latest.tar.gz", - "https://github.com/MediaBrowser/MediaBrowser.Resources/raw/master/ffmpeg/linux/ffmpeg.static.32bit.2014-07-16.tar.gz" - }; - } - - if (PlatformDetection.IsX86_64) - { - return new[] - { - "http://ffmpeg.gusari.org/static/64bit/ffmpeg.static.64bit.latest.tar.gz", - "https://github.com/MediaBrowser/MediaBrowser.Resources/raw/master/ffmpeg/linux/ffmpeg.static.64bit.2014-07-16.tar.gz" - }; - } - - } - - // No Unix version available - return new string[] { }; - - default: - throw new ApplicationException("No ffmpeg download available for " + pid); - } - } - } - - public static class PlatformDetection - { - public readonly static bool IsWindows; - public readonly static bool IsMac; - public readonly static bool IsLinux; - public readonly static bool IsX86; - public readonly static bool IsX86_64; - public readonly static bool IsArm; - - static PlatformDetection() - { - IsWindows = Path.DirectorySeparatorChar == '\\'; - - // Don't call uname on windows - if (!IsWindows) - { - var uname = GetUnixName(); - - var sysName = uname.sysname ?? string.Empty; - - IsMac = string.Equals(sysName, "Darwin", StringComparison.OrdinalIgnoreCase); - IsLinux = string.Equals(sysName, "Linux", StringComparison.OrdinalIgnoreCase); - - var archX86 = new Regex("(i|I)[3-6]86"); - IsX86 = archX86.IsMatch(uname.machine); - IsX86_64 = !IsX86 && uname.machine == "x86_64"; - IsArm = !IsX86 && !IsX86_64 && uname.machine.StartsWith("arm"); - } - else - { - if (Environment.Is64BitOperatingSystem) - IsX86_64 = true; - else - IsX86 = true; - } - } - - private static Uname GetUnixName() - { - var uname = new Uname(); - Utsname utsname; - var callResult = Syscall.uname(out utsname); - if (callResult == 0) - { - uname.sysname = utsname.sysname; - uname.machine = utsname.machine; - } - return uname; - } - } - - public class Uname - { - public string sysname = string.Empty; - public string machine = string.Empty; - } -}
\ No newline at end of file diff --git a/MediaBrowser.ServerApplication/FFMpeg/FFMpegDownloader.cs b/MediaBrowser.ServerApplication/FFMpeg/FFMpegDownloader.cs deleted file mode 100644 index 7af8546ab0..0000000000 --- a/MediaBrowser.ServerApplication/FFMpeg/FFMpegDownloader.cs +++ /dev/null @@ -1,416 +0,0 @@ -using MediaBrowser.Common.Configuration; -using MediaBrowser.Common.IO; -using MediaBrowser.Common.Net; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Logging; -using MediaBrowser.Model.Net; -using MediaBrowser.ServerApplication.IO; -using Mono.Unix.Native; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace MediaBrowser.ServerApplication.FFMpeg -{ - public class FFMpegDownloader - { - private readonly IHttpClient _httpClient; - private readonly IApplicationPaths _appPaths; - private readonly ILogger _logger; - private readonly IZipClient _zipClient; - private readonly IFileSystem _fileSystem; - - private readonly string[] _fontUrls = - { - "https://github.com/MediaBrowser/MediaBrowser.Resources/raw/master/ffmpeg/ARIALUNI.7z" - }; - - public FFMpegDownloader(ILogger logger, IApplicationPaths appPaths, IHttpClient httpClient, IZipClient zipClient, IFileSystem fileSystem) - { - _logger = logger; - _appPaths = appPaths; - _httpClient = httpClient; - _zipClient = zipClient; - _fileSystem = fileSystem; - } - - public async Task<FFMpegInfo> GetFFMpegInfo(StartupOptions options, IProgress<double> progress) - { - var customffMpegPath = options.GetOption("-ffmpeg"); - var customffProbePath = options.GetOption("-ffprobe"); - - if (!string.IsNullOrWhiteSpace(customffMpegPath) && !string.IsNullOrWhiteSpace(customffProbePath)) - { - return new FFMpegInfo - { - ProbePath = customffProbePath, - EncoderPath = customffMpegPath, - Version = "custom" - }; - } - - var version = FFMpegDownloadInfo.Version; - - if (string.Equals(version, "path", StringComparison.OrdinalIgnoreCase)) - { - return new FFMpegInfo - { - ProbePath = FFMpegDownloadInfo.FFProbeFilename, - EncoderPath = FFMpegDownloadInfo.FFMpegFilename, - Version = version - }; - } - - var rootEncoderPath = Path.Combine(_appPaths.ProgramDataPath, "ffmpeg"); - var versionedDirectoryPath = Path.Combine(rootEncoderPath, version); - - var info = new FFMpegInfo - { - ProbePath = Path.Combine(versionedDirectoryPath, FFMpegDownloadInfo.FFProbeFilename), - EncoderPath = Path.Combine(versionedDirectoryPath, FFMpegDownloadInfo.FFMpegFilename), - Version = version - }; - - Directory.CreateDirectory(versionedDirectoryPath); - - var excludeFromDeletions = new List<string> { versionedDirectoryPath }; - - if (!File.Exists(info.ProbePath) || !File.Exists(info.EncoderPath)) - { - // ffmpeg not present. See if there's an older version we can start with - var existingVersion = GetExistingVersion(info, rootEncoderPath); - - // No older version. Need to download and block until complete - if (existingVersion == null) - { - await DownloadFFMpeg(versionedDirectoryPath, progress).ConfigureAwait(false); - } - else - { - // Older version found. - // Start with that. Download new version in the background. - var newPath = versionedDirectoryPath; - Task.Run(() => DownloadFFMpegInBackground(newPath)); - - info = existingVersion; - versionedDirectoryPath = Path.GetDirectoryName(info.EncoderPath); - - excludeFromDeletions.Add(versionedDirectoryPath); - } - } - - await DownloadFonts(versionedDirectoryPath).ConfigureAwait(false); - - DeleteOlderFolders(Path.GetDirectoryName(versionedDirectoryPath), excludeFromDeletions); - - return info; - } - - private void DeleteOlderFolders(string path, IEnumerable<string> excludeFolders ) - { - var folders = Directory.GetDirectories(path) - .Where(i => !excludeFolders.Contains(i, StringComparer.OrdinalIgnoreCase)) - .ToList(); - - foreach (var folder in folders) - { - DeleteFolder(folder); - } - } - - private void DeleteFolder(string path) - { - try - { - Directory.Delete(path, true); - } - catch (Exception ex) - { - _logger.ErrorException("Error deleting {0}", ex, path); - } - } - - private FFMpegInfo GetExistingVersion(FFMpegInfo info, string rootEncoderPath) - { - var encoderFilename = Path.GetFileName(info.EncoderPath); - var probeFilename = Path.GetFileName(info.ProbePath); - - foreach (var directory in Directory.EnumerateDirectories(rootEncoderPath, "*", SearchOption.TopDirectoryOnly) - .ToList()) - { - var allFiles = Directory.EnumerateFiles(directory, "*", SearchOption.AllDirectories).ToList(); - - var encoder = allFiles.FirstOrDefault(i => string.Equals(Path.GetFileName(i), encoderFilename, StringComparison.OrdinalIgnoreCase)); - var probe = allFiles.FirstOrDefault(i => string.Equals(Path.GetFileName(i), probeFilename, StringComparison.OrdinalIgnoreCase)); - - if (!string.IsNullOrWhiteSpace(encoder) && - !string.IsNullOrWhiteSpace(probe)) - { - return new FFMpegInfo - { - EncoderPath = encoder, - ProbePath = probe, - Version = Path.GetFileName(Path.GetDirectoryName(probe)) - }; - } - } - - return null; - } - - private async void DownloadFFMpegInBackground(string directory) - { - try - { - await DownloadFFMpeg(directory, new Progress<double>()).ConfigureAwait(false); - } - catch (Exception ex) - { - _logger.ErrorException("Error downloading ffmpeg", ex); - } - } - - private async Task DownloadFFMpeg(string directory, IProgress<double> progress) - { - foreach (var url in FFMpegDownloadInfo.GetDownloadUrls()) - { - progress.Report(0); - - try - { - var tempFile = await _httpClient.GetTempFile(new HttpRequestOptions - { - Url = url, - CancellationToken = CancellationToken.None, - Progress = progress - - }).ConfigureAwait(false); - - ExtractFFMpeg(tempFile, directory); - return; - } - catch (Exception ex) - { - _logger.ErrorException("Error downloading {0}", ex, url); - } - } - - throw new ApplicationException("Unable to download required components. Please try again later."); - } - - private void ExtractFFMpeg(string tempFile, string targetFolder) - { - _logger.Info("Extracting ffmpeg from {0}", tempFile); - - var tempFolder = Path.Combine(_appPaths.TempDirectory, Guid.NewGuid().ToString()); - - Directory.CreateDirectory(tempFolder); - - try - { - ExtractArchive(tempFile, tempFolder); - - var files = Directory.EnumerateFiles(tempFolder, "*", SearchOption.AllDirectories).ToList(); - - foreach (var file in files.Where(i => - { - var filename = Path.GetFileName(i); - - return - string.Equals(filename, FFMpegDownloadInfo.FFProbeFilename, StringComparison.OrdinalIgnoreCase) || - string.Equals(filename, FFMpegDownloadInfo.FFMpegFilename, StringComparison.OrdinalIgnoreCase); - })) - { - File.Copy(file, Path.Combine(targetFolder, Path.GetFileName(file)), true); - - SetFilePermissions(targetFolder, file); - } - } - finally - { - DeleteFile(tempFile); - } - } - - private void SetFilePermissions(string targetFolder, string file) - { - // Linux: File permission to 666, and user's execute bit - if (Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX) - { - Syscall.chmod(Path.Combine(targetFolder, Path.GetFileName(file)), FilePermissions.DEFFILEMODE | FilePermissions.S_IXUSR); - } - } - - private void ExtractArchive(string archivePath, string targetPath) - { - _logger.Info("Extracting {0} to {1}", archivePath, targetPath); - - if (string.Equals(FFMpegDownloadInfo.ArchiveType, "7z", StringComparison.OrdinalIgnoreCase)) - { - _zipClient.ExtractAllFrom7z(archivePath, targetPath, true); - } - else if (string.Equals(FFMpegDownloadInfo.ArchiveType, "gz", StringComparison.OrdinalIgnoreCase)) - { - _zipClient.ExtractAllFromTar(archivePath, targetPath, true); - } - } - private void Extract7zArchive(string archivePath, string targetPath) - { - _logger.Info("Extracting {0} to {1}", archivePath, targetPath); - - _zipClient.ExtractAllFrom7z(archivePath, targetPath, true); - } - - private void DeleteFile(string path) - { - try - { - File.Delete(path); - } - catch (IOException ex) - { - _logger.ErrorException("Error deleting temp file {0}", ex, path); - } - } - - /// <summary> - /// Extracts the fonts. - /// </summary> - /// <param name="targetPath">The target path.</param> - /// <returns>Task.</returns> - private async Task DownloadFonts(string targetPath) - { - try - { - var fontsDirectory = Path.Combine(targetPath, "fonts"); - - Directory.CreateDirectory(fontsDirectory); - - const string fontFilename = "ARIALUNI.TTF"; - - var fontFile = Path.Combine(fontsDirectory, fontFilename); - - if (File.Exists(fontFile)) - { - await WriteFontConfigFile(fontsDirectory).ConfigureAwait(false); - } - else - { - // Kick this off, but no need to wait on it - Task.Run(async () => - { - await DownloadFontFile(fontsDirectory, fontFilename, new Progress<double>()).ConfigureAwait(false); - - await WriteFontConfigFile(fontsDirectory).ConfigureAwait(false); - }); - } - } - catch (HttpException ex) - { - // Don't let the server crash because of this - _logger.ErrorException("Error downloading ffmpeg font files", ex); - } - catch (Exception ex) - { - // Don't let the server crash because of this - _logger.ErrorException("Error writing ffmpeg font files", ex); - } - } - - /// <summary> - /// Downloads the font file. - /// </summary> - /// <param name="fontsDirectory">The fonts directory.</param> - /// <param name="fontFilename">The font filename.</param> - /// <returns>Task.</returns> - private async Task DownloadFontFile(string fontsDirectory, string fontFilename, IProgress<double> progress) - { - var existingFile = Directory - .EnumerateFiles(_appPaths.ProgramDataPath, fontFilename, SearchOption.AllDirectories) - .FirstOrDefault(); - - if (existingFile != null) - { - try - { - File.Copy(existingFile, Path.Combine(fontsDirectory, fontFilename), true); - return; - } - catch (IOException ex) - { - // Log this, but don't let it fail the operation - _logger.ErrorException("Error copying file", ex); - } - } - - string tempFile = null; - - foreach (var url in _fontUrls) - { - progress.Report(0); - - try - { - tempFile = await _httpClient.GetTempFile(new HttpRequestOptions - { - Url = url, - Progress = progress - - }).ConfigureAwait(false); - - break; - } - catch (Exception ex) - { - // The core can function without the font file, so handle this - _logger.ErrorException("Failed to download ffmpeg font file from {0}", ex, url); - } - } - - if (string.IsNullOrEmpty(tempFile)) - { - return; - } - - Extract7zArchive(tempFile, fontsDirectory); - - try - { - File.Delete(tempFile); - } - catch (IOException ex) - { - // Log this, but don't let it fail the operation - _logger.ErrorException("Error deleting temp file {0}", ex, tempFile); - } - } - - /// <summary> - /// Writes the font config file. - /// </summary> - /// <param name="fontsDirectory">The fonts directory.</param> - /// <returns>Task.</returns> - private async Task WriteFontConfigFile(string fontsDirectory) - { - const string fontConfigFilename = "fonts.conf"; - var fontConfigFile = Path.Combine(fontsDirectory, fontConfigFilename); - - if (!File.Exists(fontConfigFile)) - { - var contents = string.Format("<?xml version=\"1.0\"?><fontconfig><dir>{0}</dir><alias><family>Arial</family><prefer>Arial Unicode MS</prefer></alias></fontconfig>", fontsDirectory); - - var bytes = Encoding.UTF8.GetBytes(contents); - - using (var fileStream = _fileSystem.GetFileStream(fontConfigFile, FileMode.Create, FileAccess.Write, - FileShare.Read, true)) - { - await fileStream.WriteAsync(bytes, 0, bytes.Length); - } - } - } - } -} diff --git a/MediaBrowser.ServerApplication/FFMpeg/FFMpegInfo.cs b/MediaBrowser.ServerApplication/FFMpeg/FFMpegInfo.cs deleted file mode 100644 index 1361277aac..0000000000 --- a/MediaBrowser.ServerApplication/FFMpeg/FFMpegInfo.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace MediaBrowser.ServerApplication.FFMpeg -{ - /// <summary> - /// Class FFMpegInfo - /// </summary> - public class FFMpegInfo - { - /// <summary> - /// Gets or sets the path. - /// </summary> - /// <value>The path.</value> - public string EncoderPath { get; set; } - /// <summary> - /// Gets or sets the probe path. - /// </summary> - /// <value>The probe path.</value> - public string ProbePath { get; set; } - /// <summary> - /// Gets or sets the version. - /// </summary> - /// <value>The version.</value> - public string Version { get; set; } - } -}
\ No newline at end of file |
