FFMpegCore/README.md

237 lines
7.9 KiB
Markdown
Raw Permalink Normal View History

2021-08-07 15:34:40 +02:00
# [FFMpegCore](https://www.nuget.org/packages/FFMpegCore/)
2020-10-29 00:16:58 +01:00
[![NuGet Badge](https://buildstats.info/nuget/FFMpegCore)](https://www.nuget.org/packages/FFMpegCore/)
[![GitHub issues](https://img.shields.io/github/issues/rosenbjerg/FFMpegCore)](https://github.com/rosenbjerg/FFMpegCore/issues)
[![GitHub stars](https://img.shields.io/github/stars/rosenbjerg/FFMpegCore)](https://github.com/rosenbjerg/FFMpegCore/stargazers)
2020-10-29 00:28:46 +01:00
[![GitHub](https://img.shields.io/github/license/rosenbjerg/FFMpegCore)](https://github.com/rosenbjerg/FFMpegCore/blob/master/LICENSE)
2022-03-13 11:43:48 +01:00
[![CI](https://github.com/rosenbjerg/FFMpegCore/workflows/CI/badge.svg)](https://github.com/rosenbjerg/FFMpegCore/actions/workflows/ci.yml)
[![GitHub code contributors](https://img.shields.io/github/contributors/rosenbjerg/FFMpegCore)](https://github.com/rosenbjerg/FFMpegCore/graphs/contributors)
2019-02-08 11:19:40 +01:00
2021-08-07 15:34:40 +02:00
A .NET Standard FFMpeg/FFProbe wrapper for easily integrating media analysis and conversion into your .NET applications. Supports both synchronous and asynchronous calls
2019-02-08 11:19:40 +01:00
2020-05-24 19:28:00 +02:00
# API
2019-05-10 18:34:30 +02:00
2020-05-24 19:28:00 +02:00
## FFProbe
2021-08-07 15:34:40 +02:00
Use FFProbe to analyze media files:
2020-05-24 19:28:00 +02:00
```csharp
2021-08-07 15:34:40 +02:00
var mediaInfo = await FFProbe.AnalyseAsync(inputPath);
```
2020-05-24 19:28:00 +02:00
or
```csharp
2021-08-07 15:34:40 +02:00
var mediaInfo = FFProbe.Analyse(inputPath);
```
2020-05-24 19:28:00 +02:00
## FFMpeg
2021-08-07 15:34:40 +02:00
Use FFMpeg to convert your media files.
2020-05-24 19:28:00 +02:00
Easily build your FFMpeg arguments using the fluent argument builder:
2019-02-08 11:19:40 +01:00
2020-05-24 19:28:00 +02:00
Convert input file to h264/aac scaled to 720p w/ faststart, for web playback
2019-02-08 11:19:40 +01:00
```csharp
2020-05-24 19:28:00 +02:00
FFMpegArguments
2020-10-24 23:04:01 +02:00
.FromFileInput(inputPath)
.OutputToFile(outputPath, false, options => options
2020-10-24 23:03:25 +02:00
.WithVideoCodec(VideoCodec.LibX264)
.WithConstantRateFactor(21)
.WithAudioCodec(AudioCodec.Aac)
.WithVariableBitrate(4)
2021-03-15 18:49:20 +01:00
.WithVideoFilters(filterOptions => filterOptions
.Scale(VideoSize.Hd))
.WithFastStart())
2020-10-24 23:03:25 +02:00
.ProcessSynchronously();
2019-02-08 11:19:40 +01:00
```
2020-05-24 19:28:00 +02:00
Convert to and/or from streams
2019-02-08 11:19:40 +01:00
```csharp
2020-05-24 19:28:00 +02:00
await FFMpegArguments
2020-10-24 23:03:25 +02:00
.FromPipeInput(new StreamPipeSource(inputStream))
.OutputToPipe(new StreamPipeSink(outputStream), options => options
.WithVideoCodec("vp9")
.ForceFormat("webm"))
2020-05-24 19:28:00 +02:00
.ProcessAsynchronously();
2019-02-08 11:19:40 +01:00
```
2021-08-07 15:34:40 +02:00
## Helper methods
The provided helper methods makes it simple to perform common operations.
### Easily capture snapshots from a video file:
```csharp
// 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));
```
### Join video parts into one single file:
2019-02-08 11:19:40 +01:00
```csharp
2020-05-24 19:28:00 +02:00
FFMpeg.Join(@"..\joined_video.mp4",
@"..\part1.mp4",
@"..\part2.mp4",
@"..\part3.mp4"
);
2019-02-08 11:19:40 +01:00
```
2021-08-07 15:34:40 +02:00
### Join images into a video:
2019-02-08 11:19:40 +01:00
```csharp
2020-05-24 19:28:00 +02:00
FFMpeg.JoinImageSequence(@"..\joined_video.mp4", frameRate: 1,
ImageInfo.FromPath(@"..\1.png"),
ImageInfo.FromPath(@"..\2.png"),
ImageInfo.FromPath(@"..\3.png")
);
2019-02-08 11:19:40 +01:00
```
2021-08-07 15:34:40 +02:00
### Mute the audio of a video file:
2019-02-08 11:19:40 +01:00
```csharp
2021-03-15 18:49:20 +01:00
FFMpeg.Mute(inputPath, outputPath);
2019-02-08 11:19:40 +01:00
```
2021-08-07 15:34:40 +02:00
### Extract the audio track from a video file:
2019-02-08 11:19:40 +01:00
```csharp
2021-03-15 18:49:20 +01:00
FFMpeg.ExtractAudio(inputPath, outputPath);
2019-02-08 11:19:40 +01:00
```
2021-08-07 15:34:40 +02:00
### Add or replace the audio track of a video file:
2019-02-08 11:19:40 +01:00
```csharp
2021-03-15 18:49:20 +01:00
FFMpeg.ReplaceAudio(inputPath, inputAudioPath, outputPath);
2019-02-08 11:19:40 +01:00
```
2021-08-07 15:34:40 +02:00
### Combine an image with audio file, for youtube or similar platforms
2019-02-08 11:19:40 +01:00
```csharp
2021-03-15 18:49:20 +01:00
FFMpeg.PosterWithAudio(inputPath, inputAudioPath, outputPath);
2020-05-24 19:28:00 +02:00
// or
2021-03-15 18:49:20 +01:00
var image = Image.FromFile(inputImagePath);
image.AddAudio(inputAudioPath, outputPath);
2019-02-08 11:19:40 +01:00
```
2020-05-24 19:28:00 +02:00
Other available arguments could be found in `FFMpegCore.Arguments` namespace.
2019-02-08 11:19:40 +01:00
2021-08-07 15:34:40 +02:00
## Input piping
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.
2019-02-08 11:19:40 +01:00
2021-08-07 15:34:40 +02:00
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.
2019-02-08 11:19:40 +01:00
2021-08-07 15:34:40 +02:00
### Working with raw video frames
2019-02-08 11:19:40 +01:00
2021-08-07 15:34:40 +02:00
Method for generating bitmap frames:
2019-02-08 11:19:40 +01:00
```csharp
2020-05-24 19:28:00 +02:00
IEnumerable<IVideoFrame> CreateFrames(int count)
2019-02-08 11:19:40 +01:00
{
2020-05-24 19:28:00 +02:00
for(int i = 0; i < count; i++)
{
2021-08-07 15:34:40 +02:00
yield return GetNextFrame(); //method that generates of receives the next frame
2020-05-24 19:28:00 +02:00
}
2019-02-08 11:19:40 +01:00
}
```
2021-08-07 15:34:40 +02:00
Then create a `RawVideoPipeSource` that utilises your video frame source
2019-02-08 11:19:40 +01:00
```csharp
2021-08-07 15:34:40 +02:00
var videoFramesSource = new RawVideoPipeSource(CreateFrames(64))
2019-02-08 11:19:40 +01:00
{
2020-05-24 19:28:00 +02:00
FrameRate = 30 //set source frame rate
};
2021-03-15 18:49:20 +01:00
await FFMpegArguments
.FromPipeInput(videoFramesSource)
.OutputToFile(outputPath, false, options => options
.WithVideoCodec(VideoCodec.LibVpx))
.ProcessAsynchronously();
2019-02-08 11:19:40 +01:00
```
2021-08-07 15:34:40 +02:00
If you want to use `System.Drawing.Bitmap`s as `IVideoFrame`s, a `BitmapVideoFrameWrapper` wrapper class is provided.
2019-02-08 11:19:40 +01:00
2021-08-07 15:34:40 +02:00
# Binaries
2019-02-08 11:19:40 +01:00
2021-08-07 15:34:40 +02:00
## Installation
2020-05-24 19:28:00 +02:00
If you prefer to manually download them, visit [ffbinaries](https://ffbinaries.com/downloads) or [zeranoe Windows builds](https://ffmpeg.zeranoe.com/builds/).
2019-02-08 11:19:40 +01:00
2021-08-07 15:34:40 +02:00
### Windows (using choco)
command: `choco install ffmpeg -y`
2020-04-30 14:23:55 +02:00
2020-05-24 19:28:00 +02:00
location: `C:\ProgramData\chocolatey\lib\ffmpeg\tools\ffmpeg\bin`
2019-02-08 11:19:40 +01:00
2021-08-07 15:34:40 +02:00
### Mac OSX
2020-05-24 19:28:00 +02:00
command: `brew install ffmpeg mono-libgdiplus`
location: `/usr/local/bin`
2021-08-07 15:34:40 +02:00
### Ubuntu
2020-05-24 19:28:00 +02:00
command: `sudo apt-get install -y ffmpeg libgdiplus`
location: `/usr/bin`
2021-08-07 15:34:40 +02:00
## Path Configuration
2020-05-24 19:28:00 +02:00
2021-08-07 15:34:40 +02:00
### Option 1
2020-05-24 19:28:00 +02:00
2021-03-15 18:49:20 +01:00
The default value of an empty string (expecting ffmpeg to be found through PATH) can be overwritten via the `FFOptions` class:
2020-05-24 19:28:00 +02:00
2021-08-07 15:34:40 +02:00
```csharp
2021-03-15 18:49:20 +01:00
// setting global options
GlobalFFOptions.Configure(new FFOptions { BinaryFolder = "./bin", TemporaryFilesFolder = "/tmp" });
2021-08-07 15:34:40 +02:00
2021-03-15 18:49:20 +01:00
// or
GlobalFFOptions.Configure(options => options.BinaryFolder = "./bin");
2021-08-07 15:34:40 +02:00
2021-07-30 20:35:38 +02:00
// on some systems the absolute path may be required, in which case
GlobalFFOptions.Configure(new FFOptions { BinaryFolder = Server.MapPath("./bin"), TemporaryFilesFolder = Server.MapPath("/tmp") });
2021-03-15 18:49:20 +01:00
// or individual, per-run options
await FFMpegArguments
.FromFileInput(inputPath)
.OutputToFile(outputPath)
.ProcessAsynchronously(true, new FFOptions { BinaryFolder = "./bin", TemporaryFilesFolder = "/tmp" });
2021-11-18 14:00:18 +01:00
// 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();
```
2020-04-27 19:16:08 +02:00
2021-08-07 15:34:40 +02:00
### Option 2
2020-04-27 19:16:08 +02:00
2021-08-07 15:34:40 +02:00
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.
2020-04-27 19:16:08 +02:00
2020-05-24 19:28:00 +02:00
```json
2020-04-27 19:16:08 +02:00
{
2021-03-10 07:15:36 +01:00
"BinaryFolder": "./bin",
"TemporaryFilesFolder": "/tmp"
2020-04-27 19:16:08 +02:00
}
```
2021-08-07 15:34:40 +02:00
### Supporting both 32 and 64 bit processes
2021-08-12 23:06:07 +02:00
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.
2021-08-07 15:34:40 +02:00
2021-08-12 23:06:07 +02:00
By doing so, the library will attempt to use either `/{BinaryFolder}/{ARCH}/(ffmpeg|ffprobe).exe`.
2021-08-07 15:34:40 +02:00
2021-08-12 23:06:07 +02:00
If these folders are not defined, it will try to find the binaries in `/{BinaryFolder}/(ffmpeg|ffprobe.exe)`.
2021-08-07 15:34:40 +02:00
(`.exe` is only appended on Windows)
2020-05-24 19:28:00 +02:00
# Compatibility
2021-08-07 15:34:40 +02:00
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`
2020-04-27 19:16:08 +02:00
2021-08-07 16:08:15 +02:00
## Code contributors
<a href="https://github.com/rosenbjerg/ffmpegcore/graphs/contributors">
<img src="https://contrib.rocks/image?repo=rosenbjerg/ffmpegcore" />
</a>
2019-02-08 11:19:40 +01:00
2021-09-19 20:49:10 +02:00
## Other contributors
2021-08-07 16:08:15 +02:00
<a href="https://github.com/tiesont"><img src="https://avatars3.githubusercontent.com/u/420293?v=4" title="tiesont" width="80" height="80"></a>
2019-02-08 11:19:40 +01:00
### License
V.5.0.0 (#391) * Move NotifyOnProgress processing to ErrorData * added HighPass filter, LowPass filter, Audiogate and Silencedetection * re-added corresponding AudioFilterOptions * Update LICENSE * Update ci.yml * Fix argument * Bump action versions * Ignore Uri_Duration until root cause found * Use action that can install specific ffmpeg version * Remove ignore * Revert "Remove ignore" This reverts commit d85a4b81abaf4ab7832020cdb2ccfb46758d3bde. * Bump dependencies * Use setup-dotnet@v2 since v3 seems to install .NET 7 * Init * WIP * Add Directory.Build.props * Add SupportedOSPlatform attribute on tests using SDC * Fix using temporarily * Add IgnoreIf attribute to only run SDC tests on Windows * Cleanup pipelines * Cleanup * Cleanup using directives * More cleanup * Simplify attribute * Fix attribute * Add missing test file * Added blackdetect and blackframe arguments * Added log levels * Add missing using directive after rebase * fix extension is not png lost path * Apply fix to methods in new location * Add Uri support for Frame Analysis, skipped Stream support as this cannot support MP4's with moov atom in the end of the file, and input pipes do not support seek. * Add select multiple streams * Add other stream types to Channel (V,s,d,t) * Add negative mapping to select stream (deselect) * Update test * Add pad video filter * Update PipeHelpers.cs * Fix GetPipePath() for MacOS * Add SampleAspectRatio property to VideoStream * Update year * Always use Path.GetTempPath() on linux and macos * Use FedericoCarboni/setup-ffmpeg@v2 * Include macos in ci matrix * AddDeviceInput similar to AddFileInput and FromDeviceInput * fixed hwaccel parameter not working in 5.0 * a hack to unconditionally kill ffmpeg when parent .NET process exits * Remove PInvoke.Kernel32 * Remove unneeded cast * Update test * Added ability to retrieve bit depth from media streams for lossless encodings (#359) * Added ability to retrieve bit depth from media streams for lossless encodings * Shortened sample AIFF file used in tests * Cleanup after splitting into two packages (#386) * Move PosterWithAudio to FFMpegCore * Reduce windows only tests * Update Directory.Build.props * Create .editorconfig * More cleanup * Enable implicit usings * Remove unused method * Apply dotnet format * Fix unused variable in AudioGateArgument * Fix boolean conditions in AudioGateArgument * Merge boolean conditions into pattern * Use target-typed new * Add linting to CI * Add CUDA to HardwareAccelerationDevice enum * Increase timeout for Video_Join_Image_Sequence * Adjust Video_Join_Image_Sequence timeout * Fix expected seconds in Video_Join_Image_Sequence * Increase timeout for Video_TranscodeToMemory due to macos agents * fix: Switch source for rotation property from 'tags/rotate' to 'side_data_list/rotation' (incl. test case) (#388) * Init (#389) * build master branch after merge or push (#390) * Update ci.yml * Add codecov * Remove codecov for now * Add coverlet.collector and codecov --------- Co-authored-by: keg247 <44041557+keg247@users.noreply.github.com> Co-authored-by: Wilbert Bongers <msdnwilbert@muziekweb.nl> Co-authored-by: Artemii Gazizianov <107502822+ArtemiiimetrA@users.noreply.github.com> Co-authored-by: Thodoris Koskinopoulos <me@koskit.me> Co-authored-by: 赵宁 <602726286@qq.com> Co-authored-by: jeroenvanderschoot <jeroen.vanderschoot@kinetiq.tv> Co-authored-by: Sky Z <qe201020335@sina.com> Co-authored-by: Gleb Moskalenko <gleb.moskalenko.general@gmail.com> Co-authored-by: ep1kt3t0s <86835785+ep1kt3t0s@users.noreply.github.com> Co-authored-by: Victor Nova <lostfreeman@gmail.com> Co-authored-by: Tom Bogle <tom_bogle@sil.org> Co-authored-by: pklaes <10601494+pklaes@users.noreply.github.com>
2023-02-05 00:29:37 +01:00
Copyright © 2023
2020-05-24 19:28:00 +02:00
Released under [MIT license](https://github.com/rosenbjerg/FFMpegCore/blob/master/LICENSE)