How to convert audio to different formats using C# and FFmpeg

May 01, 2023
Written by
Reviewed by

How to convert audio to different formats using C# and FFmpeg

Working with audio and video can be a very daunting task if it's not your area of expertise. Luckily, there are some great tools that help you achieve difficult tasks with little media manipulation experience. In this tutorial, you'll learn how to use one of these tools, FFmpeg, to transcode audio from one format to another from a C# .NET application.

Prerequisites

Here’s what you will need to follow along:

You can find the source code for this tutorial on GitHub. Use it if you run into any issues, or submit an issue if you run into problems.

Set up FFmpeg

FFmpeg is a command-line interface (CLI) tool capable of decoding, encoding, transcoding, muxing, demuxing, streaming, filtering, and playing a large variety of media. FFmpeg is open source and supported across platforms.

To use it, you'll first need to download and install the binary. You can find some options to download FFmpeg for your operating system on the FFmpeg download page, but I'd recommend you check if FFmpeg is available in your preferred package manager and install it that way.

If you use a package manager, it's likely already installed in your system path. Verify your FFmpeg installation by running the following command:

ffmpeg -version

You should see output that looks like this:

ffmpeg version 5.1.1-1ubuntu2.1 Copyright (c) 2000-2022 the FFmpeg developers
built with gcc 12 (Ubuntu 12.2.0-3ubuntu1)
configuration: --prefix=/usr --extra-version=1ubuntu2.1 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --arch=amd64 --enable-gpl --disable-stripping --enable-gnutls --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcodec2 --enable-libdav1d --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libglslang --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librabbitmq --enable-librist --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libsrt --enable-libssh --enable-libsvtav1 --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzimg --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx --enable-openal --enable-opencl --enable-opengl --enable-sdl2 --disable-sndio --enable-pocketsphinx --enable-librsvg --enable-libmfx --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-chromaprint --enable-frei0r --enable-libx264 --enable-libplacebo --enable-shared
libavutil      57. 28.100 / 57. 28.100
libavcodec     59. 37.100 / 59. 37.100
libavformat    59. 27.100 / 59. 27.100
libavdevice    59.  7.100 / 59.  7.100
libavfilter     8. 44.100 /  8. 44.100
libswscale      6.  7.100 /  6.  7.100
libswresample   4.  7.100 /  4.  7.100
libpostproc    56.  6.100 / 56.  6.100

If you don't see output similar to this, locate the folder where the ffmpeg binary is stored, and add the path to that folder to your PATH variable.

While FFmpeg is capable of accomplishing many different tasks, however this tutorial will focus solely on changing audio from one format to another. For example, run the following command to download classic.mp3 and convert it to a wav-file:

ffmpeg -i https://demo.twilio.com/docs/classic.mp3 classic.wav

The -i options told ffmpeg where to find the input file, which was then followed by the output file; ./classic.wav on your disk. FFmpeg can detect the input file's format by analyzing it, and knows the format to transcode to because of the output file's .wav file extension. Enjoy the song, it's one of my favorites! 🕺

Convert audio files to different formats from .NET

Let's see how you can achieve the same task from .NET.

First, create a C# command-line project using the .NET CLI:

dotnet new console -o ConvertAudioFormats
cd ConvertAudioFormats

While you could interact with FFmpeg using the Process APIs or libraries like CliWrap, there's already a very helpful library that wraps the ffmpeg CLI for you: FFMpegCore.

Add the FFMpegCore NuGet package to your project using this command:

dotnet add package FFMpegCore

Now open the project in your preferred .NET IDE and update the Program.cs file with the following C#:

using FFMpegCore;

FFMpegArguments
    .FromUrlInput(new Uri("https://demo.twilio.com/docs/classic.mp3"))
    .OutputToFile("classic.wav")
    .ProcessSynchronously();

This code will do the same as the ffmpeg command you executed before, but the library makes it a lot more readable and self-explanatory.

Run the project using the .NET CLI:

dotnet run

After running the project, the classic.wav file should appear in your project directory.

If you're running the project from an IDE instead of the CLI, the classic.wav file will be located in the bin/Debug/netX.Y folder, where X and Y are the major and minor version numbers of the targeted .NET framework.

Awesome work!

Convert audio streams to different formats

If you don't want to pull the media directly from a URL or disk, you can also use FFmpeg's pipes to pass in data and receive data back without network or file I/O.

Let's recreate the same functionality using the FromPipeInput and OutputToPipe methods instead of the FromUrlInput and OutputToFile methods, by updating Program.cs as follows.

using FFMpegCore;
using FFMpegCore.Pipes;

using var httpClient = new HttpClient();
await using var audioInputStream = await httpClient.GetStreamAsync("https://demo.twilio.com/docs/classic.mp3");
await using var audioOutputStream = File.Open("classic.wav", FileMode.OpenOrCreate);

FFMpegArguments
    .FromPipeInput(new StreamPipeSource(audioInputStream))
    .OutputToPipe(new StreamPipeSink(audioOutputStream), options => 
        options.ForceFormat("wav"))
    .ProcessSynchronously();

The code above opens a network stream, audioInputStream, to stream the audio from the internet, and creates a file stream, audioOutputStream, to write the audio to. As you aren't passing an output file name directly to FFmpeg, FFmpeg cannot deduce the desired format, so you need to tell FFmpeg to use the wav format using options.ForceFormat("wav").

Run the project again:

dotnet run

The result should be the same. So what's the big deal? Well, if the default FromX and OutputToX methods don't fit your needs, using Stream's gives you the ultimate flexibility to provide input to FFmpeg and where to write the output to.

Next steps

You've just scratched the surfaces of what FFmpeg is capable of. There are a ton of extra arguments and capabilities to manipulate media files.

When building Twilio applications, FFmpeg can be a very useful tool too, for example, here's a tutorial that transcribes audio files sent through WhatsApp using the OpenAI Whisper API, but the Whisper API doesn't support the .ogg format that WhatsApp uses, so FFmpeg is used to convert the audio to a wav-file before the audio is passed to the Whisper API.

We can't wait to see what you build. Let us know!

 

Niels Swimberghe is a Belgian American software engineer and technical content creator at Twilio, and a Microsoft MVP in Developer Technologies. Get in touch with Niels on Twitter @RealSwimburger and follow Niels’ personal blog on .NET, Azure, and web development at swimburger.net.