A .NET Standard FFMpeg/FFProbe wrapper for easily integrating media analysis and conversion into your .NET applications. Supports both synchronous and asynchronous calls
Use FFProbe to analyze media files:
var mediaInfo = await FFProbe.AnalyseAsync(inputPath);
or
var mediaInfo = FFProbe.Analyse(inputPath);
Use FFMpeg to convert your media files. Easily build your FFMpeg arguments using the fluent argument builder:
Convert input file to h264/aac scaled to 720p w/ faststart, for web playback
FFMpegArguments
.FromFileInput(inputPath)
.OutputToFile(outputPath, false, options => options
.WithVideoCodec(VideoCodec.LibX264)
.WithConstantRateFactor(21)
.WithAudioCodec(AudioCodec.Aac)
.WithVariableBitrate(4)
.WithVideoFilters(filterOptions => filterOptions
.Scale(VideoSize.Hd))
.WithFastStart())
.ProcessSynchronously();
Convert to and/or from streams
await FFMpegArguments
.FromPipeInput(new StreamPipeSource(inputStream))
.OutputToPipe(new StreamPipeSink(outputStream), options => options
.WithVideoCodec("vp9")
.ForceFormat("webm"))
.ProcessAsynchronously();
The provided helper methods makes it simple to perform common operations.
// process the snapshot in-memory and use the Bitmap directly
var bitmap = FFMpeg.Snapshot(inputPath, new Size(200, 400), TimeSpan.FromMinutes(1));
// or persists the image on the drive
FFMpeg.Snapshot(inputPath, outputPath, new Size(200, 400), TimeSpan.FromMinutes(1));
FFMpeg.Join(@"..\joined_video.mp4",
@"..\part1.mp4",
@"..\part2.mp4",
@"..\part3.mp4"
);
FFMpeg.SubVideo(inputPath,
outputPath,
TimeSpan.FromSeconds(0)
TimeSpan.FromSeconds(30)
);
FFMpeg.JoinImageSequence(@"..\joined_video.mp4", frameRate: 1,
ImageInfo.FromPath(@"..\1.png"),
ImageInfo.FromPath(@"..\2.png"),
ImageInfo.FromPath(@"..\3.png")
);
FFMpeg.Mute(inputPath, outputPath);
FFMpeg.ExtractAudio(inputPath, outputPath);
FFMpeg.ReplaceAudio(inputPath, inputAudioPath, outputPath);
FFMpeg.PosterWithAudio(inputPath, inputAudioPath, outputPath);
// or
var image = Image.FromFile(inputImagePath);
image.AddAudio(inputAudioPath, outputPath);
Other available arguments could be found in FFMpegCore.Arguments
namespace.
With input piping it is possible to write video frames directly from program memory without saving them to jpeg or png and then passing path to input of ffmpeg. This feature also allows for converting video on-the-fly while frames are being generated or received.
An object implementing the IPipeSource
interface is used as the source of data. Currently, the IPipeSource
interface has two implementations; StreamPipeSource
for streams, and RawVideoPipeSource
for raw video frames.
Method for generating bitmap frames:
IEnumerable<IVideoFrame> CreateFrames(int count)
{
for(int i = 0; i < count; i++)
{
yield return GetNextFrame(); //method that generates of receives the next frame
}
}
Then create a RawVideoPipeSource
that utilises your video frame source
var videoFramesSource = new RawVideoPipeSource(CreateFrames(64))
{
FrameRate = 30 //set source frame rate
};
await FFMpegArguments
.FromPipeInput(videoFramesSource)
.OutputToFile(outputPath, false, options => options
.WithVideoCodec(VideoCodec.LibVpx))
.ProcessAsynchronously();
If you want to use System.Drawing.Bitmap
s as IVideoFrame
s, a BitmapVideoFrameWrapper
wrapper class is provided.
If you prefer to manually download them, visit ffbinaries or zeranoe Windows builds.
command: choco install ffmpeg -y
location: C:\ProgramData\chocolatey\lib\ffmpeg\tools\ffmpeg\bin
command: brew install ffmpeg mono-libgdiplus
location: /usr/local/bin
command: sudo apt-get install -y ffmpeg libgdiplus
location: /usr/bin
The default value of an empty string (expecting ffmpeg to be found through PATH) can be overwritten via the FFOptions
class:
// setting global options
GlobalFFOptions.Configure(new FFOptions { BinaryFolder = "./bin", TemporaryFilesFolder = "/tmp" });
// or
GlobalFFOptions.Configure(options => options.BinaryFolder = "./bin");
// on some systems the absolute path may be required, in which case
GlobalFFOptions.Configure(new FFOptions { BinaryFolder = Server.MapPath("./bin"), TemporaryFilesFolder = Server.MapPath("/tmp") });
// or individual, per-run options
await FFMpegArguments
.FromFileInput(inputPath)
.OutputToFile(outputPath)
.ProcessAsynchronously(true, new FFOptions { BinaryFolder = "./bin", TemporaryFilesFolder = "/tmp" });
// or combined, setting global defaults and adapting per-run options
GlobalFFOptions.Configure(new FFOptions { BinaryFolder = "./bin", TemporaryFilesFolder = "./globalTmp", WorkingDirectory = "./" });
await FFMpegArguments
.FromFileInput(inputPath)
.OutputToFile(outputPath)
.Configure(options => options.WorkingDirectory = "./CurrentRunWorkingDir")
.Configure(options => options.TemporaryFilesFolder = "./CurrentRunTmpFolder")
.ProcessAsynchronously();
The root and temp directory for the ffmpeg binaries can be configured via the ffmpeg.config.json
file, which will be read on first use only.
{
"BinaryFolder": "./bin",
"TemporaryFilesFolder": "/tmp"
}
If you wish to support multiple client processor architectures, you can do so by creating two folders, x64
and x86
, in the BinaryFolder
directory.
Both folders should contain the binaries (ffmpeg.exe
and ffprobe.exe
) built for the respective architectures.
By doing so, the library will attempt to use either /{BinaryFolder}/{ARCH}/(ffmpeg|ffprobe).exe
.
If these folders are not defined, it will try to find the binaries in /{BinaryFolder}/(ffmpeg|ffprobe.exe)
.
(.exe
is only appended on Windows)
Older versions of ffmpeg might not support all ffmpeg arguments available through this library. The library has been tested with version 3.3
to 4.2
Copyright © 2023
Released under MIT license