Getting the audio waveform data of media file using ffmpeg.exe in C#
Previously, I use the NAudio library to implement this function. It needs to extract the audio track of a media file to a separate WAV file to deal with. Even with the help of RAM disk, the processing speed is still very slow.

Yesterday, I searched again for the usable audio processing library in C#. But there is still no better choice. Finally, the popular cross-platform command line tools mencoder, ffmpeg and so on came into my head. The ffmpeg seems to work because it support stdout output.

At first, I tried to output the binary stream in WAV format to stdout. But I found that in this situation, ffmpeg will write a placeholder for size information in head, and seek back to rewrite it after the whole stream is outputed (source). When the output target is the stdout stream instead of a file, this rewriting operation will fail, which causes the obtained WAV stream to have wrong head information and cannot be used.

The reason that I use WAV format is just because it is the most familiar audio format that storing raw waveform data. But after read the documentation of ffmpeg, I found that it supports a great many formats. It can output integers or floats directly, without head information. At last I selected the little endian 32-bit float format.

The complete code is as follows:

  1. using System.Diagnostics;
  2. using System.IO;
  3.  
  4. // ...
  5.  
  6. static void Main(string[] args)
  7. {
  8.     // ...
  9.     string path = @"E:\Media\test.mp4";
  10.  
  11.     Process proc = new Process();
  12.     proc.StartInfo.FileName = @"E:\ffmpeg\ffmpeg.exe";
  13.     proc.StartInfo.Arguments = "-i \"" + path + "\" -vn -ar 44100 -ac 1 -f f32le -";
  14.     proc.StartInfo.CreateNoWindow = true;
  15.     proc.StartInfo.UseShellExecute = false;
  16.     proc.StartInfo.RedirectStandardOutput = true;
  17.     proc.StartInfo.RedirectStandardError = true;
  18.     proc.ErrorDataReceived += new DataReceivedEventHandler(proc_ErrorDataReceived);
  19.     proc.Start();
  20.     proc.BeginErrorReadLine();
  21.     ProcessStream(proc.StandardOutput.BaseStream);
  22.  
  23.     proc.WaitForExit(10000); // 10s
  24.     if (!proc.HasExited)
  25.     {
  26.         proc.Kill();
  27.         Environment.Exit(1);
  28.     }
  29.     // ...
  30. }
  31.  
  32. static void proc_ErrorDataReceived(object sender, DataReceivedEventArgs e)
  33. {
  34.     if (e.Data != null)
  35.     {
  36.         // Console.WriteLine(e.Data);
  37.         // do nothing
  38.     }
  39. }
  40.  
  41. static void ProcessStream(Stream stream)
  42. {
  43.     int didread;
  44.     int offset = 0;
  45.     byte[] buffer = new byte[sizeof(Single) * (1024 + 1)];
  46.  
  47.     int length, residual_length;
  48.  
  49.     while ((didread = stream.Read(buffer, offset, sizeof(Single) * 1024)) != 0)
  50.     {
  51.         length = offset + didread;
  52.         residual_length = length % sizeof(Single);
  53.  
  54.         if (residual_length == 0) {
  55.             ProcessBuffer(buffer, length);
  56.             offset = 0;
  57.         } else {
  58.             length -= residual_length;
  59.             ProcessBuffer(buffer, length);
  60.             Array.Copy(buffer, length, buffer, 0, residual_length);
  61.             offset = residual_length;
  62.         }
  63.     }
  64. }
  65.  
  66. static void ProcessBuffer(byte[] buffer, int length)
  67. {
  68.     int index = 0;
  69.     float sample_value;
  70.  
  71.     while (index < length)
  72.     {
  73.         sample_value = BitConverter.ToSingle(buffer, index);
  74.         index += sizeof(Single);
  75.         // to deal with sample_value
  76.     }
  77. }
  78.  
  79. // ...
Current language: English · 其他语言: 中文 (简体)
3 Comments
gou9ping
Mon, 11 Apr 2016 15:28 +0800
你好!
请问下ffmpeg 如何计算出音频的分贝呢?
skygamer
Mon, 11 Dec 2017 18:26 +0800
Hello. I want to get waveform as stream for convert stream to image. I think your code what was i need. But i can't handle my image. I put a picturebox on my form. and want to show waveform on this picturebox.

can you help me please?
skygamer
Mon, 11 Dec 2017 19:14 +0800
how can i deal with sample_value for draw waveform on my picturebox? It's urgent. Please.
Leave a Comment
Name
(required)
E-mail
(required, will not be published)
Website
(optional)
Comment
A syntax system which is similar to wiki markup is available, see the guide