tags:

views:

322

answers:

2

This is actually related to another question I had that was already answered. That question is here: Redirecting stdout of one process object to stdin of another

My issue is (I think) that the program who is getting the input should exit before the program outputting. Here is the bash equivalent of what I'm doing: tccat -i /dev/sr0 -T 1 | ffmpeg -i - -r 1 -t 1 -s 96x72 -ss 5 /tmp/wsmanage/preview_tmp/test\%03d.jpg

This just uses a program called tccat to read the first title of a dvd. That gets output to ffmpeg, which is going to create an output file at 1 frame per second that is 1 second long in .jpg format. As soon as it outputs its frame (or two) it exists. This works fine.

The following code, however, does not. I get scads of "Printing line to ffmpeg", whereas the command line version exits in just over a second. Then, it just stops printing after 30 or 40 seconds or so. FFmpeg never exits, and my program never continues.

I'm I doing this right?

Process tccatProcess = new Process();   
tccatProcess.StartInfo.FileName = "tccat";
tccatProcess.StartInfo.Arguments = String.Format("-i {0} -T {1}", devNode, title);
tccatProcess.StartInfo.UseShellExecute = false;
tccatProcess.StartInfo.RedirectStandardOutput = true;

Process ffmpegProcess = new Process();
string bashSafePreviewTemplate = slasher.bashSlash(previewTempDir + "/test%03d.jpg");
ffmpegProcess.StartInfo.FileName = "ffmpeg";
ffmpegProcess.StartInfo.Arguments = String.Format("-i - -r 1 -t 1 -s {1}x{2} -ss {3} {0}", 
 bashSafePreviewTemplate, width, height, timePosition);
ffmpegProcess.StartInfo.UseShellExecute = false;
ffmpegProcess.StartInfo.RedirectStandardInput = true;


try{
 tccatProcess.Start();
 ffmpegProcess.Start();

 StreamReader tccatOutput = tccatProcess.StandardOutput;
 StreamWriter ffmpegInput = ffmpegProcess.StandardInput;

 string line;
 while(!ffmpegProcess.HasExited)
 {
  ffmpegProcess.Refresh();
  if((line = tccatOutput.ReadLine()) != null)
  {
   Console.WriteLine("Printing line to ffmpeg");
   Console.Out.Flush();
   ffmpegInput.WriteLine(line);
   ffmpegInput.Flush();
  }
 }

 Console.WriteLine("Closing tccat");
 Console.Out.Flush();
 tccatProcess.Close();
 Console.WriteLine("Tccat closed");
 Console.Out.Flush();


}catch(Exception e){
 //uninteresting log code
 return false;
}
A: 

Doesn't tccat output binary data since you're working with video and images? If so shouldn't you be reading/writing to the input/output streams directly rather than wrapping them in a text reader?

If so you want to be using http://stackoverflow.com/questions/1284184/can-i-put-binary-in-stdin-c/1284753#1284753

KeeperOfTheSoul
Ah, this may be my problem. I didn't realize that streamreader/streamwriter were not binary safe. I'll try this as soon as I can and post back with the results! Thanks for the link also. I see just what I need to do. Even if this isn't my only problem, I can see it's definitly something that needs to be fixed.
Lytithwyn
That was it! Thanks!
Lytithwyn
A: 

For anyone who wants to do something similar, here is the new version with KeeperOfTheSoul's advice applied:

  Process tccatProcess = new Process();   
  tccatProcess.StartInfo.FileName = "tccat";
  tccatProcess.StartInfo.Arguments = String.Format("-i {0} -T {1}", devNode, title);
  tccatProcess.StartInfo.UseShellExecute = false;
  tccatProcess.StartInfo.RedirectStandardOutput = true;

  Process ffmpegProcess = new Process();
  string bashSafePreviewTemplate = slasher.bashSlash(previewTempDir + "/test%03d.jpg");
  ffmpegProcess.StartInfo.FileName = "ffmpeg";
  ffmpegProcess.StartInfo.Arguments = String.Format("-i - -r 1 -t 1 -s {1}x{2} -ss {3} {0}", 
   bashSafePreviewTemplate, width, height, timePosition);
  ffmpegProcess.StartInfo.UseShellExecute = false;
  ffmpegProcess.StartInfo.RedirectStandardInput = true;

  Console.WriteLine("tccat command: {0} {1}", tccatProcess.StartInfo.FileName, tccatProcess.StartInfo.Arguments);
  Console.WriteLine("ffmpeg command: {0} {1}", ffmpegProcess.StartInfo.FileName, ffmpegProcess.StartInfo.Arguments);

  //return true;

  try{
   tccatProcess.Start();
   ffmpegProcess.Start();

   BinaryReader tccatOutput = new BinaryReader(tccatProcess.StandardOutput.BaseStream);
   BinaryWriter ffmpegInput = new BinaryWriter(ffmpegProcess.StandardInput.BaseStream);
   int buffSize = 4096;
   byte[] buff = new byte[buffSize];


   while(!ffmpegProcess.HasExited)
   {
    ffmpegProcess.Refresh();
    buff = tccatOutput.ReadBytes(buffSize);
    ffmpegInput.Write(buff);
    ffmpegInput.Flush();
   }


   tccatProcess.Kill();
   tccatProcess.Close();
   ffmpegProcess.Close();


  }catch(Exception e){
           //uninteresting log code
                    return false;

  }
Lytithwyn