Ejemplo n.º 1
0
    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);
    }
Ejemplo n.º 2
0
    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);
    }
Ejemplo n.º 3
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);
    }
Ejemplo n.º 4
0
    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);
    }
Ejemplo n.º 5
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);
    }
Ejemplo n.º 6
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);
    }
Ejemplo n.º 7
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);
    }
Ejemplo n.º 8
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);
    }
Ejemplo n.º 9
0
    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);
    }
Ejemplo n.º 10
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);
    }
Ejemplo n.º 11
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));
    }
Ejemplo n.º 12
0
    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);
    }
Ejemplo n.º 13
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));
    }
Ejemplo n.º 14
0
    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));
    }
Ejemplo n.º 15
0
    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);
    }
Ejemplo n.º 16
0
    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);
    }
Ejemplo n.º 17
0
    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));
    }
Ejemplo n.º 18
0
 public void DeleteFileThatDoesntExistTest()
 {
     // This should succeed (though print a Debug message).
     FileEx.DeleteFile(@"C:\Test\For\Invalid\File.txt");
 }
Ejemplo n.º 19
0
    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());
    }