2

I am using ffmpeg commands with C# processes. I used a command to change the audio of a video and it was working but I also wanted to write the output to a text file. The new command works from cmd but apparently, it does not work while using a C# process. The command that does not work with the Process is:

ffmpeg -i videoPath -i audioPath -c:v copy -map 0:v:0 -map 1:a:0 -shortest newVideoPath > textFilePath 2>&1

And the working command is the same without the last part:

ffmpeg -i videoPath -i audioPath -c:v copy -map 0:v:0 -map 1:a:0 -shortest newVideoPath

Here is the C# code:

 Process proc = new Process();
 proc.StartInfo.FileName = ffmpegPath;
 proc.StartInfo.RedirectStandardError = true;
 proc.StartInfo.RedirectStandardOutput = true;
 proc.StartInfo.UseShellExecute = false;
 proc.StartInfo.CreateNoWindow = true;
 proc.StartInfo.Arguments = "-i " + videoPath + " -i " + newAudioPath + " -c:v copy" + " -map" + " 0:v:0 " + "-map 1:a:0 " + "-shortest " + newVideoPath + " > " + @"F:\Videos\log.txt"+ " 2>&1";
 proc.EnableRaisingEvents = true;
 proc.Exited += UpdateVideoSource;
 proc.Start();

I checked the arguments over and over again, and looked for missing spaces but nothing worked. What can be the problem?

Lifshitz
  • 23
  • 4

2 Answers2

2

ffmpeg has the option -report :

Dump full command line and log output to a file named program-YYYYMMDD-HHMMSS.log in the current directory.

By default, the file generated follow the parttern program-YYYYMMDD-HHMMSS.log. To specify a file, you can set the environnement variable variable FFREPORT :

FFREPORT=file=ffreport.log:level=verbose

In C#, you can start a process with a specific environnement variables by ProcessStartInfo.EnvironmentVariables :

Process proc = new Process();
proc.StartInfo.FileName = ffmpegPath;
proc.StartInfo.RedirectStandardError = false; // Don't redirect the output
proc.StartInfo.RedirectStandardOutput = false;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.CreateNoWindow = true;
//Add the argument -report
proc.StartInfo.Arguments = "-i " + videoPath + " -i " + newAudioPath + " -c:v copy" + " -map" + " 0:v:0 " + "-map 1:a:0 " + "-shortest " + newVideoPath + " -report";
//Set the output file and the log level
proc.StartInfo.EnvironmentVariables["FFREPORT"] = "file=ffreport.log:level=verbose";
proc.EnableRaisingEvents = true;
proc.Exited += UpdateVideoSource;
proc.Start();

I haven't tested, but this is good start.

vernou
  • 6,818
  • 5
  • 30
  • 58
  • Thank you very much! It works. I was almost decided to search for a different approach for my problem, but you saved me :) – Lifshitz Feb 04 '21 at 19:47
0

The function > is specific to cmd.

To redirect the process output to a file, you can redirect the output to the calling program that will write to a file :

void Redirect(StreamReader output, StreamWriter to)
{
    string textLine;
    while ((textLine = output.ReadLine()) == null)
    {
        to.WriteLine(textLine);
    }
}

using (Process proc = new Process())
{
    proc.StartInfo.FileName = ffmpegPath;
    proc.StartInfo.RedirectStandardError = true;
    proc.StartInfo.RedirectStandardOutput = true;
    proc.StartInfo.UseShellExecute = false;
    proc.StartInfo.CreateNoWindow = true;
    proc.StartInfo.Arguments = "-i " + videoPath + " -i " + newAudioPath + " -c:v copy" + " -map" + " 0:v:0 " + "-map 1:a:0 " + "-shortest";
    proc.EnableRaisingEvents = true;
    proc.Exited += UpdateVideoSource;
    proc.Start();

    using (StreamWriter writer = File.CreateText(@"F:\Videos\log.txt"))
    {
        //Redirect standard and error ouput
        var standardOutputThread = new Thread(new ThreadStart(() => Redirect(proc.StandardOutput, writer)));
        var errorOutputThread = new Thread(new ThreadStart(() => Redirect(proc.StandardError, writer)));
        //Start redirect thread
        standardOutputThread.Start();
        errorOutputThread.Start();
        //Wait the end of redirection
        standardOutputThread.Join();
        errorOutputThread.Join();
    }

    proc.WaitForExit();
}
vernou
  • 6,818
  • 5
  • 30
  • 58
  • Thank you for answering. I used your solution - what happened was that the command worked but the text file stayed empty. /: – Lifshitz Feb 03 '21 at 17:37
  • Maybe the output stream doesn't connect to the cmd output and therefore there is no output? – Lifshitz Feb 03 '21 at 17:38
  • @Lifshitz, you can set the log level to debug to force some output : `-loglevel debug`. – vernou Feb 04 '21 at 09:22
  • @Sinatr, Thread is need because the program follow two stream (standard and error). – vernou Feb 04 '21 at 10:44
  • 1
    [Process.Start](https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.process.start?view=net-5.0#System_Diagnostics_Process_Start) just start the process, it don't wait the end. The link in your comment don't respect the output order. – vernou Feb 04 '21 at 14:17
  • My bad, forgot there is a dedicated method which you already call at the end. – Sinatr Feb 04 '21 at 15:12