From 4a9ae3d2f8dfd7f3fb71fcd8d117ee6fd6fc055d Mon Sep 17 00:00:00 2001 From: Malte Rosenbjerg Date: Sun, 24 May 2020 19:28:00 +0200 Subject: [PATCH] Update README.md --- README.md | 504 +++++++++++++++--------------------------------------- 1 file changed, 140 insertions(+), 364 deletions(-) diff --git a/README.md b/README.md index 4a34689..5d8d0f5 100644 --- a/README.md +++ b/README.md @@ -10,11 +10,141 @@ Install-Package FFMpegCore ``` -A great way to use FFMpeg encoding when writing video applications, client-side and server-side. It has wrapper methods that allow conversion to all web formats: MP4, OGV, TS and methods of capturing screens from the videos. +A great way to use FFMpeg encoding when writing video applications, client-side and server-side. It has wrapper methods that allow conversion to popular web formats, such as Mp4, WebM, Ogv, TS, and methods for capturing screenshots from videos, among other. + +# API + +## FFProbe + +FFProbe is used to gather media information: + +```csharp +var mediaInfo = FFProbe.Analyse(inputFile); +``` +or +```csharp +var mediaInfo = await FFProbe.AnalyseAsync(inputFile); +``` + + +## FFMpeg +FFMpeg is used for converting your media files to web ready formats. +Easily build your FFMpeg arguments using the fluent argument builder: + +Convert input file to h264/aac scaled to 720p w/ faststart, for web playback +```csharp +FFMpegArguments + .FromInputFiles(inputFilePath) + .WithVideoCodec(VideoCodec.LibX264) + .WithConstantRateFactor(21) + .WithAudioCodec(AudioCodec.Aac) + .WithVariableBitrate(4) + .WithFastStart() + .Scale(VideoSize.Hd) + .OutputToFile(output) + .ProcessSynchronously(), +``` + +Easily capture screens from your videos: +```csharp +var mediaFileAnalysis = FFProbe.Analyse(inputFilePath); + +// process the snapshot in-memory and use the Bitmap directly +var bitmap = FFMpeg.Snapshot(mediaFileAnalysis, new Size(200, 400), TimeSpan.FromMinutes(1)); + +// or persists the image on the drive +FFMpeg.Snapshot(mediaFileAnalysis, outputPath, new Size(200, 400), TimeSpan.FromMinutes(1)) +``` + +Convert to and/or from streams +```csharp +await FFMpegArguments + .FromPipe(new StreamPipeDataWriter(inputStream)) + .WithVideoCodec("vp9") + .ForceFormat("webm") + .OutputToPipe(new StreamPipeDataReader(outputStream)) + .ProcessAsynchronously(); +``` + +Join video parts into one single file: +```csharp +FFMpeg.Join(@"..\joined_video.mp4", + @"..\part1.mp4", + @"..\part2.mp4", + @"..\part3.mp4" +); +``` + +Join images into a video: +```csharp +FFMpeg.JoinImageSequence(@"..\joined_video.mp4", frameRate: 1, + ImageInfo.FromPath(@"..\1.png"), + ImageInfo.FromPath(@"..\2.png"), + ImageInfo.FromPath(@"..\3.png") +); +``` + +Mute videos: +```csharp +FFMpeg.Mute(inputFilePath, outputFilePath); +``` + +Save audio track from video: +```csharp +FFMpeg.ExtractAudio(inputVideoFilePath, outputAudioFilePath); +``` + +Add or replace audio track on video: +```csharp +FFMpeg.ReplaceAudio(inputVideoFilePath, inputAudioFilePath, outputVideoFilePath); +``` + +Add poster image to audio file (good for youtube videos): +```csharp +FFMpeg.PosterWithAudio(inputImageFilePath, inputAudioFilePath, outputVideoFilePath); +// or +var image = Image.FromFile(inputImageFile); +image.AddAudio(inputAudioFilePath, outputVideoFilePath); +``` + +Other available arguments could be found in `FFMpegCore.Arguments` namespace. + +### 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 us to convert video on-the-fly while frames are being generated or received. + +The `IPipeSource` interface is used as the source of data. It could be represented as encoded video stream or raw frames stream. Currently, the `IPipeSource` interface has single implementation, `RawVideoPipeSource` that is used for raw stream encoding. + +For example: + +Method that is generating bitmap frames: +```csharp +IEnumerable CreateFrames(int count) +{ + for(int i = 0; i < count; i++) + { + yield return GetNextFrame(); //method of generating new frames + } +} +``` +Then create `ArgumentsContainer` with `InputPipeArgument` +```csharp +var videoFramesSource = new RawVideoPipeSource(CreateFrames(64)) //pass IEnumerable or IEnumerator to constructor of RawVideoPipeSource +{ + FrameRate = 30 //set source frame rate +}; +FFMpegArguments + .FromPipe(videoFramesSource) + // ... other encoding arguments + .OutputToFile("temporary.mp4") + .ProcessSynchronously(); +``` + +if you want to use `System.Drawing.Bitmap` as `IVideoFrame`, there is a `BitmapVideoFrameWrapper` wrapper class. + ## Binaries -If you prefer to manually download them, visit [ffbinaries](https://ffbinaries.com/downloads). +If you prefer to manually download them, visit [ffbinaries](https://ffbinaries.com/downloads) or [zeranoe Windows builds](https://ffmpeg.zeranoe.com/builds/). #### Windows @@ -52,379 +182,24 @@ The default value (`\\FFMPEG\\bin`) can be overwritten via the `FFMpegOptions` c ```c# public Startup() { - FFMpegOptions.Configure(new FFMpegOptions { RootDirectory = "./bin" }); + FFMpegOptions.Configure(new FFMpegOptions { RootDirectory = "./bin", TempDirectory = "/tmp" }); } ``` #### Option 2 -The root directory for the ffmpeg binaries can be configured via the `ffmpeg.config.json` file. +The root and temp directory for the ffmpeg binaries can be configured via the `ffmpeg.config.json` file. ```json { - "RootDirectory": "./bin" + "RootDirectory": "./bin", + "TempDirectory": "/tmp" } ``` # Compatibility - Some versions of FFMPEG might not have the same argument schema. The lib has been tested with version `3.3` to `4.1` + Some versions of FFMPEG might not have the same argument schema. The lib has been tested with version `3.3` to `4.2` - # API - -## FFProbe - -FFProbe is used to gather video information -```csharp -static void Main(string[] args) -{ - string inputFile = "G:\\input.mp4"; - - // loaded from configuration - var video = new VideoInfo(inputFile); - - string output = video.ToString(); - - Console.WriteLine(output); -} -``` - -Sample output: -```csharp -Video Path : G:\input.mp4 -Video Root : G:\\ -Video Name: input.mp4 -Video Extension : .mp4 -Video Duration : 00:00:09 -Audio Format : none -Video Format : h264 -Aspect Ratio : 16:9 -Framerate : 30fps -Resolution : 1280x720 -Size : 2.88 Mb -``` - -## FFMpeg -Convert your video files to web ready formats: - -```csharp -static void Main(string[] args) -{ - string inputFile = "input_path_goes_here"; - var encoder = new FFMpeg(); - FileInfo outputFile = new FileInfo("output_path_goes_here"); - - var video = VideoInfo.FromPath(inputFile); - - // easily track conversion progress - encoder.OnProgress += (percentage) => Console.WriteLine("Progress {0}%", percentage); - - // MP4 conversion - encoder.Convert( - video, - outputFile, - VideoType.Mp4, - Speed.UltraFast, - VideoSize.Original, - AudioQuality.Hd, - true - ); - // OGV conversion - encoder.Convert( - video, - outputFile, - VideoType.Ogv, - Speed.UltraFast, - VideoSize.Original, - AudioQuality.Hd, - true - ); - // TS conversion - encoder.Convert( - video, - outputFile, - VideoType.Ts - ); -} -``` - -Easily capture screens from your videos: -```csharp -static void Main(string[] args) -{ - string inputFile = "input_path_goes_here"; - FileInfo output = new FileInfo("output_path_goes_here"); - - var video = VideoInfo.FromPath(inputFile); - - new FFMpeg() - .Snapshot( - video, - output, - new Size(200, 400), - TimeSpan.FromMinutes(1) - ); -} -``` - -Join video parts: -```csharp -static void Main(string[] args) -{ - FFMpeg encoder = new FFMpeg(); - - encoder.Join( - new FileInfo(@"..\joined_video.mp4"), - VideoInfo.FromPath(@"..\part1.mp4"), - VideoInfo.FromPath(@"..\part2.mp4"), - VideoInfo.FromPath(@"..\part3.mp4") - ); -} -``` - -Join image sequences: -```csharp -static void Main(string[] args) -{ - FFMpeg encoder = new FFMpeg(); - - encoder.JoinImageSequence( - new FileInfo(@"..\joined_video.mp4"), - 1, // FPS - ImageInfo.FromPath(@"..\1.png"), - ImageInfo.FromPath(@"..\2.png"), - ImageInfo.FromPath(@"..\3.png") - ); -} -``` - -Strip audio track from videos: -```csharp -static void Main(string[] args) -{ - string inputFile = "input_path_goes_here", - outputFile = "output_path_goes_here"; - - new FFMpeg() - .Mute( - VideoInfo.FromPath(inputFile), - new FileInfo(outputFile) - ); -} -``` - -Save audio track from video: -```csharp -static void Main(string[] args) -{ - string inputVideoFile = "input_path_goes_here", - outputAudioFile = "output_path_goes_here"; - - new FFMpeg() - .ExtractAudio( - VideoInfo.FromPath(inputVideoFile), - new FileInfo(outputAudioFile) - ); -} -``` - -Add audio track to video: -```csharp -static void Main(string[] args) -{ - string inputVideoFile = "input_path_goes_here", - inputAudioFile = "input_path_goes_here", - outputVideoFile = "output_path_goes_here"; - - FFMpeg encoder = new FFMpeg(); - - new FFMpeg() - .ReplaceAudio( - VideoInfo.FromPath(inputVideoFile), - new FileInfo(inputAudioFile), - new FileInfo(outputVideoFile) - ); -} -``` - -Add poster image to audio file (good for youtube videos): -```csharp -static void Main(string[] args) -{ - string inputImageFile = "input_path_goes_here", - inputAudioFile = "input_path_goes_here", - outputVideoFile = "output_path_goes_here"; - - FFMpeg encoder = new FFMpeg(); - - ((Bitmap)Image.FromFile(inputImageFile)) - .AddAudio( - new FileInfo(inputAudioFile), - new FileInfo(outputVideoFile) - ); - - /* OR */ - - new FFMpeg() - .PosterWithAudio( - inputImageFile, - new FileInfo(inputAudioFile), - new FileInfo(outputVideoFile) - ); -} -``` - -Control over the 'FFmpeg' process doing the job: -```csharp -static void Main(string[] args) -{ - string inputVideoFile = "input_path_goes_here", - outputVideoFile = "input_path_goes_here"; - - FFMpeg encoder = new FFMpeg(); - - // start the conversion process - Task.Run(() => { - encoder.Convert(new VideoInfo(inputVideoFile), new FileInfo(outputVideoFile)); - }); - - // stop encoding after 2 seconds (only for example purposes) - Thread.Sleep(2000); - encoder.Stop(); -} -``` -### Enums - -Video Size enumeration: - -```csharp -public enum VideoSize -{ - HD, - FullHD, - ED, - LD, - Original -} -``` - -Speed enumeration: - -```csharp -public enum Speed -{ - VerySlow, - Slower, - Slow, - Medium, - Fast, - Faster, - VeryFast, - SuperFast, - UltraFast -} -``` -Audio codecs enumeration: - -```csharp -public enum AudioCodec -{ - Aac, - LibVorbis -} -``` - -Audio quality presets enumeration: - -```csharp -public enum AudioQuality -{ - Ultra = 384, - Hd = 192, - Normal = 128, - Low = 64 -} -``` - -Video codecs enumeration: - -```csharp -public enum VideoCodec -{ - LibX264, - LibVpx, - LibTheora, - Png, - MpegTs -} -``` -### ArgumentBuilder -Custom video converting presets could be created with help of `ArgumentContainer` class: -```csharp -var container = new ArgumentContainer(); -container.Add(new VideoCodecArgument(VideoCodec.LibX264)); -container.Add(new ScaleArgument(VideoSize.Hd)); -``` -or use Fluent API - -```csharp -var container = new ArgumentContainer() - .VideoCodec(VideoCodec.LibX264) - .Scale(VideoSize.Hd); -``` - -```csharp -var ffmpeg = new FFMpeg(); -var result = ffmpeg.Convert(container, new FileInfo("input.mp4"), new FileInfo("output.mp4")); -``` - -Other availible arguments could be found in `FFMpegCore.FFMPEG.Argument` namespace. - -If you need to create your custom argument, you just need to create new class, that is inherited from `Argument`, `Argument` or `Argument` -For example: -```csharp -public class OverrideArgument : Argument -{ - public override string GetStringValue() - { - return "-y"; - } -} -``` -### 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 us to convert video on-the-fly while frames are beeing generated/created/processed. - -`IPipeSource` interface is used as source of data. It could be represented as encoded video stream or raw frames stream. Currently `IPipeSource` interface has single implementation, `RawVideoPipeSource` that is used for raw stream encoding. - -For example: - -Method that is generate bitmap frames: -```csharp -IEnumerable CreateFrames(int count) -{ - for(int i = 0; i < count; i++) - { - yield return GetNextFrame(); //method of generating new frames - } -} -``` -Then create `ArgumentsContainer` with `InputPipeArgument` -```csharp -var videoFramesSource = new RawVideoPipeSource(CreateFrames(64)) //pass IEnumerable or IEnumerator to constructor of RawVideoPipeSource -{ - FrameRate = 30 //set source frame rate -}; -var container = new ArgumentsContainer -{ - new InputPipeArgument(videoFramesSource), - ... //Other encoding arguments - new OutputArgument("temporary.mp4") -}; - -var ffmpeg = new FFMpeg(); -var result = ffmpeg.Convert(arguments); -``` - -if you want to use `System.Drawing.Bitmap` as `IVideoFrame`, there is `BitmapVideoFrameWrapper` wrapper class. ## Contributors @@ -438,5 +213,6 @@ if you want to use `System.Drawing.Bitmap` as `IVideoFrame`, there is `BitmapVid ### License -Copyright © 2018, [Vlad Jerca](https://github.com/vladjerca). -Released under the [MIT license](https://github.com/jonschlinkert/github-contributors/blob/master/LICENSE). +Copyright © 2020 + +Released under [MIT license](https://github.com/rosenbjerg/FFMpegCore/blob/master/LICENSE)