tags:

views:

982

answers:

4

I'd like to be able to use FFmpeg to convert a video file from within my C# program. I know I can just call a shell command, but is there a better way?

The issue with invoking a command via the shell, is I'm not sure you could do things like a progress bar, etc... or could you?

If there isn't a way, can anyone suggest the best way to layout some framework for executing shell commands. Passing one big long string is very cumbersome atm.

+6  A: 

There's a wrapper library over FFmpeg for .NET.

Darin Dimitrov
"At present audio decoding and encoding are mature and video capabilities are in development (we currently have video decoding working but without synced audio yet)." I need audio working properly.
Dominic Bou-Samra
Sounds to me like they're on it, but it isn't there yet...
Abel
+2  A: 

How about writing a C++/CLI wrapper around ffmpeg's native interface and then calling your wrapper interface from your application?

Soo Wei Tan
The VC compiler does not support many C language constructs used in ffmpeg. The ffmpeg team is interested to see someone succeeds in porting the code to VC.
Sheng Jiang 蒋晟
+14  A: 

You can easily implement a progress bar if running ffmpeg. The output of ffmpeg while running is something like:

frame= 3366 fps=465 q=31.0 Lsize=    6474kB time=140.35 bitrate= 377.9kbits/s

And it is refreshed ~twice per second. You can parse that line and get the data you need to display the progress. When you run in the command line, you only see one line being updated all the time, but what ffmpeg does is to write the line followed by \r. That's why you don't see multiple lines. However, when using StreamReader.ReadLine() on the error output of the program, you get one line for every update.

Sample code to read the output follows. You would have to ignore any line that does not begins with 'frame', perhaps use BeginErrorReadLine()+ErrorDataReceived if you want reading lines to be asynchronous, etc., but you get the idea (I've actually tested it):

using System;
using System.Diagnostics;
using System.IO;

class Test {
        static void Main (string [] args)
        {
                Process proc = new Process ();
                proc.StartInfo.FileName = "ffmpeg";
                proc.StartInfo.Arguments = "-i " + args [0] + " " + args [1];
                proc.StartInfo.RedirectStandardError = true;
                proc.StartInfo.UseShellExecute = false;
                if (!proc.Start ()) {
                        Console.WriteLine ("Error starting");
                        return;
                }
                StreamReader reader = proc.StandardError;
                string line;
                while ((line = reader.ReadLine ()) != null) {
                        Console.WriteLine (line);
                }
                proc.Close ();
        }
}
Gonzalo
Ahh... I've been trying to redirect to standardOutput... not error. It suddenly works :P
Dominic Bou-Samra
+1: I've done the same thing in Java and am very, very pleased with the results. There are a few catches, though: like the `time` value, can be something like 100000000 int the progress line output for the first update. My gut says it is an internal initialized value.
Stu Thompson
Probably yeah. Just use a predicate statement to eliminate values above a certain reasonable range. Dirty, but it'll work
Dominic Bou-Samra
+1  A: 

I just found fflib at sourceforge. Looks pretty promising, haven't used it though.

Vinz