6

I want to get the video file duration in string using C#. I searched the internet and all i get is:

ffmpeg -i inputfile.avi

And every1 say that parse the output for duration.

Here is my code which is

string filargs = "-y -i " + inputavi + " -ar 22050 " + outputflv;
    Process proc;
    proc = new Process();
    proc.StartInfo.FileName = spath;
    proc.StartInfo.Arguments = filargs;
    proc.StartInfo.UseShellExecute = false;
    proc.StartInfo.CreateNoWindow = false;
    proc.StartInfo.RedirectStandardOutput = false;
    try
    {
        proc.Start();

    }
    catch (Exception ex)
    {
        Response.Write(ex.Message);
    }

    try
    {
        proc.WaitForExit(50 * 1000);
    }
    catch (Exception ex)
    { }
    finally
    {
        proc.Close();
    }

Now please tell me how can i save the output string and parse it for the video duration.

Thanks and regards,

one noa
  • 345
  • 1
  • 3
  • 10
Hamad
  • 161
  • 1
  • 3
  • 7

3 Answers3

7

There is another Option to get Video Length ,by using Media Info DLL

Using Ffmpeg :

proc.StartInfo.RedirectErrorOutput = true;
string message = proc.ErrorOutput.ReadToEnd();

Filtering shouldn't be an issue ,so do it you're self.

PS : using ffmpeg you should not read the StandardOutput but ErrorOutput i dont know why ,but it work's only like that.

Rosmarine Popcorn
  • 10,761
  • 11
  • 59
  • 89
  • Thanks man your code didnt work instead i used following code: 'proc.StartInfo.RedirectStandardError = true; string message = proc.StandardError.ReadToEnd();' But thanks anyway, you showed me the first step, which eventually turn out well for for me. Stay Blesses!!! – Hamad Jun 24 '11 at 12:51
5

FFmpeg is a little bit of an adventure to parse. But in any case, here's what you need to know.

First, FFmpeg doesn't play well with RedirectOutput options

What you'll need to do is instead of launching ffmpeg directly, launch cmd.exe, passing in ffmpeg as an argument, and redirecting the output to a "monitor file" through a command line output like so... note that in the while (!proc.HasExited) loop you can read this file for real-time FFmpeg status, or just read it at the end if this is a quick operation.

        FileInfo monitorFile = new FileInfo(Path.Combine(ffMpegExe.Directory.FullName, "FFMpegMonitor_" + Guid.NewGuid().ToString() + ".txt"));

        string ffmpegpath = Environment.SystemDirectory + "\\cmd.exe"; 
        string ffmpegargs = "/C " + ffMpegExe.FullName + " " + encodeArgs + " 2>" + monitorFile.FullName;

        string fullTestCmd = ffmpegpath + " " + ffmpegargs;

        ProcessStartInfo psi = new ProcessStartInfo(ffmpegpath, ffmpegargs);
        psi.WorkingDirectory = ffMpegExe.Directory.FullName;
        psi.CreateNoWindow = true;
        psi.UseShellExecute = false;
        psi.Verb = "runas";

        var proc = Process.Start(psi);

        while (!proc.HasExited)
        {
            System.Threading.Thread.Sleep(1000);
        }

        string encodeLog = System.IO.File.ReadAllText(monitorFile.FullName);

Great, now you've got the log of what FFmpeg just spit out. Now to get the duration. The duration line will look something like this:

Duration: 00:10:53.79, start: 0.000000, bitrate: 9963 kb/s

Clean up the results into a List<string>:

var encodingLines = encodeLog.Split(System.Environment.NewLine[0]).Where(line => string.IsNullOrWhiteSpace(line) == false && string.IsNullOrEmpty(line.Trim()) == false).Select(s => s.Trim()).ToList();

... then loop through them looking for Duration.

        foreach (var line in encodingLines)
        {
            // Duration: 00:10:53.79, start: 0.000000, bitrate: 9963 kb/s
            if (line.StartsWith("Duration"))
            {
                var duration = ParseDurationLine(line);
            }
        }

Here's some code that can do the parse for you:

    private TimeSpan ParseDurationLine(string line)
    {
        var itemsOfData = line.Split(" "[0], "="[0]).Where(s => string.IsNullOrEmpty(s) == false).Select(s => s.Trim().Replace("=", string.Empty).Replace(",", string.Empty)).ToList();

        string duration = GetValueFromItemData(itemsOfData, "Duration:");

        return TimeSpan.Parse(duration);
    }

    private string GetValueFromItemData(List<string> items, string targetKey)
    {
        var key = items.FirstOrDefault(i => i.ToUpper() == targetKey.ToUpper());

        if (key == null) { return null; }
        var idx = items.IndexOf(key);

        var valueIdx = idx + 1;

        if (valueIdx >= items.Count)
        {
            return null;
        }

        return items[valueIdx];
    }
Brandon
  • 13,956
  • 16
  • 72
  • 114
  • Sorry dude! I am unable to understand your code. Where will my inputavi file will fit in of which i want to find the duration??? Also explain the variables u hav used e.g., "encodeArgs" What is it. – Hamad Jun 24 '11 at 04:55
  • your code is working fine which shows info about ffmpeg when used ffmpeg as input. How can i use this to send my avi file as input and get its info??? Thanks Anyways. Yu are doing great – Hamad Jun 24 '11 at 05:24
  • What if there is a metadata with name Duration and Value "00:00:00"? Security is not perfect – Roman Holzner Jul 11 '14 at 11:05
1

Just check it out::

    //Create varriables

    string ffMPEG = System.IO.Path.Combine(Application.StartupPath, "ffMPEG.exe");
    system.Diagnostics.Process mProcess = null;

    System.IO.StreamReader SROutput = null;
    string outPut = "";

    string filepath = "D:\\source.mp4";
    string param = string.Format("-i \"{0}\"", filepath);

    System.Diagnostics.ProcessStartInfo oInfo = null;

    System.Text.RegularExpressions.Regex re = null;
    System.Text.RegularExpressions.Match m = null;
    TimeSpan Duration =  null;

    //Get ready with ProcessStartInfo
    oInfo = new System.Diagnostics.ProcessStartInfo(ffMPEG, param);
    oInfo.CreateNoWindow = true;

    //ffMPEG uses StandardError for its output.
    oInfo.RedirectStandardError = true;
    oInfo.WindowStyle = ProcessWindowStyle.Hidden;
    oInfo.UseShellExecute = false;

    // Lets start the process

    mProcess = System.Diagnostics.Process.Start(oInfo);

    // Divert output
    SROutput = mProcess.StandardError;

    // Read all
    outPut = SROutput.ReadToEnd();

    // Please donot forget to call WaitForExit() after calling SROutput.ReadToEnd

    mProcess.WaitForExit();
    mProcess.Close();
    mProcess.Dispose();
    SROutput.Close();
    SROutput.Dispose();

    //get duration

    re = new System.Text.RegularExpressions.Regex("[D|d]uration:.((\\d|:|\\.)*)");
    m = re.Match(outPut);

    if (m.Success) {
        //Means the output has cantained the string "Duration"
        string temp = m.Groups(1).Value;
        string[] timepieces = temp.Split(new char[] {':', '.'});
        if (timepieces.Length == 4) {

            // Store duration
            Duration = new TimeSpan(0, Convert.ToInt16(timepieces[0]), Convert.ToInt16(timepieces[1]), Convert.ToInt16(timepieces[2]), Convert.ToInt16(timepieces[3]));
        }
    }

With thanks, Gouranga Das.