FFEncoder Version 2.0.0
The Next Big Update
It's been a while since I've worked on this as I've been quite busy, but this latest release should hopefully make up for it. I added so many things, I felt a full revision bump was needed.
x264 Support (Finally) with the -Encoder
Parameter
NOTE: I did not add 10-Bit or UHD encoding support for x264. It's not industry standard, and nobody really uses it. If you attempt to encode a UHD HDR source with x264, a terminating error is thrown - use x265 instead.
As has been requested for quite some time, x264 support is finally here. This new parameter lets you specify x264 or x265.
It works much the same as x265 does, but since there is a lot of similar functionality with different option names, instead of creating new parameters, I've added aliases to existing ones or modified the parsing. For example:
-PsyRd
This parameter still behaves as expected in x265, but the type has been modified from [double]
to [string]
to support x264 syntax. In x264, psy-rd
encapsulates 2 settings, psy-rdo
and psy-trellis
, and it can be used in the form <psy-rdo>,<psy-trellis>
:
NOTE: The number of spaces before or after the comma separator doesn't matter - regex will account for this
# x264 - MUST use quotes with this format
PS > .\FFencoder.ps1 in.mkv -Encoder x264 -CRF 17 -PsyRd '1.10,0.01' -o out.mkv
# x265 still works the same as before
PS > .\FFencoder.ps1 in.mkv -Encoder x265 -CRF 17 -PsyRd 2.2 -o out.mkv
If you want, you can also use this to pass psy-rdo
only, too, and use -PsyRdoq
to pass psy-trellis
. Both options use the encoder-specific default values for these unless modified.
-PsyRdoq
/ -PsyTrellis
/ -PsyRDO
Since psy-rdoq
is essentially x265's implementation of psy-trellis
, I've made -PsyTrellis
an alias for -PsyRdoq
and -PsyRDO
an alias for -PsyRd
, and you can use them to pass psy-trellis
separately from psy-rdo
- personally, I think this is the better way, but you can do it however you like:
# x264 - Split the options
PS > .\FFencoder.ps1 in.mkv -Encoder x264 -CRF 17 -PsyRDO 1.00 -PsyTrellis 0.01 -o out.mkv
# x265 still works the same as before
PS > .\FFencoder.ps1 in.mkv -Encoder x265 -CRF 17 -PsyRdoq 1.4 -o out.mkv
Note that PsyRdoq
still defaults to the chosen preset value for x265.
-Threads
/ -FrameThreads
I renamed the parameter -FrameThreads
to -Threads
to be more universal. -FrameThreads
is still an alias. Value ranges differ dramatically between encoders, but I did my best to include input validation before the script starts. Just be aware.
-x255Extra
Renamed to -EncoderExtra
This one is fairly self-explanatory.
Universal Encoder Parameters
In the spirit of cross-compatibility, I've added several new parameters that are common to both encoders. most of these parameters use the preset value by default, but can be modified via parameter, too.
-Tree
/ -CUTree
/ -MBTree
As both encoders implement their own motion vector lookahead implementations, I created the general parameter name -Tree
, with aliases -CUTree
and -MBTree
for the specific encoders. They are all equivalent, so there won't be any errors if you use -CUTree
with x264 and vice versa.
-Ref
Specifies the number of references frames. This works more or less the same for both x264 and x265, with x264 being a bit more sensitive about hardware compatibility.
-Merange
/ -MR
Specifies the motion estimation search range. While each encoder uses different value ranges, the effect is the same. I did my best to constrain the possible inputs to cover both (16 - 96), but do watch out with x265 as you might get an error trying to use a value as high as 96 - I'm not sure, I've never tried. I've never seen a value higher than this used before with x264, and the documentation on what the range actually is was...elusive. If you need it updated, open an issue and I can resolve it quickly.
-RCLookahead
/ -Lookahead
/ -RCL
Controls the rate control lookahead buffer. I almost never modify this in x265 (I previously had it hardcoded), but in x264 I do often change it. Since it's common to both and the ranges are the same, it seemed like a logical addition.
New Features
I guess I was feeling a bit ambitious after being away for so long, and decided to add some cool quality of life features to the script as a whole.
Encoder Progress Bar
There is now an official progress bar that shows you your progress! It uses the number of frames encoded to show your current progress (pulled from the log), and you no longer need to run a separate command in a separate shell to see your progress (although I did not remove that as it still has far more info):
To make this work, all encoding tasks now run as a background job, which are continuously monitored to provide progress bar updates. The progress function will check for updates every 1.5 seconds to limit the overhead on the UI.
Additionally, if you terminate the script early via Ctrl+C, the script will attempt to shut down gracefully by killing all running jobs before exiting.
If you're running a test encode, the frame value from -TestFrames
will be used as the total count. For full encodes, the source is quickly scanned for a frame count without demuxing - be patient, this can take up to 30 seconds to load depending on the length of the source.
If you don't want a progress bar for whatever reason, you can disable it using the -DisableProgress
switch parameter.
NOTE: The bar will be somewhat slower to update with HDR10+ encoding, as all the SEI messages really spam the log and create large gaps between frame counters. Just keep that in mind.
VMAF Support
Ever wanted to calculate VMAF easily without leaving the script? Now you can! I've added support for this very useful quality metric directly into the script, which operates as its own parameter set.
Simply pass it a source via -Source
/-Reference
(aliases for -InputPath
) and an encode via -Encode
/-Distorted
(aliases for -OutputPath
) to begin comparison. The machine Learning model files are already provided, and Frames-Per-Second (FPS) and resolution are calculated automatically.
Additionally, you may add SSIM
and PSNR
measurements as well during the same VMAF run using their respective switch parameters - see the README for more info.
Timed Input Prompts
Previously, certain errors would cause the script to exit with an error - I did this because the Read-Host
cmdlet to accept user input still somehow does not provide a timeout option, and I didn't want to break automation with a prompt that sits there for all eternity if you aren't at your computer.
To remedy this, I built my own custom type using C# that is used as an input prompt with a timeout - it's dynamically loaded into memory with the function and not compiled to .dll
because I wasn't sure how that would affect *NIX systems.
If you accidentally pass an incorrect option for a parameter (that can't be caught by parameter validation), you will be prompted for re-input. If you don't enter it in a reasonable amount of time, the script will throw a warning/error but move on instead of exiting in most cases.
Version Checking
This is one feature previous releases really lacked, and I decided to step it up for this one. The script will now verify your version of both PowerShell and FFEncoder, and prompt you to update or throw an error when applicable.
With FFEncoder, it will verify that the release you're running is the latest, and offer to download the latest using git
if you are not. Now, you will never miss out on another update.
For PowerShell, it will verify that you're running the proper version and exit on an error if you are not. The module already requires PowerShell 7.0 or newer, but there might be situations where you switched to Windows PowerShell 5.1 and forgot to switch back - the script will kindly remind you of this. It will also check if you're running the latest version of PowerShell via an API call to GitHub, and warn you that you're missing out on some features if not.
Slick stuff, cool stuff, neat stuff - Garth Brooks
MKV Tag Generation with -GenerateMKVTagFile
I am a dedicated fan of the MKV container format, and have had a script that automatically generates tag files for a while now. If you aren't aware, a tag file is an XML file that contains additional metadata that can be added to the file; this data can be viewed in programs like MediaInfo, or parsed by media agents like Plex or Emby. It's a useful and cool thing to add to your files, and I'm happy to add the option to the script.
The parameter accepts a hashtable as input, and the only required argument is an API key. The script pulls metadata using the TMDB API, so you will need an API key for this to work (it's free to signup). For example:
# Generate a tag file
PS > .\FFencoder.ps1 in.mkv -Encoder x264 -CRF 17 -GenerateMKVTagFile @{APIKey='123456ABCDEFG'} -o out.mkv
The parameter calls an external script, MatroskaTagGenerator.ps1
, and it's highly customizable. See the wiki for full details on what it can do and how to use it.
Updates
This release also comes with several updates/improvements to existing features.
Overhauled Console Output
PowerShell 7.2 brought us the joy of convenient ANSI escape sequences, and I've taken full advantage of that in this latest update. This isn't a requirement, but it's a nice bonus, and really enhances the console experience. If you aren't running version 7.2, the script will warn you that an update is available (but not download it). The base requirement is still PowerShell 7.0.
I've also added in some unicode character sets that add icons, typography, etc. Minor, but fun.
Lastly, I've added some new banners when the script launches and exits.
New Binaries
This one isn't as exciting, but I've updated all of the various binaries used by the script, such as dovi_tool
and hdr10plus_tool
. Big thanks to quietvoid for creating the best non-commercial parsers for us mere mortals to use.
Dolby Encoding Engine Update
DISCLAIMER: I've said it before, and I'll say it again - I do NOT claim to own a copy of DEE.
For those who have access to the Dolby Encoding Engine (DEE) encoder, which is best Dolby audio encoder available for most, there have been some major updates to how it is used in the script.
New Downmix Options
Now, you can use the dee_*
arguments to downmix E-AC3 to 5.1 or stereo, or downmix AC3 to stereo; these options do not apply to TrueHD encoding. See the wiki for more information on how to use these new options.
Configuration Files
First, I overhauled the XML config file used to encode Dolby Digital / Dolby Digital Plus tracks based on some advice from audio engineers.
the most significant change was updating the downmix layout from LoRo (or left only right only, pure stereo) to LtRt, which is more commonly used for movies/TV shows. This is especially useful for downmixing to Pro Logic II on systems that don't have a 5.1 setup, for example, as the channels will be properly matrixed. With LoRo, I'm told it's simply stereo - no matrix. I also updated the phase shift to match the new setting.
Compiled Binaries for Deew
First of all, big shout out to pcroland for writing the initial wrapper for DEE with Python, called Deew
(and blazingly fast, too). I made some changes to suit FFEncoder, but most of the code was written by them.
In the last release, I added support for DEE by integrating Deew
into FFEncoder using Python/PowerShell hacks and background jobs. While this worked, it required that Python be installed, along with all of the necessary packages. It had significant overhead, and was quite slow to run. For this release, I've compiled Deew into an executable, so Python and its packages are no longer a dependency.
I compiled it for Windows and Linux only, as I'm not aware of a macOS version of DEE at this time. However, the Linux binary might work for macOS if one does exist. If anyone is aware of a macOS version of DEE, please let me know and I'll compile it for the Darwin kernel, too.
Performance Updates
This has been a long time coming. I love PowerShell and it's implicit use of objects, and it works incredibly well on *NIX systems now, too (dare I say, better than BASH?).
However, it's not the fastest language in the world, so I went about modifying nearly the entire codebase to use native dotnet
method calls in place of PowerShell cmdlets wherever possible to speed things up.
Additionally, I changed all background jobs to run as a separate thread instead of a process; this has had a remarkable effect on speed, especially considering all encoding now runs as jobs due to the progress bar (assuming it's not disabled). Depending on the number of jobs spinning up at once, it can take a second to get going, but overall, it's much faster than before.
Updates to Scaling
For upscaling/downscaling, I've streamlined the process a lot. I removed the -ScaleFilter
parameter as it was superfluous, and you now pass the scaling option directly to -Scale
:
# Now there are only 2 scaling-related parameters
PS > ./FFencoder.ps1 in_2160p.mkv -Encoder x265 -CRF 17 -Scale spline36 -Resolution 1080p -o out.mkv
The script will implicitly check that your version of ffmpeg supports the chosen option, and will prompt you to enter a compatible one if not (using one of the new timed input prompts).
The script will also warn you and assign a default scaling resolution based on the input file's dimensions if you do not pass an argument to the -Resolution
parameter. Before, the default was 1080p, which didn't make much sense if the input file was also 1920x1080.
Bug Fixes & Other Changes
- Fixed
HME
bug in DV encoding - This was being ignored if passed via-EncoderExtra
- Fixed error when encoding a source with no audio tracks
- If you passed a source with no audio, the script would yell at you while it verified you weren't doing a lossy -> lossy conversion, which made no sense in this context
- It would also throw an terminating error regarding the audio parameters unless you selected
none
. The default option iscopy
, and there was nothing to copy
- Removed second confirmation for existing file deletion - This was providing no value, as the second prompt's response could not be captured anyway; the encode would continue even if you said no (don't delete the file) to the second confirmation prompt
- Fixed custom crop bug with HDR content - Some sources return an extra character when confirming resolution for custom cropping, which was breaking the HDR branch logic
- Fixed bug with track naming logic - Some tracks were not being assigned titles depending on the input
New Bugs
- Rescaling with DoVi - This has been turned off for the time being, as x265 really does not like it when you pipe scaling filters to it. I'm working on fixing that now