public bool ReMuxToMkv(string inputName, MediaInfo keep, string outputName) { if (keep == null) { return(ReMuxToMkv(inputName, outputName)); } // Verify correct data type Debug.Assert(keep.Parser == ToolType.MkvMerge); // Delete output file FileEx.DeleteFile(outputName); // Create the track number filters // The track numbers are reported by MkvMerge --identify, use the track.id values string videoTracks = keep.Video.Count > 0 ? $"--video-tracks {string.Join(",", keep.Video.Select(info => info.Id.ToString(CultureInfo.InvariantCulture)))} " : "--no-video "; string audioTracks = keep.Audio.Count > 0 ? $"--audio-tracks {string.Join(",", keep.Audio.Select(info => info.Id.ToString(CultureInfo.InvariantCulture)))} " : "--no-audio "; string subtitleTracks = keep.Subtitle.Count > 0 ? $"--subtitle-tracks {string.Join(",", keep.Subtitle.Select(info => info.Id.ToString(CultureInfo.InvariantCulture)))} " : "--no-subtitles "; // Remux tracks string snippets = Program.Options.TestSnippets ? Snippet : ""; string commandline = $"{MergeOptions} {snippets} --output \"{outputName}\" {videoTracks}{audioTracks}{subtitleTracks} \"{inputName}\""; int exitCode = Command(commandline); return(exitCode is 0 or 1); }
private bool ConvertToMkv(string inputName, string videoCodec, int videoQuality, string audioCodec, MediaInfo keep, MediaInfo reEncode, string outputName) { // Simple encoding of audio and video and passthrough of other tracks if (keep == null || reEncode == null) { return(ConvertToMkv(inputName, videoCodec, videoQuality, audioCodec, outputName)); } // Delete output file FileEx.DeleteFile(outputName); // Create an input and output map CreateFfMpegMap(videoCodec, videoQuality, audioCodec, keep, reEncode, out string input, out string output); // TODO: Error with some PGS subtitles // https://trac.ffmpeg.org/ticket/2622 // [matroska,webm @ 000001d77fb61ca0] Could not find codec parameters for stream 2 (Subtitle: hdmv_pgs_subtitle): unspecified size // Consider increasing the value for the 'analyzeduration' and 'probesize' options // Convert using map string snippet = Program.Options.TestSnippets ? Snippet : ""; string commandline = $"{GlobalOptions} -i \"{inputName}\" {OutputOptions} {snippet} {input} {output} -f matroska \"{outputName}\""; int exitCode = Command(commandline); return(exitCode == 0); }
public bool ExtractToFile(string inputName, int trackId, string outputName) { // Delete existing output file FileEx.DeleteFile(outputName); // Extract track to file string commandline = $"\"{inputName}\" tracks {ExtractOptions} {trackId}:\"{outputName}\""; int exitCode = Command(commandline); return(exitCode is 0 or 1); }
public bool ConvertToMkv(string inputName, string videoCodec, int videoQuality, string outputName) { // Delete output file FileEx.DeleteFile(outputName); // Encode video, copy audio and subtitle streams string snippet = Program.Options.TestSnippets ? Snippet : ""; string commandline = $"{GlobalOptions} -i \"{inputName}\" {OutputOptions} {snippet} -map 0 -c:v {videoCodec} -crf {videoQuality} -preset medium -c:a copy -c:s copy -f matroska \"{outputName}\""; int exitCode = Command(commandline); return(exitCode == 0); }
public bool RemoveMetadata(string inputName, string outputName) { // Delete output file FileEx.DeleteFile(outputName); // Remove all metadata using -map_metadata -1 string snippet = Program.Options.TestSnippets ? Snippet : ""; string commandline = $"{GlobalOptions} -i \"{inputName}\" {OutputOptions} {snippet} -map_metadata -1 -map 0 -c copy -f matroska \"{outputName}\""; int exitCode = Command(commandline); return(exitCode == 0); }
public bool ReMuxToMkv(string inputName, string outputName) { // Delete output file FileEx.DeleteFile(outputName); // Remux and copy all streams string snippet = Program.Options.TestSnippets ? Snippet : ""; string commandline = $"{GlobalOptions} -i \"{inputName}\" {OutputOptions} {snippet} -map 0 -codec copy -f matroska \"{outputName}\""; int exitCode = Command(commandline); return(exitCode == 0); }
public bool ConvertToMkv(string inputName, string videoCodec, int videoQuality, string outputName) { // Delete output file FileEx.DeleteFile(outputName); // Encode video, copy audio and subtitles string snippet = Program.Options.TestSnippets ? Snippet : ""; string commandline = $"--input \"{inputName}\" {snippet} --output \"{outputName}\" --format av_mkv --encoder {videoCodec} --encoder-preset medium --quality {videoQuality} --all-subtitles --all-audio --aencoder copy --audio-fallback {Program.Config.ConvertOptions.AudioEncodeCodec}"; int exitCode = Command(commandline); return(exitCode == 0); }
public bool ReMuxToMkv(string inputName, string outputName) { // Delete output file FileEx.DeleteFile(outputName); // Remux all string snippets = Program.Options.TestSnippets ? Snippet : ""; string commandline = $"{MergeOptions} {snippets} --output \"{outputName}\" \"{inputName}\""; int exitCode = Command(commandline); return(exitCode is 0 or 1); }
public bool DeInterlaceToMkv(string inputName, string videoCodec, int videoQuality, string outputName, bool includeSubtitles = true) { // Delete output file FileEx.DeleteFile(outputName); // Encode and decomb video, copy audio, and conditionally copy subtitles string snippet = Program.Options.TestSnippets ? Snippet : ""; string subtitles = includeSubtitles ? "--all-subtitles" : "--subtitle none"; string commandline = $"--input \"{inputName}\" {snippet} --output \"{outputName}\" --format av_mkv --encoder {videoCodec} --encoder-preset medium --quality {videoQuality} --comb-detect --decomb {subtitles} --all-audio --aencoder copy --audio-fallback {Program.Config.ConvertOptions.AudioEncodeCodec}"; int exitCode = Command(commandline); return(exitCode == 0); }
public bool RemoveClosedCaptions(string inputName, string outputName) { // Delete output file FileEx.DeleteFile(outputName); // Remove SEI NAL units, e.g. EIA-608, from video stream using -bsf:v "filter_units=remove_types=6" // https://ffmpeg.org/ffmpeg-bitstream-filters.html#filter_005funits string snippet = Program.Options.TestSnippets ? Snippet : ""; string commandline = $"{GlobalOptions} -i \"{inputName}\" {OutputOptions} {snippet} -map 0 -c copy -bsf:v \"filter_units=remove_types=6\" -f matroska \"{outputName}\""; int exitCode = Command(commandline); return(exitCode == 0); }
public static bool ReMuxToMkv(string inputName, MediaInfo keep, out string outputName) { if (inputName == null) { throw new ArgumentNullException(nameof(inputName)); } if (keep == null) { throw new ArgumentNullException(nameof(keep)); } // This only works on MKV files and MkvMerge MediaInfo types Debug.Assert(keep.Parser == MediaTool.ToolType.MkvMerge); Debug.Assert(MkvMergeTool.IsMkvFile(inputName)); // Match the logic in ConvertToMKV() // Test if (Program.Options.TestNoModify) { outputName = inputName; return(true); } // Create a temp filename based on the input name outputName = Path.ChangeExtension(inputName, ".mkv"); string tempName = Path.ChangeExtension(inputName, ".tmp"); // Remux keeping specific tracks Log.Logger.Information("ReMux using MkvMerge : {FileName}", inputName); if (!Tools.MkvMerge.ReMuxToMkv(inputName, keep, tempName)) { Log.Logger.Error("ReMux using MkvMerge failed : {FileName}", inputName); FileEx.DeleteFile(tempName); return(false); } // Rename the temp file to the output file if (!FileEx.RenameFile(tempName, outputName)) { return(false); } // If the input and output names are not the same, delete the input return(inputName.Equals(outputName, StringComparison.OrdinalIgnoreCase) || FileEx.DeleteFile(inputName)); }
public bool ReMuxToMkv(string inputName, MediaInfo keep, string outputName) { if (keep == null) { return(ReMuxToMkv(inputName, outputName)); } // Delete output file FileEx.DeleteFile(outputName); // Create an input and output map CreateFfMpegMap(keep, out string input, out string output); // Remux using map string snippet = Program.Options.TestSnippets ? Snippet : ""; string commandline = $"{GlobalOptions} -i \"{inputName}\" {OutputOptions} {snippet} {input} {output} -f matroska \"{outputName}\""; int exitCode = Command(commandline); return(exitCode == 0); }
public static bool DeInterlaceToMkvHandbrake(string inputName, out string outputName) { if (inputName == null) { throw new ArgumentNullException(nameof(inputName)); } // Match the logic in ConvertToMKV() // Test if (Program.Options.TestNoModify) { outputName = inputName; return(true); } // Create a temp filename based on the input name outputName = Path.ChangeExtension(inputName, ".mkv"); string tempName = Path.ChangeExtension(inputName, ".tmp"); // Deinterlace video using handbrake Log.Logger.Information("DeInterlace using HandBrake : {FileName}", inputName); if (!Tools.HandBrake.DeInterlaceToMkv(inputName, tempName)) { Log.Logger.Error("DeInterlace using HandBrake failed : {FileName}", inputName); FileEx.DeleteFile(tempName); return(false); } // Rename the temp file to the output file if (!FileEx.RenameFile(tempName, outputName)) { return(false); } // If the input and output names are not the same, delete the input return(inputName.Equals(outputName, StringComparison.OrdinalIgnoreCase) || FileEx.DeleteFile(inputName)); }
public static bool ConvertToMkvFfMpeg(string inputName, MediaInfo keep, MediaInfo reencode, out string outputName) { if (inputName == null) { throw new ArgumentNullException(nameof(inputName)); } // Match the logic in ReMuxToMKV() // Test if (Program.Options.TestNoModify) { outputName = inputName; return(true); } // Create a temp filename based on the input name outputName = Path.ChangeExtension(inputName, ".mkv"); string tempName = Path.ChangeExtension(inputName, ".tmp"); // Convert using ffmpeg Log.Logger.Information("ReEncode using FfMpeg : {FileName}", inputName); if (!Tools.FfMpeg.ConvertToMkv(inputName, keep, reencode, tempName)) { Log.Logger.Error("ReEncode using FfMpeg failed : {FileName}", inputName); FileEx.DeleteFile(tempName); return(false); } // Rename the temp file to the output file if (!FileEx.RenameFile(tempName, outputName)) { return(false); } // If the input and output names are not the same, delete the input return(inputName.Equals(outputName, StringComparison.OrdinalIgnoreCase) || FileEx.DeleteFile(inputName)); }
public bool ExtractToFiles(string inputName, MediaInfo extractTracks, out Dictionary <int, string> idToFileNames) { // Verify correct data type Debug.Assert(extractTracks.Parser == ToolType.MkvMerge); // Create the track ids and destination filenames using the input name and track ids // The track numbers are reported by MkvMerge --identify, use the track.id values idToFileNames = new Dictionary <int, string>(); StringBuilder output = new(); string outputFile; foreach (VideoInfo info in extractTracks.Video) { outputFile = $"{inputName}.Track_{info.Id}.video"; FileEx.DeleteFile(outputFile); idToFileNames[info.Id] = outputFile; output.Append($"{info.Id}:\"{outputFile}\" "); } foreach (AudioInfo info in extractTracks.Audio) { outputFile = $"{inputName}.Track_{info.Id}.audio"; FileEx.DeleteFile(outputFile); idToFileNames[info.Id] = outputFile; output.Append($"{info.Id}:\"{outputFile}\" "); } foreach (SubtitleInfo info in extractTracks.Subtitle) { outputFile = $"{inputName}.Track_{info.Id}.subtitle"; FileEx.DeleteFile(outputFile); idToFileNames[info.Id] = outputFile; output.Append($"{info.Id}:\"{outputFile}\" "); } // Extract string commandline = $"\"{inputName}\" tracks {ExtractOptions} {output}"; int exitCode = Command(commandline); return(exitCode is 0 or 1); }
public bool MergeToMkv(string sourceOne, MediaInfo keepOne, string sourceTwo, string outputName) { // Selectively merge tracks from sourceOne with all tracks in sourceTwo // Verify correct data type Debug.Assert(keepOne.Parser == ToolType.MkvMerge); // Delete output file FileEx.DeleteFile(outputName); // Create the track number filters // The track numbers are reported by MkvMerge --identify, use the track.id values string videoTracks = keepOne.Video.Count > 0 ? $"--video-tracks {string.Join(",", keepOne.Video.Select(info => info.Id.ToString(CultureInfo.InvariantCulture)))} " : "--no-video "; string audioTracks = keepOne.Audio.Count > 0 ? $"--audio-tracks {string.Join(",", keepOne.Audio.Select(info => info.Id.ToString(CultureInfo.InvariantCulture)))} " : "--no-audio "; string subtitleTracks = keepOne.Subtitle.Count > 0 ? $"--subtitle-tracks {string.Join(",", keepOne.Subtitle.Select(info => info.Id.ToString(CultureInfo.InvariantCulture)))} " : "--no-subtitles "; // Remux tracks string snippets = Program.Options.TestSnippets ? Snippet : ""; string commandline = $"{MergeOptions} {snippets} --output \"{outputName}\" {videoTracks}{audioTracks}{subtitleTracks} --no-chapters \"{sourceOne}\" \"{sourceTwo}\""; int exitCode = Command(commandline); return(exitCode is 0 or 1); }
public static bool ReMuxToMkv(string inputName, out string outputName) { if (inputName == null) { throw new ArgumentNullException(nameof(inputName)); } // Match the logic in ConvertToMKV() // Test if (Program.Options.TestNoModify) { outputName = inputName; return(true); } // Create a MKV and temp filename based on the input name outputName = Path.ChangeExtension(inputName, ".mkv"); string tempName = Path.ChangeExtension(inputName, ".tmp"); // MkvMerge and FfMpeg both have problems dealing with some AVI files, so we will try both // E.g. https://github.com/FFmpeg/FFmpeg/commit/8de1ee9f725aa3c550f425bd3120bcd95d5b2ea8 // E.g. https://github.com/mbunkus/mkvtoolnix/issues/2123 // Try MKV first Log.Logger.Information("ReMux using MkvMerge : {FileName}", inputName); if (!Tools.MkvMerge.ReMuxToMkv(inputName, tempName)) { // Failed, delete temp file FileEx.DeleteFile(tempName); // Cancel requested if (Program.IsCancelledError()) { return(false); } // Failed Log.Logger.Error("ReMux using MkvMerge failed : {FileName}", inputName); // Retry using FfMpeg Log.Logger.Information("ReMux using FfMpeg : {FileName}", inputName); if (!Tools.FfMpeg.ReMuxToMkv(inputName, tempName)) { // Failed, delete temp file FileEx.DeleteFile(tempName); // Cancel requested if (Program.IsCancelledError()) { return(false); } // Error Log.Logger.Error("ReMux using FfMpeg failed : {FileName}", inputName); return(false); } } // Rename the temp file to the output file if (!FileEx.RenameFile(tempName, outputName)) { return(false); } // If the input and output names are not the same, delete the input return(inputName.Equals(outputName, StringComparison.OrdinalIgnoreCase) || FileEx.DeleteFile(inputName)); }
public void DeleteFileThatDoesntExistTest() { // This should succeed (though print a Debug message). FileEx.DeleteFile(@"C:\Test\For\Invalid\File.txt"); }
private static Program Create(CommandLineOptions options, bool verifyTools) { // Load config from JSON if (!File.Exists(options.SettingsFile)) { Log.Logger.Error("Settings file not found : {SettingsFile}", options.SettingsFile); return(null); } Log.Logger.Information("Loading settings from : {SettingsFile}", options.SettingsFile); ConfigFileJsonSchema config = ConfigFileJsonSchema.FromFile(options.SettingsFile); // Compare the schema version if (config.SchemaVersion != ConfigFileJsonSchema.Version) { Log.Logger.Warning("Settings JSON schema mismatch : {SchemaVersion} != {Version}, {FileName}", config.SchemaVersion, ConfigFileJsonSchema.Version, options.SettingsFile); // Upgrade the file schema Log.Logger.Information("Writing upgraded settings file : {FileName}", options.SettingsFile); ConfigFileJsonSchema.ToFile(options.SettingsFile, config); } // Set the static options from the loaded settings Options = options; Config = config; // Set the FileEx options FileEx.Options.TestNoModify = Options.TestNoModify; FileEx.Options.RetryCount = config.MonitorOptions.FileRetryCount; FileEx.Options.RetryWaitTime = config.MonitorOptions.FileRetryWaitTime; // Set the FileEx Cancel object FileEx.Options.Cancel = CancelSource.Token; // Use log file if (!string.IsNullOrEmpty(options.LogFile)) { // Delete if not in append mode if (!options.LogAppend && !FileEx.DeleteFile(options.LogFile)) { Log.Logger.Error("Failed to clear the logfile : {LogFile}", options.LogFile); return(null); } // Recreate the logger with a file CreateLogger(options.LogFile); Log.Logger.Information("Logging output to : {LogFile}", options.LogFile); } // Log app and runtime version string appVersion = Assembly.GetExecutingAssembly().GetCustomAttribute <AssemblyInformationalVersionAttribute>()?.InformationalVersion; string runtimeVersion = Environment.Version.ToString(); Log.Logger.Information("Application Version : {AppVersion}, Runtime Version : {RuntimeVersion}", appVersion, runtimeVersion); // Verify tools if (verifyTools) { // Upgrade tools if auto update is enabled if (Config.ToolsOptions.AutoUpdate && !Tools.CheckForNewTools()) { return(null); } // Verify tools if (!Tools.VerifyTools()) { return(null); } } // Create program instance return(new Program()); }