├── Inno_Setup_Compiler.iss
├── NotEnoughAV1Encodes
├── MediaInfo
│ └── MediaInfo.dll
├── resources
│ ├── img
│ │ ├── pause.png
│ │ ├── queue.png
│ │ ├── save.png
│ │ ├── start.png
│ │ ├── stop.png
│ │ ├── video.png
│ │ ├── folder.png
│ │ ├── neav1e.ico
│ │ ├── resume.png
│ │ ├── settings.png
│ │ └── videoplaceholder.jpg
│ ├── lang
│ │ └── LocalizedStrings.cs
│ ├── Settings.cs
│ ├── MediaLanguages.cs
│ └── Global.cs
├── Encoders
│ ├── Encoder.cs
│ ├── AVCFFmpeg.cs
│ ├── HEVCFFmpeg.cs
│ ├── NVEnc.cs
│ ├── QSVEnc.cs
│ ├── SvtAV1FFmpeg.cs
│ ├── SvtAV1.cs
│ ├── Rav1eFFmpeg.cs
│ ├── Rav1e.cs
│ ├── VpxVP9FFmpeg.cs
│ ├── AMFAV1.cs
│ ├── Aomenc.cs
│ └── AOMAV1FFmpeg.cs
├── Queue
│ ├── ChunkProgress.cs
│ ├── ChunkVMAF.cs
│ └── QueueElement.cs
├── Controls
│ ├── SubtitlesTab.xaml.cs
│ ├── ChunkingTab.xaml.cs
│ ├── Partials
│ │ ├── VideoTabOptimization.xaml
│ │ ├── VideoTabOptimization.xaml.cs
│ │ └── VideoTabVideo.xaml
│ ├── AudioTab.xaml.cs
│ ├── AdvancedTab.xaml.cs
│ ├── HDRTab.xaml.cs
│ ├── MainWindowTopButtons.xaml
│ ├── SubtitlesTab.xaml
│ ├── AudioTab.xaml
│ ├── SummaryTab.xaml
│ ├── SummaryTab.xaml.cs
│ ├── QueueTab.xaml
│ └── FiltersTab.xaml
├── App.xaml.cs
├── Video
│ └── Encoder.cs
├── AssemblyInfo.cs
├── Audio
│ ├── AudioTracks.cs
│ ├── CommandGenerator.cs
│ └── EncodeAudio.cs
├── Views
│ ├── FirstStartup.xaml.cs
│ ├── TestCustomSettings.xaml
│ ├── OpenSource.xaml
│ ├── OpenSource.xaml.cs
│ ├── SavePresetDialog.xaml.cs
│ ├── FirstStartup.xaml
│ ├── TestCustomSettings.xaml.cs
│ ├── BatchFolderDialog.xaml
│ ├── BatchFolderDialog.xaml.cs
│ ├── ProgramSettings.xaml.cs
│ └── SavePresetDialog.xaml
├── App.xaml
├── win32
│ ├── IdleDetection.cs
│ ├── Suspend.cs
│ └── Resume.cs
├── Subtitle
│ ├── SubtitleTracks.cs
│ ├── CommandGenerator.cs
│ └── ExtractSubtitles.cs
├── MainWindow.xaml
└── NotEnoughAV1Encodes.csproj
├── appveyor.yml
├── .github
└── ISSUE_TEMPLATE
│ ├── feature_request.md
│ └── bug_report.md
├── LICENSE
├── NotEnoughAV1Encodes.sln
├── README.md
├── .gitattributes
└── .gitignore
/Inno_Setup_Compiler.iss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Alkl58/NotEnoughAV1Encodes/HEAD/Inno_Setup_Compiler.iss
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/MediaInfo/MediaInfo.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Alkl58/NotEnoughAV1Encodes/HEAD/NotEnoughAV1Encodes/MediaInfo/MediaInfo.dll
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/resources/img/pause.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Alkl58/NotEnoughAV1Encodes/HEAD/NotEnoughAV1Encodes/resources/img/pause.png
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/resources/img/queue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Alkl58/NotEnoughAV1Encodes/HEAD/NotEnoughAV1Encodes/resources/img/queue.png
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/resources/img/save.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Alkl58/NotEnoughAV1Encodes/HEAD/NotEnoughAV1Encodes/resources/img/save.png
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/resources/img/start.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Alkl58/NotEnoughAV1Encodes/HEAD/NotEnoughAV1Encodes/resources/img/start.png
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/resources/img/stop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Alkl58/NotEnoughAV1Encodes/HEAD/NotEnoughAV1Encodes/resources/img/stop.png
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/resources/img/video.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Alkl58/NotEnoughAV1Encodes/HEAD/NotEnoughAV1Encodes/resources/img/video.png
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/resources/img/folder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Alkl58/NotEnoughAV1Encodes/HEAD/NotEnoughAV1Encodes/resources/img/folder.png
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/resources/img/neav1e.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Alkl58/NotEnoughAV1Encodes/HEAD/NotEnoughAV1Encodes/resources/img/neav1e.ico
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/resources/img/resume.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Alkl58/NotEnoughAV1Encodes/HEAD/NotEnoughAV1Encodes/resources/img/resume.png
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/resources/img/settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Alkl58/NotEnoughAV1Encodes/HEAD/NotEnoughAV1Encodes/resources/img/settings.png
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/resources/img/videoplaceholder.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Alkl58/NotEnoughAV1Encodes/HEAD/NotEnoughAV1Encodes/resources/img/videoplaceholder.jpg
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Encoders/Encoder.cs:
--------------------------------------------------------------------------------
1 | namespace NotEnoughAV1Encodes.Encoders
2 | {
3 | interface IEncoder
4 | {
5 | string GetCommand();
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Queue/ChunkProgress.cs:
--------------------------------------------------------------------------------
1 | namespace NotEnoughAV1Encodes.Queue
2 | {
3 | public class ChunkProgress
4 | {
5 | public string ChunkName { get; set; }
6 | public long Progress { get; set; } = 0;
7 | public long ProgressSecondPass { get; set; } = 0;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Controls/SubtitlesTab.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Controls;
2 |
3 | namespace NotEnoughAV1Encodes.Controls
4 | {
5 | public partial class SubtitlesTab : UserControl
6 | {
7 | public SubtitlesTab()
8 | {
9 | InitializeComponent();
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Data;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 | using System.Windows;
8 |
9 | namespace NotEnoughAV1Encodes
10 | {
11 | ///
12 | /// Interaction logic for App.xaml
13 | ///
14 | public partial class App : Application
15 | {
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Queue/ChunkVMAF.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Windows.Documents;
3 |
4 | namespace NotEnoughAV1Encodes.Queue
5 | {
6 | public class ChunkVMAF
7 | {
8 | public string ChunkName { get; set; }
9 | public string CalculatedQuantizer { get; set; }
10 | public List QValues { get; set; }
11 | public List VMAFValues { get; set; }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Video/Encoder.cs:
--------------------------------------------------------------------------------
1 | namespace NotEnoughAV1Encodes.Video
2 | {
3 | public enum Encoders
4 | {
5 | AOMFFMPEG = 0,
6 | RAV1EFFMPEG = 1,
7 | SVTAV1FFMPEG = 2,
8 | VPXVP9FFMPEG = 3,
9 | AOMENC = 5,
10 | RAV1E = 6,
11 | SVTAV1 = 7,
12 | X265 = 9,
13 | X264 = 10,
14 | QSVAV1 = 12,
15 | NVENCAV1 = 13,
16 | AMFAV1 = 14,
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | version: 1.3.{build}
2 | image: Visual Studio 2022
3 | configuration: Release
4 | assembly_info:
5 | patch: true
6 | file: AssemblyInfo.*
7 | assembly_version: "1.3.{build}"
8 | assembly_file_version: "{version}"
9 | assembly_informational_version: "{version}"
10 | build:
11 | verbosity: minimal
12 | before_build:
13 | - nuget restore
14 | artifacts:
15 | - path: '\NotEnoughAV1Encodes\bin\Release\'
16 | name: NotEnoughAV1Encodes
17 | skip_commits:
18 | files:
19 | - README.md
20 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | [assembly: ThemeInfo(
4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
5 | //(used if a resource is not found in the page,
6 | // or application resource dictionaries)
7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
8 | //(used if a resource is not found in the page,
9 | // app, or any theme specific resource dictionaries)
10 | )]
11 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Controls/ChunkingTab.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Text.RegularExpressions;
2 | using System.Windows.Controls;
3 | using System.Windows.Input;
4 |
5 | namespace NotEnoughAV1Encodes.Controls
6 | {
7 | public partial class ChunkingTab : UserControl
8 | {
9 | public ChunkingTab()
10 | {
11 | InitializeComponent();
12 | }
13 |
14 | private void NumberValidationTextBox(object sender, TextCompositionEventArgs e)
15 | {
16 | // Validates that the TextBox Input are only numbers
17 | Regex regex = new("[^0-9]+");
18 | e.Handled = regex.IsMatch(e.Text);
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Audio/AudioTracks.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace NotEnoughAV1Encodes.Audio
4 | {
5 | public class AudioTracks
6 | {
7 | public bool Active { get; set; }
8 | public int Index { get; set; }
9 | public int Codec { get; set; }
10 | public int Channels { get; set; }
11 | public string Bitrate { get; set; }
12 | public string Language { get; set; }
13 | public List Languages { get; set; }
14 | public string CustomName { get; set; }
15 | public bool PCM { get; set; }
16 | public bool External { get; set; }
17 | public string ExternalPath { get; set; }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: "[Feature]"
5 | labels: enhancement
6 | assignees: Alkl58
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/resources/lang/LocalizedStrings.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using WPFLocalizeExtension.Engine;
3 |
4 | namespace NotEnoughAV1Encodes.resources.lang
5 | {
6 | public class LocalizedStrings
7 | {
8 | public static LocalizedStrings Instance { get; } = new LocalizedStrings();
9 |
10 | public static void SetCulture(CultureInfo cultureInfo)
11 | {
12 | LocalizeDictionary.Instance.Culture = cultureInfo;
13 | }
14 |
15 | public string this[string key]
16 | {
17 | get
18 | {
19 | var result = LocalizeDictionary.Instance.GetLocalizedObject("NotEnoughAV1Encodes", "Strings", key, LocalizeDictionary.Instance.Culture);
20 | return result as string;
21 | }
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: "[BUG] "
5 | labels: bug
6 | assignees: Alkl58
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Log File**
27 | If possible, upload the log generated by the program here.
28 |
29 | **Desktop (please complete the following information):**
30 | - OS: [e.g. Win10 20H1]
31 | - NEAV1E Version: [e.g. v1.9]
32 |
33 | **Additional context**
34 | Add any other context about the problem here.
35 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Views/FirstStartup.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Windows;
4 | using MahApps.Metro.Controls;
5 | using Newtonsoft.Json;
6 |
7 | namespace NotEnoughAV1Encodes.Views
8 | {
9 | public partial class FirstStartup : MetroWindow
10 | {
11 | readonly Settings _settingsDB;
12 | public FirstStartup(Settings settingsDB)
13 | {
14 | InitializeComponent();
15 | _settingsDB = settingsDB;
16 | }
17 |
18 | private void ButtonClose_Click(object sender, RoutedEventArgs e)
19 | {
20 | try
21 | {
22 | Directory.CreateDirectory(Path.Combine(Global.AppData, "NEAV1E"));
23 | File.WriteAllText(Path.Combine(Global.AppData, "NEAV1E", "settings.json"), JsonConvert.SerializeObject(_settingsDB, Formatting.Indented));
24 | }
25 | catch (Exception ex) { MessageBox.Show(ex.Message); }
26 | Close();
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Encoders/AVCFFmpeg.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace NotEnoughAV1Encodes.Encoders
4 | {
5 | class AVCFFmpeg : IEncoder
6 | {
7 | public string GetCommand()
8 | {
9 | // Get MainWindow instance to access UI elements
10 | MainWindow mainWindow = Application.Current.MainWindow as MainWindow;
11 |
12 | string settings = "-c:v libx264";
13 |
14 | // Quality / Bitrate Selection
15 | string quality = mainWindow.VideoTabVideoQualityControl.ComboBoxQualityModeX26x.SelectedIndex switch
16 | {
17 | 0 => " -crf " + mainWindow.VideoTabVideoQualityControl.SliderQualityX26x.Value,
18 | 1 => " -b:v " + mainWindow.VideoTabVideoQualityControl.TextBoxBitrateX26x.Text + "k",
19 | _ => ""
20 | };
21 |
22 | // Preset
23 | settings += quality + " -preset " + mainWindow.GenerateMPEGEncoderSpeed();
24 |
25 | return settings;
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Encoders/HEVCFFmpeg.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace NotEnoughAV1Encodes.Encoders
4 | {
5 | class HEVCFFmpeg : IEncoder
6 | {
7 | public string GetCommand()
8 | {
9 | // Get MainWindow instance to access UI elements
10 | MainWindow mainWindow = Application.Current.MainWindow as MainWindow;
11 |
12 | string settings = "-c:v libx265";
13 |
14 | // Quality / Bitrate Selection
15 | string quality = mainWindow.VideoTabVideoQualityControl.ComboBoxQualityModeX26x.SelectedIndex switch
16 | {
17 | 0 => " -crf " + mainWindow.VideoTabVideoQualityControl.SliderQualityX26x.Value,
18 | 1 => " -b:v " + mainWindow.VideoTabVideoQualityControl.TextBoxBitrateX26x.Text + "k",
19 | _ => ""
20 | };
21 |
22 | // Preset
23 | settings += quality + " -preset " + mainWindow.GenerateMPEGEncoderSpeed();
24 |
25 | return settings;
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/App.xaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Alkl58
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/win32/IdleDetection.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel;
3 | using System.Runtime.InteropServices;
4 |
5 | namespace NotEnoughAV1Encodes.win32
6 | {
7 | internal class IdleDetection
8 | {
9 | public static TimeSpan GetInputIdleTime()
10 | {
11 | var plii = new NativeMethods.LastInputInfo();
12 | plii.cbSize = (UInt32)Marshal.SizeOf(plii);
13 |
14 | if (NativeMethods.GetLastInputInfo(ref plii))
15 | {
16 | return TimeSpan.FromMilliseconds(Environment.TickCount64 - plii.dwTime);
17 | }
18 | else
19 | {
20 | throw new Win32Exception(Marshal.GetLastWin32Error());
21 | }
22 | }
23 |
24 | private static class NativeMethods
25 | {
26 | public struct LastInputInfo
27 | {
28 | public UInt32 cbSize;
29 | public UInt32 dwTime;
30 | }
31 |
32 | [DllImport("user32.dll")]
33 | public static extern bool GetLastInputInfo(ref LastInputInfo plii);
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.29806.167
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NotEnoughAV1Encodes", "NotEnoughAV1Encodes\NotEnoughAV1Encodes.csproj", "{085F1D3A-00C7-41A3-B985-2195B078A364}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {085F1D3A-00C7-41A3-B985-2195B078A364}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {085F1D3A-00C7-41A3-B985-2195B078A364}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {085F1D3A-00C7-41A3-B985-2195B078A364}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {085F1D3A-00C7-41A3-B985-2195B078A364}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {5F34AA94-003F-4244-9116-077051CD707C}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Subtitle/SubtitleTracks.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.ComponentModel;
3 |
4 | namespace NotEnoughAV1Encodes.Subtitle
5 | {
6 | public class SubtitleTracks : INotifyPropertyChanged
7 | {
8 | public event PropertyChangedEventHandler PropertyChanged;
9 | private bool _active = true;
10 | private bool _enabled = true;
11 | public bool Active {
12 | get => _active;
13 | set { _active = value; NotifyPropertyChanged("Active"); }
14 | }
15 | public bool Enabled
16 | {
17 | get => _enabled;
18 | set { _enabled = value; NotifyPropertyChanged("Enabled"); }
19 | }
20 | public int Index { get; set; }
21 | public string Language { get; set; }
22 | public List Languages { get; set; }
23 | public string CustomName { get; set; }
24 | public bool Default { get; set; }
25 | public bool BurnIn { get; set; }
26 | public bool PictureBased { get; set; }
27 |
28 | private void NotifyPropertyChanged(string property)
29 | {
30 | if (PropertyChanged != null)
31 | {
32 | PropertyChanged(this, new PropertyChangedEventArgs(property));
33 | PropertyChanged(this, new PropertyChangedEventArgs("DisplayMember"));
34 | }
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Views/TestCustomSettings.xaml:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Encoders/NVEnc.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Windows;
3 |
4 | namespace NotEnoughAV1Encodes.Encoders
5 | {
6 | class NVEnc : IEncoder
7 | {
8 | public string GetCommand()
9 | {
10 | // Get MainWindow instance to access UI elements
11 | MainWindow mainWindow = Application.Current.MainWindow as MainWindow;
12 |
13 | string settings = "-f yuv4mpegpipe - | " +
14 | "\"" + Path.Combine(Directory.GetCurrentDirectory(), "Apps", "nvenc", "NVEncC64.exe") + "\" --y4m -i -";
15 |
16 | // Codec
17 | settings += " --codec av1";
18 |
19 | // Quality / Bitrate Selection
20 | string quality = mainWindow.VideoTabVideoQualityControl.ComboBoxQualityModeQSVAV1.SelectedIndex switch
21 | {
22 | 0 => " --cqp " + mainWindow.VideoTabVideoQualityControl.SliderQualityQSVAV1.Value,
23 | 1 => " --vbr " + mainWindow.VideoTabVideoQualityControl.TextBoxBitrateQSVAV1.Text,
24 | 2 => " --cbr " + mainWindow.VideoTabVideoQualityControl.TextBoxBitrateQSVAV1.Text,
25 | _ => ""
26 | };
27 |
28 | // Preset
29 | settings += quality + " --preset " + mainWindow.GenerateNVENCEncoderSpeed();
30 |
31 | // Bit-Depth
32 | settings += " --output-depth ";
33 | settings += mainWindow.VideoTabVideoPartialControl.ComboBoxVideoBitDepthLimited.SelectedIndex switch
34 | {
35 | 0 => "8",
36 | 1 => "10",
37 | _ => "8"
38 | };
39 |
40 | return settings;
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # NotEnoughAV1Encodes
2 |
3 | #### NEAV1E is a GUI for AV1 encoders - aomenc, rav1e, svt-av1 & vp9.
4 |
5 | A tool to make encoding faster and easier for AV1 encoders.
6 |
7 | 
8 |
9 |
10 | ---
11 |
12 | ## 🔬 How does this program work?
13 | 1. This program will split the given video file into chunks (scene based splitting or equal chunks).
14 | 2. After splitting, it will encode the chunks with n-amount of workers.
15 | 3. When finished, it will merge the encoded files to a single video file.
16 |
17 |
18 | ##  Releases [](https://ci.appveyor.com/project/Alkl/notenoughav1encodes/branch/master)
19 |
20 | #### Stable Builds: [Releases](https://github.com/Alkl58/NotEnoughAV1Encodes/releases)
21 |
22 | #### Testing Builds: [AppVeyor](https://ci.appveyor.com/project/Alkl/notenoughav1encodes/branch/master/artifacts)
23 |
24 | ## 📽 Encoders
25 |
26 | NEAV1E supports the following encoders:
27 |
28 | - Intel Quicksync AV1 (Intel ARC)
29 | - NVIDIA NVENC AV1 (RTX 40 Series)
30 | - aomenc / libaom
31 | - rav1e / librav1e
32 | - svt-av1 / libsvt-av1
33 | - libvpx-vp9
34 | - libx265 / libx264
35 |
36 | ### 🎉 Special Thanks To
37 | - [@wcxu21](https://github.com/wcxu21) for Chinese Translations!
38 | - Nonami for Russian Translations!
39 | - ieno for Japanese Translations!
40 | - All other wonderful people reporting Bugs and being so patient!
41 |
42 | ---
43 |
44 | #### 📬 Contacting me
45 | You can find me on the unofficial [AV1 Discord](https://discord.gg/HSBxne3) or on the [NEAV1E Discord](https://discord.gg/yG27ArHBFe)
46 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Views/OpenSource.xaml:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Encoders/QSVEnc.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Windows;
3 |
4 | namespace NotEnoughAV1Encodes.Encoders
5 | {
6 | class QSVEnc : IEncoder
7 | {
8 | public string GetCommand()
9 | {
10 | // Get MainWindow instance to access UI elements
11 | MainWindow mainWindow = Application.Current.MainWindow as MainWindow;
12 |
13 | string settings = "-f yuv4mpegpipe - | " +
14 | "\"" + Path.Combine(Directory.GetCurrentDirectory(), "Apps", "qsvenc", "QSVEncC64.exe") + "\" --y4m -i -";
15 |
16 | // Codec
17 | settings += " --codec av1";
18 |
19 | // Quality / Bitrate Selection
20 | string quality = mainWindow.VideoTabVideoQualityControl.ComboBoxQualityModeQSVAV1.SelectedIndex switch
21 | {
22 | 0 => " --cqp " + mainWindow.VideoTabVideoQualityControl.SliderQualityQSVAV1.Value,
23 | 1 => " --icq " + mainWindow.VideoTabVideoQualityControl.SliderQualityQSVAV1.Value,
24 | 2 => " --vbr " + mainWindow.VideoTabVideoQualityControl.TextBoxBitrateQSVAV1.Text,
25 | 3 => " --cbr " + mainWindow.VideoTabVideoQualityControl.TextBoxBitrateQSVAV1.Text,
26 | _ => ""
27 | };
28 |
29 | // Preset
30 | settings += quality + " --quality " + mainWindow.GenerateQuickSyncEncoderSpeed();
31 |
32 | // Bit-Depth
33 | settings += " --output-depth ";
34 | settings += mainWindow.VideoTabVideoPartialControl.ComboBoxVideoBitDepthLimited.SelectedIndex switch
35 | {
36 | 0 => "8",
37 | 1 => "10",
38 | _ => "8"
39 | };
40 |
41 | // Output Colorspace
42 | settings += " --output-csp ";
43 | settings += mainWindow.VideoTabVideoPartialControl.ComboBoxColorFormat.SelectedIndex switch
44 | {
45 | 0 => "i420",
46 | 1 => "i422",
47 | 2 => "i444",
48 | _ => "i420"
49 | };
50 |
51 | return settings;
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Controls/Partials/VideoTabOptimization.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/resources/Settings.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using System.IO;
3 |
4 | namespace NotEnoughAV1Encodes
5 | {
6 | public class Settings
7 | {
8 | /// Sets if Temp Files should be deleted after a successfull encode.
9 | public bool DeleteTempFiles { get; set; } = true;
10 | /// Sets if System shutsdown after the queue finished.
11 | public bool ShutdownAfterEncode { get; set; }
12 | /// Program Theme e.g. "Dark.Blue"
13 | public string Theme { get; set; } = "Light.Blue";
14 | /// Program Base Theme (used by Settings Window)
15 | public int BaseTheme { get; set; }
16 | /// Program Accent Theme (used by Settings Window)
17 | public int AccentTheme { get; set; }
18 | /// Sets Background Image of Program
19 | public string BGImage { get; set; }
20 | /// Specifies the Temp Folder used
21 | public string TempPath { get; set; } = Path.GetTempPath();
22 | /// Specifies the default Output Folder
23 | public string DefaultOutPath { get; set; } = "";
24 | /// Specifies the default Output Container
25 | public string DefaultOutContainer { get; set; } = ".mkv";
26 | /// Toggles Logging functionality
27 | public bool Logging { get; set; } = true;
28 | /// Toggles wether or not to clear the queue automatically
29 | public bool AutoClearQueue { get; set; } = true;
30 | /// Toggles Auto Resume Pause functionality
31 | public bool AutoResumePause { get; set; } = false;
32 | /// Toggles Process Priority (false => low)
33 | public bool PriorityNormal { get; set; } = true;
34 | /// CultureInfo for Language (Default: en-US)
35 | public CultureInfo CultureInfo { get; set; } = new("en");
36 | /// Default Preset to load on startup
37 | public string DefaultPreset { get; set; }
38 | /// Toggles Input Seeking
39 | public bool UseInputSeeking { get; set; }
40 | /// Sort Queue By...
41 | public int SortQueueBy { get; set; }
42 | /// Include Subfolders when opening a Batch Folder
43 | public bool SubfolderBatch { get; set; }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Controls/AudioTab.xaml.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Win32;
2 | using NotEnoughAV1Encodes.Video;
3 | using System.Collections.Generic;
4 | using System.Diagnostics;
5 | using System.Text.RegularExpressions;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Input;
9 |
10 | namespace NotEnoughAV1Encodes.Controls
11 | {
12 | public partial class AudioTab : UserControl
13 | {
14 | public AudioTab()
15 | {
16 | InitializeComponent();
17 | }
18 |
19 | private void NumberValidationTextBox(object sender, TextCompositionEventArgs e)
20 | {
21 | // Validates that the TextBox Input are only numbers
22 | Regex regex = new("[^0-9]+");
23 | e.Handled = regex.IsMatch(e.Text);
24 | }
25 |
26 | private void AudioTracksImport_Click(object sender, RoutedEventArgs e)
27 | {
28 | OpenFileDialog openAudioFilesDialog = new()
29 | {
30 | Filter = "Audio Files|*.mp3;*.aac;*.flac;*.m4a;*.ogg;*.opus;*.wav;*.wma|All Files|*.*",
31 | Multiselect = true
32 | };
33 |
34 | bool? result = openAudioFilesDialog.ShowDialog();
35 | if (result == true)
36 | {
37 | List AudioTracks = new();
38 |
39 | // Get MainWindow instance to access UI elements
40 | MainWindow mainWindow = Application.Current.MainWindow as MainWindow;
41 |
42 | if (ListBoxAudioTracks.ItemsSource != null)
43 | {
44 | AudioTracks = (List) ListBoxAudioTracks.ItemsSource;
45 | }
46 | foreach (string file in openAudioFilesDialog.FileNames)
47 | {
48 | Debug.WriteLine(file);
49 | AudioTracks.Add(mainWindow.videoDB.ParseMediaInfoAudio(file, mainWindow.PresetSettings));
50 | }
51 |
52 | try { ListBoxAudioTracks.Items.Clear(); } catch { }
53 | try { ListBoxAudioTracks.ItemsSource = null; } catch { }
54 | try { mainWindow.SubtitlesTabControl.ListBoxSubtitleTracks.Items.Clear(); } catch { }
55 | try { mainWindow.SubtitlesTabControl.ListBoxSubtitleTracks.ItemsSource = null; } catch { }
56 |
57 | mainWindow.videoDB.AudioTracks = AudioTracks;
58 | ListBoxAudioTracks.ItemsSource = AudioTracks;
59 | }
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/resources/MediaLanguages.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace NotEnoughAV1Encodes.resources
4 | {
5 | internal class MediaLanguages
6 | {
7 | public static Dictionary Languages = new();
8 | public static List LanguageKeys = new();
9 |
10 | public static void FillDictionary()
11 | {
12 | // Languages in ISO 639-2 Format: https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes
13 | Languages.Add("English", "eng");
14 | Languages.Add("Arabic", "ara");
15 | Languages.Add("Bosnian", "bos");
16 | Languages.Add("Bulgarian", "bul");
17 | Languages.Add("Chinese", "zho");
18 | Languages.Add("Czech", "ces");
19 | Languages.Add("Greek", "ell");
20 | Languages.Add("Estonian", "est");
21 | Languages.Add("Persian", "per");
22 | Languages.Add("Filipino", "fil");
23 | Languages.Add("Finnish", "fin");
24 | Languages.Add("French", "fra");
25 | Languages.Add("Georgian", "kat");
26 | Languages.Add("German", "deu");
27 | Languages.Add("Croatian", "hrv");
28 | Languages.Add("Hungarian", "hun");
29 | Languages.Add("Indonesian", "ind");
30 | Languages.Add("Icelandic", "isl");
31 | Languages.Add("Italian", "ita");
32 | Languages.Add("Japanese", "jpn");
33 | Languages.Add("Korean", "kor");
34 | Languages.Add("Latin", "lat");
35 | Languages.Add("Latvian", "lav");
36 | Languages.Add("Lithuanian", "lit");
37 | Languages.Add("Dutch", "nld");
38 | Languages.Add("Norwegian", "nob");
39 | Languages.Add("Polish", "pol");
40 | Languages.Add("Portuguese", "por");
41 | Languages.Add("Romanian", "ron");
42 | Languages.Add("Russian", "rus");
43 | Languages.Add("Slovak", "slk");
44 | Languages.Add("Slovenian", "slv");
45 | Languages.Add("Spanish", "spa");
46 | Languages.Add("Swedish", "swe");
47 | Languages.Add("Thai", "tha");
48 | Languages.Add("Turkish", "tur");
49 | Languages.Add("Ukrainian", "ukr");
50 | Languages.Add("Vietnamese", "vie");
51 | Languages.Add("Undefined", "und");
52 |
53 | foreach (string language in Languages.Keys)
54 | {
55 | LanguageKeys.Add(language);
56 | }
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Views/OpenSource.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Windows;
4 | using ControlzEx.Theming;
5 | using MahApps.Metro.Controls;
6 | using Microsoft.Win32;
7 |
8 | namespace NotEnoughAV1Encodes.Views
9 | {
10 | public partial class OpenSource : MetroWindow
11 | {
12 | public string Path { get; set; }
13 | public bool Quit { get; set; }
14 | public bool BatchFolder { get; set; }
15 | public bool ProjectFile { get; set; }
16 |
17 | public OpenSource(string theme)
18 | {
19 | InitializeComponent();
20 | try { ThemeManager.Current.ChangeTheme(this, theme); } catch { }
21 | }
22 |
23 | private void ButtonOpenVideoFile_Click(object sender, RoutedEventArgs e)
24 | {
25 | // Single File Input
26 | OpenFileDialog openVideoFileDialog = new();
27 | openVideoFileDialog.Filter = "Video Files|*.mp4;*.mkv;*.webm;*.flv;*.avi;*.mov;*.wmv;*.ts|All Files|*.*";
28 | bool? result = openVideoFileDialog.ShowDialog();
29 | if (result == true)
30 | {
31 | Path = openVideoFileDialog.FileName;
32 | BatchFolder = false;
33 | ProjectFile = false;
34 | Quit = true;
35 | Close();
36 | }
37 | }
38 |
39 | private void ButtonOpenBatchFolder_Click(object sender, RoutedEventArgs e)
40 | {
41 | // Folder Input
42 | System.Windows.Forms.FolderBrowserDialog openFolderDialog = new();
43 | var result = openFolderDialog.ShowDialog();
44 | if (result == System.Windows.Forms.DialogResult.OK)
45 | {
46 | Path = openFolderDialog.SelectedPath;
47 | BatchFolder = true;
48 | ProjectFile = false;
49 | Quit = true;
50 | Close();
51 | }
52 | }
53 |
54 | private void ButtonOpenProjectFile_Click(object sender, RoutedEventArgs e)
55 | {
56 | // Project File Input
57 | OpenFileDialog openFileDialog = new();
58 | openFileDialog.Filter = "JSON File|*.json;";
59 | bool? result = openFileDialog.ShowDialog();
60 | if (result == true)
61 | {
62 | Path = openFileDialog.FileName;
63 | BatchFolder = false;
64 | ProjectFile = true;
65 | Quit = true;
66 | Close();
67 | }
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Encoders/SvtAV1FFmpeg.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace NotEnoughAV1Encodes.Encoders
4 | {
5 | class SvtAV1FFmpeg : IEncoder
6 | {
7 | public string GetCommand()
8 | {
9 | // Get MainWindow instance to access UI elements
10 | MainWindow mainWindow = Application.Current.MainWindow as MainWindow;
11 |
12 | string settings = "-c:v libsvtav1";
13 |
14 | // Quality / Bitrate Selection
15 | string quality = mainWindow.VideoTabVideoQualityControl.ComboBoxQualityModeSVTAV1FFMPEG.SelectedIndex switch
16 | {
17 | 0 => " -crf " + mainWindow.VideoTabVideoQualityControl.SliderQualitySVTAV1FFMPEG.Value,
18 | 1 => " -b:v " + mainWindow.VideoTabVideoQualityControl.TextBoxBitrateSVTAV1FFMPEG.Text + "k",
19 | _ => ""
20 | };
21 |
22 | // Preset
23 | settings += quality + " -preset " + mainWindow.VideoTabVideoOptimizationControl.SliderEncoderPreset.Value;
24 |
25 | // Advanced Settings
26 | if (mainWindow.VideoTabVideoOptimizationControl.ToggleSwitchAdvancedSettings.IsOn == false)
27 | {
28 | settings += " -g " + mainWindow.VideoTabVideoPartialControl.GenerateKeyFrameInerval();
29 | }
30 | else
31 | {
32 | settings +=
33 | " -g " + mainWindow.AdvancedTabControl.TextBoxSVTAV1MaxGOP.Text + // Keyframe Interval
34 | " -svtav1-params " +
35 | "aq-mode=" + mainWindow.AdvancedTabControl.ComboBoxSVTAV1AQMode.Text + // AQ Mode
36 | ":tile-columns=" + mainWindow.AdvancedTabControl.ComboBoxSVTAV1TileColumns.Text + // Tile Columns
37 | ":tile-rows=" + mainWindow.AdvancedTabControl.ComboBoxSVTAV1TileRows.Text + // Tile Rows
38 | ":lookahead=" + mainWindow.AdvancedTabControl.TextBoxSVTAV1Lookahead.Text + // Lookahead
39 | ":film-grain=" + mainWindow.AdvancedTabControl.TextBoxSVTAV1FilmGrain.Text + // Film Grain
40 | ":film-grain-denoise=" + mainWindow.AdvancedTabControl.TextBoxSVTAV1FilmGrainDenoise.Text; // Film Grain Denoise
41 | }
42 |
43 | return settings;
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/win32/Suspend.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Management;
5 | using System.Runtime.InteropServices;
6 |
7 | namespace NotEnoughAV1Encodes
8 | {
9 | internal class Suspend
10 | {
11 | [Flags]
12 | public enum ThreadAccess : int
13 | {
14 | TERMINATE = 0x0001,
15 | SUSPEND_RESUME = 0x0002,
16 | GET_CONTEXT = 0x0008,
17 | SET_CONTEXT = 0x0010,
18 | SET_INFORMATION = 0x0020,
19 | QUERY_INFORMATION = 0x0040,
20 | SET_THREAD_TOKEN = 0x0080,
21 | IMPERSONATE = 0x0100,
22 | DIRECT_IMPERSONATION = 0x0200
23 | }
24 |
25 | [DllImport("kernel32.dll")]
26 | private static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
27 |
28 | [DllImport("kernel32.dll")]
29 | private static extern uint SuspendThread(IntPtr hThread);
30 |
31 | [DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
32 | private static extern bool CloseHandle(IntPtr handle);
33 |
34 | public static List GetChildProcesses(int process_id)
35 | {
36 | List children = new();
37 |
38 | ManagementObjectSearcher mos = new(string.Format("Select * From Win32_Process Where ParentProcessID={0}", process_id));
39 |
40 | foreach (ManagementObject mo in mos.Get())
41 | {
42 | children.Add(Convert.ToInt32(mo["ProcessID"]));
43 | }
44 |
45 | return children;
46 | }
47 |
48 | public static void SuspendProcessTree(int pid)
49 | {
50 | List children = GetChildProcesses(pid);
51 |
52 | // Pause cmd
53 | SuspendProcess(pid);
54 |
55 | // Pause subprocess
56 | foreach (int pid_children in children)
57 | {
58 | SuspendProcess(pid_children);
59 | }
60 | }
61 |
62 | private static void SuspendProcess(int pid)
63 | {
64 | var process = Process.GetProcessById(pid); // throws exception if process does not exist
65 |
66 | foreach (ProcessThread pT in process.Threads)
67 | {
68 | IntPtr pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)pT.Id);
69 |
70 | if (pOpenThread == IntPtr.Zero)
71 | {
72 | continue;
73 | }
74 |
75 | SuspendThread(pOpenThread);
76 |
77 | CloseHandle(pOpenThread);
78 | }
79 | }
80 | }
81 | }
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Views/SavePresetDialog.xaml.cs:
--------------------------------------------------------------------------------
1 | using ControlzEx.Theming;
2 | using MahApps.Metro.Controls;
3 | using System.Text.RegularExpressions;
4 | using System.Windows;
5 | using System.Windows.Input;
6 |
7 | namespace NotEnoughAV1Encodes.Views
8 | {
9 | public partial class SavePresetDialog : MetroWindow
10 | {
11 | public string PresetName { get; set; }
12 | public string PresetBatchName { get; set; }
13 | public int AudioCodecMono { get; set; }
14 | public int AudioBitrateMono { get; set; }
15 | public int AudioCodecStereo { get; set; }
16 | public int AudioBitrateStereo { get; set; }
17 | public int AudioCodecSixChannel { get; set; }
18 | public int AudioBitrateSixChannel { get; set; }
19 | public int AudioCodecEightChannel { get; set; }
20 | public int AudioBitrateEightChannel { get; set; }
21 | public bool Quit { get; set; }
22 | public SavePresetDialog(string _theme)
23 | {
24 | InitializeComponent();
25 | try { ThemeManager.Current.ChangeTheme(this, _theme); } catch { }
26 | }
27 |
28 | private void NumberValidationTextBox(object sender, TextCompositionEventArgs e)
29 | {
30 | // Validates that the TextBox Input are only numbers
31 | Regex regex = new("[^0-9]+");
32 | e.Handled = regex.IsMatch(e.Text);
33 | }
34 |
35 | private void ButtonSave_Click(object sender, RoutedEventArgs e)
36 | {
37 | if (string.IsNullOrWhiteSpace(TextBoxPresetName.Text))
38 | {
39 | MessageBox.Show("Baka! You need to set a preset name!", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
40 | return;
41 | }
42 | PresetName = TextBoxPresetName.Text;
43 | PresetBatchName = TextBoxBatchFileName.Text;
44 | // Mono Audio
45 | AudioCodecMono = ComboBoxAudioCodecMono.SelectedIndex;
46 | AudioBitrateMono = int.Parse(TextBoxAudioBitrateMono.Text);
47 | // Stereo Audio
48 | AudioCodecStereo = ComboBoxAudioCodecStereo.SelectedIndex;
49 | AudioBitrateStereo = int.Parse(TextBoxAudioBitrateStereo.Text);
50 | // 5.1 Audio
51 | AudioCodecSixChannel = ComboBoxAudioCodecSixChannel.SelectedIndex;
52 | AudioBitrateSixChannel = int.Parse(TextBoxAudioBitrateSixChannel.Text);
53 | // 7.1 Audio
54 | AudioCodecEightChannel = ComboBoxAudioCodecEightChannel.SelectedIndex;
55 | AudioBitrateEightChannel = int.Parse(TextBoxAudioBitrateEightChannel.Text);
56 | Quit = true;
57 | Close();
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Encoders/SvtAV1.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Windows;
3 |
4 | namespace NotEnoughAV1Encodes.Encoders
5 | {
6 | class SvtAV1 : IEncoder
7 | {
8 | public string GetCommand()
9 | {
10 | // Get MainWindow instance to access UI elements
11 | MainWindow mainWindow = Application.Current.MainWindow as MainWindow;
12 |
13 | string settings = "-nostdin -f yuv4mpegpipe - | " +
14 | "\"" + Path.Combine(Directory.GetCurrentDirectory(), "Apps", "svt-av1", "SvtAv1EncApp.exe") + "\" -i stdin";
15 |
16 | // Quality / Bitrate Selection
17 | string quality = mainWindow.VideoTabVideoQualityControl.ComboBoxQualityModeSVTAV1.SelectedIndex switch
18 | {
19 | 0 => " --rc 0 --crf " + mainWindow.VideoTabVideoQualityControl.SliderQualitySVTAV1.Value,
20 | 1 => " --rc 1 --tbr " + mainWindow.VideoTabVideoQualityControl.TextBoxBitrateSVTAV1.Text,
21 | _ => ""
22 | };
23 |
24 | // Preset
25 | settings += quality + " --preset " + mainWindow.VideoTabVideoOptimizationControl.SliderEncoderPreset.Value;
26 |
27 | // Advanced Settings
28 | if (mainWindow.VideoTabVideoOptimizationControl.ToggleSwitchAdvancedSettings.IsOn == false)
29 | {
30 | settings += " --keyint " + mainWindow.VideoTabVideoPartialControl.GenerateKeyFrameInerval();
31 |
32 | }
33 | else
34 | {
35 | settings += " --tile-columns " + mainWindow.AdvancedTabControl.ComboBoxSVTAV1TileColumns.Text + // Tile Columns
36 | " --tile-rows " + mainWindow.AdvancedTabControl.ComboBoxSVTAV1TileRows.Text + // Tile Rows
37 | " --keyint " + mainWindow.AdvancedTabControl.TextBoxSVTAV1MaxGOP.Text + // Keyframe Interval
38 | " --lookahead " + mainWindow.AdvancedTabControl.TextBoxSVTAV1Lookahead.Text + // Lookahead
39 | " --aq-mode " + mainWindow.AdvancedTabControl.ComboBoxSVTAV1AQMode.Text + // AQ Mode
40 | " --film-grain " + mainWindow.AdvancedTabControl.TextBoxSVTAV1FilmGrain.Text + // Film Grain
41 | " --film-grain-denoise " + mainWindow.AdvancedTabControl.TextBoxSVTAV1FilmGrainDenoise.Text; // Film Grain Denoise
42 | }
43 |
44 | return settings;
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/win32/Resume.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Management;
5 | using System.Runtime.InteropServices;
6 |
7 | namespace NotEnoughAV1Encodes
8 | {
9 | internal class Resume
10 | {
11 | [Flags]
12 | public enum ThreadAccess : int
13 | {
14 | TERMINATE = 0x0001,
15 | SUSPEND_RESUME = 0x0002,
16 | GET_CONTEXT = 0x0008,
17 | SET_CONTEXT = 0x0010,
18 | SET_INFORMATION = 0x0020,
19 | QUERY_INFORMATION = 0x0040,
20 | SET_THREAD_TOKEN = 0x0080,
21 | IMPERSONATE = 0x0100,
22 | DIRECT_IMPERSONATION = 0x0200
23 | }
24 |
25 | [DllImport("kernel32.dll")]
26 | private static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
27 |
28 | [DllImport("kernel32.dll")]
29 | private static extern int ResumeThread(IntPtr hThread);
30 |
31 | [DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
32 | private static extern bool CloseHandle(IntPtr handle);
33 |
34 | private static List GetChildProcesses(int process_id)
35 | {
36 | List children = new();
37 |
38 | ManagementObjectSearcher mos = new(String.Format("Select * From Win32_Process Where ParentProcessID={0}", process_id));
39 |
40 | foreach (ManagementObject mo in mos.Get())
41 | {
42 | children.Add(Convert.ToInt32(mo["ProcessID"]));
43 | }
44 |
45 | return children;
46 | }
47 |
48 | public static void ResumeProcessTree(int pid)
49 | {
50 | List children = GetChildProcesses(pid);
51 |
52 | // Pause cmd
53 | ResumeProcess(pid);
54 |
55 | // Pause subprocess
56 | foreach (int pid_children in children)
57 | {
58 | ResumeProcess(pid_children);
59 | }
60 | }
61 |
62 | public static void ResumeProcess(int pid)
63 | {
64 | var process = Process.GetProcessById(pid);
65 |
66 | if (process.ProcessName == string.Empty)
67 | return;
68 |
69 | foreach (ProcessThread pT in process.Threads)
70 | {
71 | IntPtr pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)pT.Id);
72 |
73 | if (pOpenThread == IntPtr.Zero)
74 | {
75 | continue;
76 | }
77 |
78 | int suspendCount;
79 | do
80 | {
81 | suspendCount = ResumeThread(pOpenThread);
82 | } while (suspendCount > 0);
83 |
84 | CloseHandle(pOpenThread);
85 | }
86 | }
87 | }
88 | }
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Views/FirstStartup.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/resources/Global.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Threading;
5 |
6 | namespace NotEnoughAV1Encodes
7 | {
8 | internal class Global
9 | {
10 | public static string AppData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
11 | public static string Temp = Path.GetTempPath();
12 |
13 | // Current Active PIDs
14 | public static List LaunchedPIDs = new();
15 |
16 | public static int GetTotalFramesProcessed(string stderr)
17 | {
18 | try
19 | {
20 | if (stderr.Contains("frame="))
21 | {
22 | int Start, End;
23 | Start = stderr.IndexOf("frame=", 0) + "frame=".Length;
24 | End = stderr.IndexOf("fps=", Start);
25 | return int.Parse(stderr[Start..End]);
26 | }
27 | }
28 | catch { }
29 |
30 | return 0;
31 | }
32 |
33 | public static int GetTotalTimeProcessed(string stderr, Queue.QueueElement queue)
34 | {
35 | try
36 | {
37 | if (stderr.Contains("time="))
38 | {
39 | // Get Timespan of Video
40 | TimeSpan length = TimeSpan.Parse(queue.VideoDB.MIDuration);
41 |
42 | // Parse stderr Output of FFmpeg
43 | int Start, End;
44 | Start = stderr.IndexOf("time=", 0) + "time=".Length;
45 | End = stderr.IndexOf("bitrate=", Start);
46 | string ffmpegTime = stderr[Start..End];
47 |
48 | // Convert FFmpeg time to Timespan
49 | TimeSpan ts = TimeSpan.Parse(ffmpegTime);
50 |
51 | // Progress in Percent
52 | double prog = Math.Round(ts / length, 2) * 100;
53 |
54 | // Convert Progress to amount of Frames (roughly)
55 | int frameCount = Convert.ToInt32(prog) * (Convert.ToInt32(queue.VideoDB.MIFrameCount) / 100);
56 |
57 | return frameCount;
58 | }
59 | }
60 | catch { }
61 |
62 | return 0;
63 | }
64 |
65 | private static readonly ReaderWriterLockSlim readWriteLock = new();
66 | public static void Logger(string logMessage, string logPath)
67 | {
68 | // We could use a better logging method with different logging levels
69 | // However for this "small" application this is enough
70 |
71 | if(MainWindow.Logging == false)
72 | {
73 | return;
74 | }
75 |
76 | // Set Status to Locked
77 | readWriteLock.EnterWriteLock();
78 | try
79 | {
80 | using StreamWriter sw = new(logPath, true);
81 | sw.WriteLine($"{DateTime.Now} : {logMessage}");
82 | sw.Close();
83 | }
84 | finally
85 | {
86 | // Release Lock
87 | readWriteLock.ExitWriteLock();
88 | }
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Subtitle/CommandGenerator.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 |
3 | namespace NotEnoughAV1Encodes.Subtitle
4 | {
5 | internal class CommandGenerator
6 | {
7 | public string GenerateSoftsub(System.Windows.Controls.ItemCollection tracks)
8 | {
9 | bool noSubs = true;
10 | string command = "";
11 | bool firstMap = true;
12 | string map = " --subtitle-tracks ";
13 | foreach (SubtitleTracks track in tracks)
14 | {
15 | // Skip Subtitle Track if not active
16 | if (track.Active == false) continue;
17 | // Skip Subtitle Track if burned in
18 | if (track.BurnIn == true) continue;
19 |
20 | // Mapping Subtitles
21 | map += firstMap ? track.Index : "," + track.Index;
22 | firstMap = false;
23 |
24 | command += SoftsubGenerator(track.Index, resources.MediaLanguages.Languages[track.Language], track.CustomName, track.Default);
25 | noSubs = false;
26 | }
27 |
28 | // Only return non null, if subs actually exists
29 | // Needed for Muxing Logic in Video/VideoMuxer.cs
30 | return noSubs ? null : map + command;
31 | }
32 |
33 | public string GenerateHardsub(System.Windows.Controls.ItemCollection tracks, string identifier)
34 | {
35 | bool noSubs = true;
36 | string command = "";
37 |
38 | foreach (SubtitleTracks track in tracks)
39 | {
40 | // Skip Subtitle Track if not active
41 | if (track.Active == false) continue;
42 | // Skip Subtitle Track if not burned in
43 | if (track.BurnIn == false) continue;
44 | // Skip Subtitle Track if not empty
45 | if(!string.IsNullOrEmpty(command)) continue;
46 |
47 | string subPath = Path.Combine(Global.Temp, "NEAV1E", identifier, "Subtitles", "subs.mkv");
48 | command = HardsubGenerator(track.PictureBased, track.Index, subPath);
49 | noSubs = false;
50 | }
51 |
52 | return noSubs ? null : command;
53 | }
54 |
55 | private static string SoftsubGenerator(int index, string language, string name, bool defaultSub)
56 | {
57 | // mkvmerge commands
58 | string subDefault = defaultSub ? "yes" : "no";
59 | return " --language " + index + ":" + language + " --track-name " + index + ":\"" + name + "\" --default-track " + index + ":" + subDefault;
60 | }
61 |
62 | private string HardsubGenerator(bool pictureBased, int index, string input)
63 | {
64 | // FFmpeg Path Escaping Hell
65 | // Should look something like this: "C\\\:Users\\\\Username\\\\..."
66 | input = input.Replace("\u005c", "\u005c\u005c\u005c\u005c").Replace(":", "\u005c\u005c\u005c:");
67 |
68 | // ffmpeg filter commands
69 | if (pictureBased)
70 | return " -filter_complex \"[0:v][1:s:" + index + "]overlay[v]\" -map \"[v]\" ";
71 | return " -vf subtitles=\"" + input + "\":si=" + index;
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Encoders/Rav1eFFmpeg.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace NotEnoughAV1Encodes.Encoders
4 | {
5 | class Rav1eFFmpeg : IEncoder
6 | {
7 | public string GetCommand()
8 | {
9 | // Get MainWindow instance to access UI elements
10 | MainWindow mainWindow = Application.Current.MainWindow as MainWindow;
11 |
12 | string settings = "-c:v librav1e";
13 |
14 | // Quality / Bitrate Selection
15 | string quality = mainWindow.VideoTabVideoQualityControl.ComboBoxQualityModeRAV1EFFMPEG.SelectedIndex switch
16 | {
17 | 0 => " -qp " + mainWindow.VideoTabVideoQualityControl.SliderQualityRAV1EFFMPEG.Value,
18 | 1 => " -b:v " + mainWindow.VideoTabVideoQualityControl.TextBoxBitrateRAV1EFFMPEG.Text + "k",
19 | _ => ""
20 | };
21 |
22 | // Preset
23 | settings += quality + " -speed " + mainWindow.VideoTabVideoOptimizationControl.SliderEncoderPreset.Value;
24 |
25 | // Advanced Settings
26 | if (mainWindow.VideoTabVideoOptimizationControl.ToggleSwitchAdvancedSettings.IsOn == false)
27 | {
28 | settings += " -tile-columns 2 -tile-rows 1 -g " + mainWindow.VideoTabVideoPartialControl.GenerateKeyFrameInerval() + " -rav1e-params threads=4";
29 | }
30 | else
31 | {
32 | settings += " -tile-columns " + mainWindow.AdvancedTabControl.ComboBoxRav1eTileColumns.SelectedIndex + // Tile Columns
33 | " -tile-rows " + mainWindow.AdvancedTabControl.ComboBoxRav1eTileRows.SelectedIndex; // Tile Rows
34 |
35 | settings += " -rav1e-params " +
36 | "threads=" + mainWindow.AdvancedTabControl.ComboBoxRav1eThreads.SelectedIndex + // Threads
37 | ":rdo-lookahead-frames=" + mainWindow.AdvancedTabControl.TextBoxRav1eLookahead.Text + // RDO Lookahead
38 | ":tune=" + mainWindow.AdvancedTabControl.ComboBoxRav1eTune.Text; // Tune
39 |
40 | if (mainWindow.AdvancedTabControl.TextBoxRav1eMaxGOP.Text != "0")
41 | settings += ":keyint=" + mainWindow.AdvancedTabControl.TextBoxRav1eMaxGOP.Text; // Keyframe Interval
42 |
43 | if (mainWindow.AdvancedTabControl.ComboBoxRav1eColorPrimaries.SelectedIndex != 0)
44 | settings += ":primaries=" + mainWindow.AdvancedTabControl.ComboBoxRav1eColorPrimaries.Text; // Color Primaries
45 | if (mainWindow.AdvancedTabControl.ComboBoxRav1eColorTransfer.SelectedIndex != 0)
46 | settings += ":transfer=" + mainWindow.AdvancedTabControl.ComboBoxRav1eColorTransfer.Text; // Color Transfer
47 | if (mainWindow.AdvancedTabControl.ComboBoxRav1eColorMatrix.SelectedIndex != 0)
48 | settings += ":matrix=" + mainWindow.AdvancedTabControl.ComboBoxRav1eColorMatrix.Text; // Color Matrix
49 | }
50 |
51 | return settings;
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Views/TestCustomSettings.xaml.cs:
--------------------------------------------------------------------------------
1 | using ControlzEx.Theming;
2 | using MahApps.Metro.Controls;
3 | using System.Diagnostics;
4 | using System.IO;
5 | using System.Threading.Tasks;
6 | using System.Windows.Media;
7 |
8 | namespace NotEnoughAV1Encodes.Views
9 | {
10 | public partial class TestCustomSettings : MetroWindow
11 | {
12 | public TestCustomSettings(string theme, int encoder, string command)
13 | {
14 | InitializeComponent();
15 | try { ThemeManager.Current.ChangeTheme(this, theme); } catch { }
16 | Test(encoder, command);
17 | }
18 |
19 | private async void Test(int encoder, string command)
20 | {
21 | ProgressBar.IsIndeterminate = true;
22 | LabelProgressBar.Content = "Testing... Please wait.";
23 |
24 | int exitCode = await Task.Run(() => TestEncode(encoder, command));
25 |
26 | if (exitCode == 0)
27 | {
28 | LabelProgressBar.Foreground = new SolidColorBrush(Color.FromRgb(6, 176, 37));
29 | LabelProgressBar.Content = "Test was Successfull.";
30 | }
31 | else
32 | {
33 | LabelProgressBar.Foreground = new SolidColorBrush(Color.FromRgb(200, 0, 0));
34 | LabelProgressBar.Content = "Test Terminated with Error Code: " + exitCode.ToString() + " - Invalid settings?";
35 | }
36 | ProgressBar.IsIndeterminate = false;
37 | }
38 |
39 | private int TestEncode(int encoder, string command)
40 | {
41 | Process ffmpegProcess = new();
42 | ProcessStartInfo startInfo = new();
43 | startInfo.UseShellExecute = true;
44 | startInfo.FileName = "cmd.exe";
45 | startInfo.WorkingDirectory = Path.Combine(Directory.GetCurrentDirectory(), "Apps", "FFmpeg");
46 | startInfo.WindowStyle = ProcessWindowStyle.Hidden;
47 |
48 | string input = " -y -i \"" + Path.Combine(Directory.GetCurrentDirectory(), "sample", "test_sample.mp4") + "\"";
49 | string testCommand = " -t 00:00.30 " + command + " ";
50 |
51 | if (encoder <= 4)
52 | {
53 | // Internal Encoders
54 | testCommand += "\"" + Path.Combine(Directory.GetCurrentDirectory(), "sample", "test_sample_out.webm") + "\"";
55 | }
56 | else
57 | {
58 | // External Encoders
59 | string passesSettings = "";
60 | if (encoder is 5) { passesSettings = " --passes=1 --output="; }
61 | if (encoder is 6) { passesSettings = " --output "; }
62 | if (encoder is 7) { passesSettings = " --passes 1 --output "; }
63 | testCommand += passesSettings + "\"" + Path.Combine(Directory.GetCurrentDirectory(), "sample", "test_sample_out.ivf") + "\"";
64 | }
65 |
66 | startInfo.Arguments = "/C ffmpeg.exe " + input + testCommand;
67 |
68 | ffmpegProcess.StartInfo = startInfo;
69 | ffmpegProcess.Start();
70 | ffmpegProcess.WaitForExit();
71 |
72 | return ffmpegProcess.ExitCode;
73 | }
74 |
75 | private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
76 | {
77 | Close();
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Encoders/Rav1e.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Windows;
3 |
4 | namespace NotEnoughAV1Encodes.Encoders
5 | {
6 | class Rav1e : IEncoder
7 | {
8 | public string GetCommand()
9 | {
10 | // Get MainWindow instance to access UI elements
11 | MainWindow mainWindow = Application.Current.MainWindow as MainWindow;
12 |
13 | string settings = "-f yuv4mpegpipe - | " +
14 | "\"" + Path.Combine(Directory.GetCurrentDirectory(), "Apps", "rav1e", "rav1e.exe") + "\" - -y";
15 |
16 | // Quality / Bitrate Selection
17 | string quality = mainWindow.VideoTabVideoQualityControl.ComboBoxQualityModeRAV1E.SelectedIndex switch
18 | {
19 | 0 => " --quantizer " + mainWindow.VideoTabVideoQualityControl.SliderQualityRAV1E.Value,
20 | 1 => " --bitrate " + mainWindow.VideoTabVideoQualityControl.TextBoxBitrateRAV1E.Text,
21 | _ => ""
22 | };
23 |
24 | // Preset
25 | settings += quality + " --speed " + mainWindow.VideoTabVideoOptimizationControl.SliderEncoderPreset.Value;
26 |
27 | // Advanced Settings
28 | if (mainWindow.VideoTabVideoOptimizationControl.ToggleSwitchAdvancedSettings.IsOn == false)
29 | {
30 | settings += " --threads 4 --tile-cols 2 --tile-rows 1 --keyint " + mainWindow.VideoTabVideoPartialControl.GenerateKeyFrameInerval();
31 | }
32 | else
33 | {
34 | settings += " --threads " + mainWindow.AdvancedTabControl.ComboBoxRav1eThreads.SelectedIndex + // Threads
35 | " --tile-cols " + mainWindow.AdvancedTabControl.ComboBoxRav1eTileColumns.SelectedIndex + // Tile Columns
36 | " --tile-rows " + mainWindow.AdvancedTabControl.ComboBoxRav1eTileRows.SelectedIndex + // Tile Rows
37 | " --rdo-lookahead-frames " + mainWindow.AdvancedTabControl.TextBoxRav1eLookahead.Text + // RDO Lookahead
38 | " --tune " + mainWindow.AdvancedTabControl.ComboBoxRav1eTune.Text; // Tune
39 |
40 | if (mainWindow.AdvancedTabControl.TextBoxRav1eMaxGOP.Text != "0")
41 | settings += " --keyint " + mainWindow.AdvancedTabControl.TextBoxRav1eMaxGOP.Text; // Keyframe Interval
42 |
43 | if (mainWindow.AdvancedTabControl.ComboBoxRav1eColorPrimaries.SelectedIndex != 0)
44 | settings += " --primaries " + mainWindow.AdvancedTabControl.ComboBoxRav1eColorPrimaries.Text; // Color Primaries
45 | if (mainWindow.AdvancedTabControl.ComboBoxRav1eColorTransfer.SelectedIndex != 0)
46 | settings += " --transfer " + mainWindow.AdvancedTabControl.ComboBoxRav1eColorTransfer.Text; // Color Transfer
47 | if (mainWindow.AdvancedTabControl.ComboBoxRav1eColorMatrix.SelectedIndex != 0)
48 | settings += " --matrix " + mainWindow.AdvancedTabControl.ComboBoxRav1eColorMatrix.Text; // Color Matrix
49 | }
50 |
51 | return settings;
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Subtitle/ExtractSubtitles.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.IO;
4 | using System.Threading;
5 |
6 | namespace NotEnoughAV1Encodes.Subtitle
7 | {
8 | internal class ExtractSubtitles
9 | {
10 | public void Extract(Queue.QueueElement queueElement, CancellationToken _token)
11 | {
12 | Global.Logger("DEBUG - ExtractSubtitles.Extract()", queueElement.Output + ".log");
13 | if (queueElement.SubtitleCommand != null && !File.Exists(Path.Combine(Global.Temp, "NEAV1E", queueElement.UniqueIdentifier, "Subtitles", "exit.log")))
14 | {
15 | Directory.CreateDirectory(Path.Combine(Global.Temp, "NEAV1E", queueElement.UniqueIdentifier, "Subtitles"));
16 | Global.Logger("INFO - ExtractSubtitles.Extract() => Command: " + queueElement.SubtitleCommand, queueElement.Output + ".log");
17 |
18 | Process processSubtitles = new();
19 | ProcessStartInfo startInfo = new()
20 | {
21 | WindowStyle = ProcessWindowStyle.Hidden,
22 | FileName = "cmd.exe",
23 | WorkingDirectory = Path.Combine(Directory.GetCurrentDirectory(), "Apps", "FFmpeg"),
24 | Arguments = "/C ffmpeg.exe -i \"" + queueElement.VideoDB.InputPath + "\" -vn -an -dn -map_metadata -1 -map 0:s? -c:s copy \"" + Path.Combine(Global.Temp, "NEAV1E", queueElement.UniqueIdentifier, "Subtitles", "subs.mkv") + "\"",
25 | RedirectStandardError = true,
26 | RedirectStandardInput = true,
27 | CreateNoWindow = true
28 | };
29 | processSubtitles.StartInfo = startInfo;
30 |
31 | _token.Register(() => { try { processSubtitles.StandardInput.Write("q"); } catch { } });
32 |
33 | processSubtitles.Start();
34 |
35 | StreamReader sr = processSubtitles.StandardError;
36 | while (!sr.EndOfStream)
37 | {
38 | int processedFrames = Global.GetTotalFramesProcessed(sr.ReadLine());
39 | if (processedFrames != 0)
40 | {
41 | queueElement.Progress = Convert.ToDouble(processedFrames);
42 | queueElement.Status = "Extracting Subtitles - " + ((decimal)queueElement.Progress / queueElement.FrameCount).ToString("0.00%");
43 | }
44 | }
45 |
46 | processSubtitles.WaitForExit();
47 |
48 | // Reset Progressbar
49 | queueElement.Progress = 0.00;
50 |
51 | if (processSubtitles.ExitCode == 0 && _token.IsCancellationRequested == false)
52 | {
53 | var logFile = File.Create(Path.Combine(Global.Temp, "NEAV1E", queueElement.UniqueIdentifier, "Subtitles", "exit.log"));
54 | logFile.Close();
55 | Global.Logger("DEBUG - ExtractSubtitles.Extract() => ExitCode: " + processSubtitles.ExitCode, queueElement.Output + ".log");
56 | }
57 | else
58 | {
59 | Global.Logger("FATAL - ExtractSubtitles.Extract() => ExitCode: " + processSubtitles.ExitCode, queueElement.Output + ".log");
60 | }
61 | }
62 | else
63 | {
64 | Global.Logger("WARN - ExtractSubtitles.Extract() => File already exist - Resuming?", queueElement.Output + ".log");
65 | }
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Controls/AdvancedTab.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Text.RegularExpressions;
2 | using System.Windows;
3 | using System.Windows.Controls;
4 | using System.Windows.Input;
5 | using System.Windows.Media;
6 |
7 | namespace NotEnoughAV1Encodes.Controls
8 | {
9 | public partial class AdvancedTab : UserControl
10 | {
11 | public AdvancedTab()
12 | {
13 | InitializeComponent();
14 | }
15 |
16 | private void NumberValidationTextBox(object sender, TextCompositionEventArgs e)
17 | {
18 | // Validates that the TextBox Input are only numbers
19 | Regex regex = new("[^0-9]+");
20 | e.Handled = regex.IsMatch(e.Text);
21 | }
22 |
23 | private void CheckBoxCustomVideoSettings_Toggled(object sender, RoutedEventArgs e)
24 | {
25 | if (MainWindow.startupLock) return;
26 |
27 | // Get MainWindow instance to access UI elements
28 | MainWindow mainWindow = Application.Current.MainWindow as MainWindow;
29 |
30 | if (CheckBoxCustomVideoSettings.IsOn && mainWindow.SummaryTabControl.presetLoadLock == false && IsLoaded)
31 | {
32 | TextBoxCustomVideoSettings.Text = mainWindow.GenerateEncoderCommand();
33 | }
34 | }
35 |
36 | private void TextBoxCustomVideoSettings_TextChanged(object sender, TextChangedEventArgs e)
37 | {
38 | if (MainWindow.startupLock) return;
39 |
40 | // Get MainWindow instance to access UI elements
41 | MainWindow mainWindow = Application.Current.MainWindow as MainWindow;
42 |
43 | // Verifies the arguments the user inputs into the encoding settings textbox
44 | // If the users writes a "forbidden" argument, it will display the text red
45 | string[] forbiddenWords = { "help", "cfg", "debug", "output", "passes", "pass", "fpf", "limit",
46 | "skip", "webm", "ivf", "obu", "q-hist", "rate-hist", "fullhelp", "benchmark", "first-pass", "second-pass",
47 | "reconstruction", "enc-mode-2p", "input-stat-file", "output-stat-file" };
48 |
49 | foreach (string word in forbiddenWords)
50 | {
51 | if (mainWindow.settingsDB.BaseTheme == 0)
52 | {
53 | // Lightmode
54 | TextBoxCustomVideoSettings.Foreground = new SolidColorBrush(Color.FromRgb(0, 0, 0));
55 | }
56 | else
57 | {
58 | // Darkmode
59 | TextBoxCustomVideoSettings.Foreground = new SolidColorBrush(Color.FromRgb(255, 255, 255));
60 | }
61 |
62 | if (TextBoxCustomVideoSettings.Text.Contains(word))
63 | {
64 | TextBoxCustomVideoSettings.Foreground = new SolidColorBrush(Color.FromRgb(255, 0, 0));
65 | break;
66 | }
67 | }
68 | }
69 |
70 | private void ButtonTestSettings_Click(object sender, RoutedEventArgs e)
71 | {
72 | if (MainWindow.startupLock) return;
73 |
74 | // Get MainWindow instance to access UI elements
75 | MainWindow mainWindow = Application.Current.MainWindow as MainWindow;
76 |
77 | Views.TestCustomSettings testCustomSettings = new(mainWindow.settingsDB.Theme, mainWindow.VideoTabVideoPartialControl.ComboBoxVideoEncoder.SelectedIndex, mainWindow.AdvancedTabControl.CheckBoxCustomVideoSettings.IsOn ? mainWindow.AdvancedTabControl.TextBoxCustomVideoSettings.Text : mainWindow.GenerateEncoderCommand());
78 | testCustomSettings.ShowDialog();
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Controls/HDRTab.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Controls;
3 |
4 | namespace NotEnoughAV1Encodes.Controls
5 | {
6 | public partial class HDRTab : UserControl
7 | {
8 | public HDRTab()
9 | {
10 | InitializeComponent();
11 | }
12 |
13 | public string GenerateMKVMergeHDRCommand()
14 | {
15 | string settings = " ";
16 |
17 | // Get MainWindow instance to access UI elements
18 | MainWindow mainWindow = Application.Current.MainWindow as MainWindow;
19 |
20 | if (mainWindow.VideoTabVideoPartialControl.CheckBoxVideoHDR.IsChecked == true)
21 | {
22 | settings = "";
23 | if (CheckBoxMKVMergeMasteringDisplay.IsChecked == true)
24 | {
25 | // --chromaticity-coordinates TID:red-x,red-y,green-x,green-y,blue-x,blue-y
26 | settings += " --chromaticity-coordinates 0:" +
27 | TextBoxMKVMergeMasteringRx.Text + "," +
28 | TextBoxMKVMergeMasteringRy.Text + "," +
29 | TextBoxMKVMergeMasteringGx.Text + "," +
30 | TextBoxMKVMergeMasteringGy.Text + "," +
31 | TextBoxMKVMergeMasteringBx.Text + "," +
32 | TextBoxMKVMergeMasteringBy.Text;
33 | }
34 | if (CheckBoxMKVMergeWhiteMasteringDisplay.IsChecked == true)
35 | {
36 | // --white-colour-coordinates TID:x,y
37 | settings += " --white-colour-coordinates 0:" +
38 | TextBoxMKVMergeMasteringWPx.Text + "," +
39 | TextBoxMKVMergeMasteringWPy.Text;
40 | }
41 | if (CheckBoxMKVMergeLuminance.IsChecked == true)
42 | {
43 | // --max-luminance TID:float
44 | // --min-luminance TID:float
45 | settings += " --max-luminance 0:" + TextBoxMKVMergeMasteringLMax.Text;
46 | settings += " --min-luminance 0:" + TextBoxMKVMergeMasteringLMin.Text;
47 | }
48 | if (CheckBoxMKVMergeMaxContentLight.IsChecked == true)
49 | {
50 | // --max-content-light TID:n
51 | settings += " --max-content-light 0:" + TextBoxMKVMergeMaxContentLight.Text;
52 | }
53 | if (CheckBoxMKVMergeMaxFrameLight.IsChecked == true)
54 | {
55 | // --max-frame-light TID:n
56 | settings += " --max-frame-light 0:" + TextBoxMKVMergeMaxFrameLight.Text;
57 | }
58 | if (ComboBoxMKVMergeColorPrimaries.SelectedIndex != 2)
59 | {
60 | // --colour-primaries TID:n
61 | settings += " --colour-primaries 0:" + ComboBoxMKVMergeColorPrimaries.SelectedIndex.ToString();
62 | }
63 | if (ComboBoxMKVMergeColorTransfer.SelectedIndex != 2)
64 | {
65 | // --colour-transfer-characteristics TID:n
66 | settings += " --colour-transfer-characteristics 0:" + ComboBoxMKVMergeColorTransfer.SelectedIndex.ToString();
67 | }
68 | if (ComboBoxMKVMergeColorMatrix.SelectedIndex != 2)
69 | {
70 | // --colour-matrix-coefficients TID:n
71 | settings += " --colour-matrix-coefficients 0:" + ComboBoxMKVMergeColorMatrix.SelectedIndex.ToString();
72 | }
73 | }
74 | return settings;
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/NotEnoughAV1Encodes.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | WinExe
5 | net6.0-windows
6 | true
7 | true
8 | resources\img\neav1e.ico
9 | 2.1.7
10 | Alkl58
11 |
12 |
13 |
14 | x64
15 |
16 |
17 |
18 | x64
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | True
62 | True
63 | Strings.resx
64 |
65 |
66 |
67 |
68 |
69 | PublicResXFileCodeGenerator
70 |
71 |
72 | PublicResXFileCodeGenerator
73 | Strings.Designer.cs
74 |
75 |
76 | PublicResXFileCodeGenerator
77 |
78 |
79 | PublicResXFileCodeGenerator
80 |
81 |
82 |
83 |
84 |
85 | PreserveNewest
86 |
87 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Encoders/VpxVP9FFmpeg.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace NotEnoughAV1Encodes.Encoders
4 | {
5 | class VpxVP9FFmpeg : IEncoder
6 | {
7 | public string GetCommand()
8 | {
9 | // Get MainWindow instance to access UI elements
10 | MainWindow mainWindow = Application.Current.MainWindow as MainWindow;
11 |
12 | string settings = "-c:v libvpx-vp9";
13 |
14 | // Quality / Bitrate Selection
15 | string quality = mainWindow.VideoTabVideoQualityControl.ComboBoxQualityModeVP9FFMPEG.SelectedIndex switch
16 | {
17 | 0 => " -crf " + mainWindow.VideoTabVideoQualityControl.SliderQualityVP9FFMPEG.Value + " -b:v 0",
18 | 1 => " -crf " + mainWindow.VideoTabVideoQualityControl.SliderQualityVP9FFMPEG.Value + " -b:v " + mainWindow.VideoTabVideoQualityControl.TextBoxMaxBitrateVP9FFMPEG.Text + "k",
19 | 2 => " -b:v " + mainWindow.VideoTabVideoQualityControl.TextBoxAVGBitrateVP9FFMPEG.Text + "k",
20 | 3 => " -minrate " + mainWindow.VideoTabVideoQualityControl.TextBoxMinBitrateVP9FFMPEG.Text + "k -b:v " + mainWindow.VideoTabVideoQualityControl.TextBoxAVGBitrateVP9FFMPEG.Text + "k -maxrate " + mainWindow.VideoTabVideoQualityControl.TextBoxMaxBitrateVP9FFMPEG.Text + "k",
21 | _ => ""
22 | };
23 |
24 | // Preset
25 | settings += quality + " -cpu-used " + mainWindow.VideoTabVideoOptimizationControl.SliderEncoderPreset.Value;
26 |
27 | // Advanced Settings
28 | if (mainWindow.VideoTabVideoOptimizationControl.ToggleSwitchAdvancedSettings.IsOn == false)
29 | {
30 | settings += " -threads 4 -tile-columns 2 -tile-rows 1 -g " + mainWindow.VideoTabVideoPartialControl.GenerateKeyFrameInerval();
31 | }
32 | else
33 | {
34 | settings += " -threads " + mainWindow.AdvancedTabControl.ComboBoxVP9Threads.Text + // Max Threads
35 | " -tile-columns " + mainWindow.AdvancedTabControl.ComboBoxVP9TileColumns.SelectedIndex + // Tile Columns
36 | " -tile-rows " + mainWindow.AdvancedTabControl.ComboBoxVP9TileRows.SelectedIndex + // Tile Rows
37 | " -lag-in-frames " + mainWindow.AdvancedTabControl.TextBoxVP9LagInFrames.Text + // Lag in Frames
38 | " -g " + mainWindow.AdvancedTabControl.TextBoxVP9MaxKF.Text + // Max GOP
39 | " -aq-mode " + mainWindow.AdvancedTabControl.ComboBoxVP9AQMode.SelectedIndex + // AQ-Mode
40 | " -tune " + mainWindow.AdvancedTabControl.ComboBoxVP9ATune.SelectedIndex + // Tune
41 | " -tune-content " + mainWindow.AdvancedTabControl.ComboBoxVP9ATuneContent.SelectedIndex; // Tune-Content
42 |
43 | if (mainWindow.AdvancedTabControl.CheckBoxVP9ARNR.IsChecked == true)
44 | {
45 | settings += " -arnr-maxframes " + mainWindow.AdvancedTabControl.ComboBoxAomencVP9Max.Text + // ARNR Max Frames
46 | " -arnr-strength " + mainWindow.AdvancedTabControl.ComboBoxAomencVP9Strength.Text + // ARNR Strength
47 | " -arnr-type " + mainWindow.AdvancedTabControl.ComboBoxAomencVP9ARNRType.Text; // ARNR Type
48 | }
49 | }
50 |
51 | return settings;
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Audio/CommandGenerator.cs:
--------------------------------------------------------------------------------
1 | namespace NotEnoughAV1Encodes.Audio
2 | {
3 | internal class CommandGenerator
4 | {
5 | public string Generate(System.Windows.Controls.ItemCollection tracks)
6 | {
7 | string audioCommand = "";
8 | int endIndex = 0;
9 | int externalIndex = 0;
10 | bool copyaudio = false;
11 | bool noaudio = true;
12 |
13 | foreach (AudioTracks track in tracks)
14 | {
15 | // Skip Audio Track if not active
16 | if(track.Active == false) continue;
17 |
18 | if (track.External)
19 | {
20 | externalIndex += 1;
21 | }
22 |
23 | audioCommand += MultipleTrackCommandGenerator(int.Parse(track.Bitrate), track.Index, endIndex, track.Codec, track.Channels, track.Language, track.CustomName, track.PCM, track.External, externalIndex);
24 | endIndex += 1;
25 |
26 | if (track.Codec == 5)
27 | {
28 | copyaudio = true;
29 | }
30 |
31 | noaudio = false;
32 | }
33 |
34 | if (!copyaudio)
35 | {
36 | audioCommand += " -af aformat=channel_layouts=" + '\u0022' + "7.1|5.1|stereo|mono" + '\u0022';
37 | }
38 |
39 | return noaudio ? null : audioCommand;
40 | }
41 |
42 | private static string SwitchCodec(int _audioCodec, bool _pcmBluray)
43 | {
44 | string audioCodeSwitch = _audioCodec switch
45 | {
46 | 0 => " libopus",
47 | 1 => " ac3",
48 | 2 => " eac3",
49 | 3 => " aac",
50 | 4 => " libmp3lame",
51 | 5 => _pcmBluray ? " pcm_s16le" : " copy",
52 | _ => " ",
53 | };
54 | return audioCodeSwitch;
55 | }
56 |
57 | private string MultipleTrackCommandGenerator(int activeTrackBitrate, int mapIndex, int endIndex, int activTrackCodec, int channelLayout, string language, string trackName, bool pcmBluray, bool external, int externalIndex)
58 | {
59 | string audioCodecCommand;
60 |
61 | // Audio Mapping
62 | audioCodecCommand = " -map 0:a:" + mapIndex + " -c:a:" + endIndex;
63 |
64 | if (external)
65 | {
66 | audioCodecCommand = " -map " + externalIndex + ":a:" + mapIndex + " -c:a:" + endIndex;
67 | }
68 |
69 | // Codec
70 | audioCodecCommand += SwitchCodec(activTrackCodec, pcmBluray);
71 | // Bitrate
72 | if (activTrackCodec != 5)
73 | {
74 | audioCodecCommand += " -b:a:" + endIndex + " " + activeTrackBitrate + "k";
75 | }
76 | // Channel Layout
77 | audioCodecCommand += " -ac:a:" + endIndex + " " + SetChannelLayout(channelLayout);
78 | // Metadata
79 | audioCodecCommand += " -metadata:s:a:" + endIndex + " language=" + resources.MediaLanguages.Languages[language];
80 | // Title
81 | if (activTrackCodec != 5)
82 | {
83 | audioCodecCommand += " -metadata:s:a:" + endIndex + " title=" + '\u0022' + trackName + '\u0022';
84 | }
85 | return audioCodecCommand;
86 | }
87 |
88 | private static string SetChannelLayout(int _layout)
89 | {
90 | string _returnLayout = _layout switch
91 | {
92 | 0 => "1",
93 | 1 => "2",
94 | 2 => "6",
95 | 3 => "8",
96 | _ => "2",
97 | };
98 | return _returnLayout;
99 | }
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Encoders/AMFAV1.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace NotEnoughAV1Encodes.Encoders
4 | {
5 | internal class AMFAV1 : IEncoder
6 | {
7 | /*
8 | * The implementation is pretty questionable
9 | * There is basically no documentation available online
10 | * Some unassuring things I found:
11 | * - https://trac.ffmpeg.org/ticket/10389 (av1_amf ignores most quality/bitrate settings except for b:v)
12 | * - https://trac.ffmpeg.org/ticket/10266 (Issues when using av1_amf to encode a video)*
13 | * *does this mean that amd amf only supports 1080p!?
14 | * - Supported pixel formats: nv12 yuv420p d3d11 dxva2_vld (no 422/444 ... really?!)
15 | *
16 | * It's unclear which arguments should be mixed with which.
17 | */
18 | public string GetCommand()
19 | {
20 | // Get MainWindow instance to access UI elements
21 | MainWindow mainWindow = Application.Current.MainWindow as MainWindow;
22 |
23 | string command = "-c:v av1_amf";
24 |
25 | // Speed
26 | // -quality E..V....... Set the encoding quality(from 0 to 100) (default speed)
27 | // balanced 70 E..V.......
28 | // speed 100 E..V.......
29 | // quality 30 E..V.......
30 | // high_quality 0 E..V.......
31 | command += " -quality ";
32 | command += mainWindow.VideoTabVideoOptimizationControl.SliderEncoderPreset.Value switch
33 | {
34 | 0 => "high_quality",
35 | 1 => "quality",
36 | 2 => "balanced",
37 | 3 => "speed",
38 | _ => ""
39 | };
40 |
41 |
42 | // Quality Preset
43 | // -rc E..V....... Set the rate control mode(from - 1 to 6)(default - 1)
44 | // cqp 0 E..V....... Constant Quantization Parameter
45 | // vbr_latency 1 E..V....... Latency Constrained Variable Bitrate
46 | // vbr_peak 2 E..V....... Peak Contrained Variable Bitrate
47 | // cbr 3 E..V....... Constant Bitrate
48 | // qvbr 4 E..V....... Quality Variable Bitrate
49 | // hqvbr 5 E..V....... High Quality Variable Bitrate
50 | // hqcbr 6 E..V....... High Quality Constant Bitrate
51 | command += " -rc ";
52 | command += mainWindow.VideoTabVideoQualityControl.ComboBoxQualityModeAMFAV1.SelectedIndex switch
53 | {
54 | 0 => "cqp -qp " + mainWindow.VideoTabVideoQualityControl.SliderQualityAMFAV1.Value,
55 | 1 => "cbr -b:v " + mainWindow.VideoTabVideoQualityControl.TextBoxBitrateAMFAV1.Text + "k",
56 | 2 => "hqcbr -b:v " + mainWindow.VideoTabVideoQualityControl.TextBoxBitrateAMFAV1.Text + "k",
57 | 3 => "qvbr -b:v " + mainWindow.VideoTabVideoQualityControl.TextBoxBitrateAMFAV1.Text + "k -qvbr_quality_level " + mainWindow.VideoTabVideoQualityControl.SliderQualityAMFAV1.Value,
58 | 4 => "hqvbr -b:v " + mainWindow.VideoTabVideoQualityControl.TextBoxBitrateAMFAV1.Text + "k",
59 | _ => ""
60 | };
61 |
62 | return command;
63 | }
64 |
65 | public static string GetSpeed(double value)
66 | {
67 | return value switch
68 | {
69 | 0 => "High Quality",
70 | 1 => "Quality",
71 | 2 => "Balanced",
72 | 3 => "Speed",
73 | _ => "default"
74 | };
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Controls/MainWindowTopButtons.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
16 |
22 |
28 |
34 |
39 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Audio/EncodeAudio.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.IO;
4 | using System.Threading;
5 |
6 | namespace NotEnoughAV1Encodes.Audio
7 | {
8 | class EncodeAudio
9 | {
10 | public void Encode(Queue.QueueElement queueElement, CancellationToken _token)
11 | {
12 | Global.Logger("DEBUG - EncodeAudio.Encode()", queueElement.Output + ".log");
13 | if (queueElement.AudioCommand != null && !File.Exists(Path.Combine(Global.Temp, "NEAV1E", queueElement.UniqueIdentifier, "Audio", "exit.log")))
14 | {
15 | Directory.CreateDirectory(Path.Combine(Global.Temp, "NEAV1E", queueElement.UniqueIdentifier, "Audio"));
16 |
17 | Global.Logger("INFO - EncodeAudio.Encode() => Command: " + queueElement.AudioCommand, queueElement.Output + ".log");
18 |
19 | string externalInput = "";
20 | foreach (AudioTracks audioTrack in queueElement.VideoDB.AudioTracks)
21 | {
22 | if (!audioTrack.External) continue;
23 | externalInput += " -i \"" + audioTrack.ExternalPath + "\"";
24 | }
25 |
26 | Process processAudio = new();
27 | ProcessStartInfo startInfo = new()
28 | {
29 | WindowStyle = ProcessWindowStyle.Hidden,
30 | FileName = "cmd.exe",
31 | WorkingDirectory = Path.Combine(Directory.GetCurrentDirectory(), "Apps", "FFmpeg"),
32 | Arguments = "/C ffmpeg.exe -y -analyzeduration 100M -probesize 100M -i \"" + queueElement.VideoDB.InputPath + "\" " + externalInput + " -vn -sn -map_metadata -1 " + queueElement.AudioCommand + " \"" + Path.Combine(Global.Temp, "NEAV1E", queueElement.UniqueIdentifier, "Audio", "audio.mkv") + "\"",
33 | RedirectStandardError = true,
34 | RedirectStandardInput = true,
35 | CreateNoWindow = true
36 | };
37 | processAudio.StartInfo = startInfo;
38 |
39 | _token.Register(() => { try { processAudio.StandardInput.Write("q"); } catch { } });
40 |
41 | processAudio.Start();
42 |
43 | StreamReader sr = processAudio.StandardError;
44 | string stderr = "\n";
45 | while (!sr.EndOfStream)
46 | {
47 | string line = sr.ReadLine();
48 | if (!line.Contains("time="))
49 | stderr += line + "\n";
50 | int processedFrames = Global.GetTotalTimeProcessed(line, queueElement);
51 | if (processedFrames != 0)
52 | {
53 | queueElement.Progress = Convert.ToDouble(processedFrames);
54 | queueElement.Status = "Encoding Audio - " + ((decimal)queueElement.Progress / queueElement.FrameCount).ToString("0.00%");
55 | }
56 | }
57 |
58 | processAudio.WaitForExit();
59 |
60 | // Reset Progressbar
61 | queueElement.Progress = 0.00;
62 |
63 | if (processAudio.ExitCode == 0 && _token.IsCancellationRequested == false)
64 | {
65 | var logFile = File.Create(Path.Combine(Global.Temp, "NEAV1E", queueElement.UniqueIdentifier, "Audio", "exit.log"));
66 | logFile.Close();
67 | Global.Logger("DEBUG - EncodeAudio.Encode() => ExitCode: " + processAudio.ExitCode, queueElement.Output + ".log");
68 | }
69 | else
70 | {
71 | queueElement.Error = true;
72 | queueElement.ErrorCount += 1;
73 | Global.Logger("FATAL - EncodeAudio.Encode() => ExitCode: " + processAudio.ExitCode, queueElement.Output + ".log");
74 | Global.Logger("==========================================================" + stderr, queueElement.Output + ".log");
75 | Global.Logger("==========================================================", queueElement.Output + ".log");
76 | }
77 | }
78 | else
79 | {
80 | Global.Logger("WARN - EncodeAudio.Encode() => File already exist - Resuming?", queueElement.Output + ".log");
81 | }
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Controls/SubtitlesTab.xaml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Controls/Partials/VideoTabOptimization.xaml.cs:
--------------------------------------------------------------------------------
1 | using NotEnoughAV1Encodes.Encoders;
2 | using System.Windows;
3 | using System.Windows.Controls;
4 |
5 | namespace NotEnoughAV1Encodes.Controls.Partials
6 | {
7 | public partial class VideoTabOptimization : UserControl
8 | {
9 | public VideoTabOptimization()
10 | {
11 | InitializeComponent();
12 | }
13 |
14 | private void SliderEncoderPreset_ValueChanged(object sender, RoutedPropertyChangedEventArgs e)
15 | {
16 | UpdateSpeedLabel();
17 | }
18 |
19 | public void UpdateSpeedLabel()
20 | {
21 | if (MainWindow.startupLock) return;
22 |
23 | // Get MainWindow instance to access UI elements
24 | MainWindow mainWindow = Application.Current.MainWindow as MainWindow;
25 |
26 | // Shows / Hides Real Time Mode CheckBox
27 | if (CheckBoxRealTimeMode != null && mainWindow.VideoTabVideoPartialControl.ComboBoxVideoEncoder != null)
28 | {
29 | if (mainWindow.VideoTabVideoPartialControl.ComboBoxVideoEncoder.SelectedIndex == (int)Video.Encoders.AOMFFMPEG || mainWindow.VideoTabVideoPartialControl.ComboBoxVideoEncoder.SelectedIndex == (int)Video.Encoders.AOMENC)
30 | {
31 | if (SliderEncoderPreset.Value >= 5)
32 | {
33 | CheckBoxRealTimeMode.Visibility = Visibility.Visible;
34 | }
35 | else
36 | {
37 | CheckBoxRealTimeMode.IsOn = false;
38 | CheckBoxRealTimeMode.Visibility = Visibility.Collapsed;
39 | }
40 | }
41 | else
42 | {
43 | CheckBoxRealTimeMode.Visibility = Visibility.Collapsed;
44 | }
45 | }
46 |
47 | LabelSpeedValue.Content = SliderEncoderPreset.Value;
48 |
49 | // x264 / x265
50 | if (mainWindow.VideoTabVideoPartialControl.ComboBoxVideoEncoder.SelectedIndex is (int)Video.Encoders.X265 or (int)Video.Encoders.X264)
51 | {
52 | LabelSpeedValue.Content = mainWindow.GenerateMPEGEncoderSpeed();
53 | }
54 |
55 | // av1 hardware (Intel Arc)
56 | if (mainWindow.VideoTabVideoPartialControl.ComboBoxVideoEncoder.SelectedIndex is (int)Video.Encoders.QSVAV1)
57 | {
58 | LabelSpeedValue.Content = mainWindow.GenerateQuickSyncEncoderSpeed();
59 | }
60 |
61 | // av1 hardware (nvenc rtx 4000)
62 | if (mainWindow.VideoTabVideoPartialControl.ComboBoxVideoEncoder.SelectedIndex is (int)Video.Encoders.NVENCAV1)
63 | {
64 | LabelSpeedValue.Content = mainWindow.GenerateNVENCEncoderSpeed();
65 | }
66 |
67 | // av1 hardware (AMD AMF)
68 | if (mainWindow.VideoTabVideoPartialControl.ComboBoxVideoEncoder.SelectedIndex is (int)Video.Encoders.AMFAV1)
69 | {
70 | LabelSpeedValue.Content = AMFAV1.GetSpeed(SliderEncoderPreset.Value);
71 | }
72 | }
73 |
74 | private void CheckBoxTwoPassEncoding_Toggled(object sender, RoutedEventArgs e)
75 | {
76 | if (MainWindow.startupLock) return;
77 |
78 | // Get MainWindow instance to access UI elements
79 | MainWindow mainWindow = Application.Current.MainWindow as MainWindow;
80 |
81 | if (mainWindow.VideoTabVideoPartialControl.ComboBoxVideoEncoder.SelectedIndex == (int)Video.Encoders.SVTAV1 && mainWindow.VideoTabVideoQualityControl.ComboBoxQualityModeSVTAV1.SelectedIndex == 0 && CheckBoxTwoPassEncoding.IsOn)
82 | {
83 | CheckBoxTwoPassEncoding.IsOn = false;
84 | }
85 |
86 | if (mainWindow.VideoTabVideoPartialControl.ComboBoxVideoEncoder.SelectedIndex == (int)Video.Encoders.SVTAV1FFMPEG && mainWindow.VideoTabVideoQualityControl.ComboBoxQualityModeSVTAV1FFMPEG.SelectedIndex == 0 && CheckBoxTwoPassEncoding.IsOn)
87 | {
88 | CheckBoxTwoPassEncoding.IsOn = false;
89 | }
90 |
91 | if (CheckBoxRealTimeMode.IsOn && CheckBoxTwoPassEncoding.IsOn)
92 | {
93 | CheckBoxTwoPassEncoding.IsOn = false;
94 | }
95 | }
96 |
97 | private void CheckBoxRealTimeMode_Toggled(object sender, RoutedEventArgs e)
98 | {
99 | // Reverts to 1 Pass encoding if Real Time Mode is activated
100 | if (CheckBoxRealTimeMode.IsOn && CheckBoxTwoPassEncoding.IsOn)
101 | {
102 | CheckBoxTwoPassEncoding.IsOn = false;
103 | }
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Views/BatchFolderDialog.xaml:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
35 |
36 |
37 |
38 |
39 |
45 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Views/BatchFolderDialog.xaml.cs:
--------------------------------------------------------------------------------
1 | using ControlzEx.Theming;
2 | using MahApps.Metro.Controls;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Windows;
7 |
8 | namespace NotEnoughAV1Encodes.Views
9 | {
10 | public partial class BatchFolderDialog : MetroWindow
11 | {
12 | public bool Quit { get; set; }
13 | public bool PresetBitdepth { get; set; }
14 | public bool ActivateSubtitles { get; set; } = true;
15 | public bool MirrorFolderStructure { get; set; }
16 | public string Input { get; set; }
17 | public string Preset { get; set; }
18 | public string Output { get; set; }
19 | public int Container { get; set; }
20 |
21 | public List Files = new();
22 |
23 | private bool OutputSelected = false;
24 |
25 | public BatchFolderDialog(string theme, string folderPath, bool subfolders)
26 | {
27 | InitializeComponent();
28 | try { ThemeManager.Current.ChangeTheme(this, theme); } catch { }
29 |
30 | Input = folderPath;
31 |
32 | SearchOption searchOption = SearchOption.TopDirectoryOnly;
33 | if (subfolders)
34 | {
35 | searchOption = SearchOption.AllDirectories;
36 | }
37 |
38 | // "Video Files|*.mp4;*.mkv;*.webm;*.flv;*.avi;*.mov;*.wmv;
39 | var files = Directory.EnumerateFiles(folderPath, "*.*", searchOption)
40 | .Where(s => s.ToLower().EndsWith(".mp4") ||
41 | s.ToLower().EndsWith(".mkv") ||
42 | s.ToLower().EndsWith(".webm") ||
43 | s.ToLower().EndsWith(".flv") ||
44 | s.ToLower().EndsWith(".avi") ||
45 | s.ToLower().EndsWith(".mov") ||
46 | s.ToLower().EndsWith(".wmv") ||
47 | s.ToLower().EndsWith(".mpg") ||
48 | s.ToLower().EndsWith(".ts"));
49 |
50 | foreach (var file in files)
51 | {
52 | ListBoxVideoItems.Items.Add(file);
53 | }
54 |
55 | // Load Presets
56 | if (Directory.Exists(Path.Combine(Global.AppData, "NEAV1E", "Presets")))
57 | {
58 | string[] filePaths = Directory.GetFiles(Path.Combine(Global.AppData, "NEAV1E", "Presets"), "*.json", SearchOption.TopDirectoryOnly);
59 |
60 | foreach (string file in filePaths)
61 | {
62 | ComboBoxPresets.Items.Add(Path.GetFileNameWithoutExtension(file));
63 | }
64 |
65 | try { ComboBoxPresets.SelectedIndex = 0; } catch { }
66 | }
67 |
68 | // Set Default Values
69 | ToggleSwitchUsePresetBitDepth.IsOn = true;
70 | }
71 |
72 | private void ButtonSelectDestination_Click(object sender, RoutedEventArgs e)
73 | {
74 | System.Windows.Forms.FolderBrowserDialog openFileDlg = new System.Windows.Forms.FolderBrowserDialog();
75 | var result = openFileDlg.ShowDialog();
76 | if (result.ToString() != string.Empty)
77 | {
78 | TextBoxDestination.Text = openFileDlg.SelectedPath;
79 | OutputSelected = true;
80 | }
81 | }
82 |
83 | private void ListBoxVideoItems_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
84 | {
85 | if (ListBoxVideoItems.SelectedItem == null) return;
86 | if (e.Key == System.Windows.Input.Key.Delete)
87 | {
88 | ListBoxVideoItems.Items.Remove(ListBoxVideoItems.SelectedItem);
89 | }
90 | }
91 |
92 | private void QueueMenuItemDelete_Click(object sender, RoutedEventArgs e)
93 | {
94 | if (ListBoxVideoItems.SelectedItem == null) return;
95 | ListBoxVideoItems.Items.Remove(ListBoxVideoItems.SelectedItem);
96 | }
97 |
98 | private void ButtonAddToQueue_Click(object sender, RoutedEventArgs e)
99 | {
100 | // Return if Output is not selected
101 | if (!OutputSelected)
102 | {
103 |
104 | MessageBoxResult result = MessageBox.Show("Please select a Destination!", "Error", MessageBoxButton.YesNo);
105 | if (result == MessageBoxResult.Yes)
106 | {
107 | ButtonSelectDestination_Click(sender, e);
108 | }
109 | return;
110 | }
111 | else
112 | {
113 | foreach (string files in ListBoxVideoItems.Items) Files.Add(files);
114 | Container = ComboBoxContainer.SelectedIndex;
115 | Preset = ComboBoxPresets.SelectedItem.ToString();
116 | Output = TextBoxDestination.Text;
117 | PresetBitdepth = ToggleSwitchUsePresetBitDepth.IsOn;
118 | ActivateSubtitles = ToggleSwitchActivateSubtitles.IsOn;
119 | MirrorFolderStructure = ToggleSwitchMirrorFolderStructure.IsOn;
120 | Quit = true;
121 | Close();
122 | }
123 | }
124 |
125 | private void ButtonCancelEncode_Click(object sender, System.Windows.RoutedEventArgs e)
126 | {
127 | Close();
128 | }
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Encoders/Aomenc.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Windows;
3 |
4 | namespace NotEnoughAV1Encodes.Encoders
5 | {
6 | class Aomenc : IEncoder
7 | {
8 | public string GetCommand()
9 | {
10 | // Get MainWindow instance to access UI elements
11 | MainWindow mainWindow = Application.Current.MainWindow as MainWindow;
12 |
13 | string settings = "-f yuv4mpegpipe - | " +
14 | "\"" + Path.Combine(Directory.GetCurrentDirectory(), "Apps", "aomenc", "aomenc.exe") + "\" -";
15 |
16 | // Quality / Bitrate Selection
17 | string quality = mainWindow.VideoTabVideoQualityControl.ComboBoxQualityModeAOMENC.SelectedIndex switch
18 | {
19 | 0 => " --cq-level=" + mainWindow.VideoTabVideoQualityControl.SliderQualityAOMENC.Value + " --end-usage=q",
20 | 1 => " --cq-level=" + mainWindow.VideoTabVideoQualityControl.SliderQualityAOMENC.Value + " --target-bitrate=" + mainWindow.VideoTabVideoQualityControl.TextBoxBitrateAOMENC.Text + " --end-usage=cq",
21 | 2 => " --target-bitrate=" + mainWindow.VideoTabVideoQualityControl.TextBoxBitrateAOMENC.Text + " --end-usage=vbr",
22 | 3 => " --target-bitrate=" + mainWindow.VideoTabVideoQualityControl.TextBoxBitrateAOMENC.Text + " --end-usage=cbr",
23 | _ => ""
24 | };
25 |
26 | // Preset
27 | settings += quality + " --cpu-used=" + mainWindow.VideoTabVideoOptimizationControl.SliderEncoderPreset.Value;
28 |
29 | // Advanced Settings
30 | if (mainWindow.VideoTabVideoOptimizationControl.ToggleSwitchAdvancedSettings.IsOn == false)
31 | {
32 | settings += " --threads=4 --tile-columns=2 --tile-rows=1 --kf-max-dist=" + mainWindow.VideoTabVideoPartialControl.GenerateKeyFrameInerval();
33 | }
34 | else
35 | {
36 | settings += " --threads=" + mainWindow.AdvancedTabControl.ComboBoxAomencThreads.Text + // Threads
37 | " --tile-columns=" + mainWindow.AdvancedTabControl.ComboBoxAomencTileColumns.Text + // Tile Columns
38 | " --tile-rows=" + mainWindow.AdvancedTabControl.ComboBoxAomencTileRows.Text + // Tile Rows
39 | " --lag-in-frames=" + mainWindow.AdvancedTabControl.TextBoxAomencLagInFrames.Text + // Lag in Frames
40 | " --sharpness=" + mainWindow.AdvancedTabControl.ComboBoxAomencSharpness.Text + // Sharpness (Filter)
41 | " --aq-mode=" + mainWindow.AdvancedTabControl.ComboBoxAomencAQMode.SelectedIndex + // AQ-Mode
42 | " --enable-keyframe-filtering=" + mainWindow.AdvancedTabControl.ComboBoxAomencKeyFiltering.SelectedIndex + // Key Frame Filtering
43 | " --tune=" + mainWindow.AdvancedTabControl.ComboBoxAomencTune.Text + // Tune
44 | " --tune-content=" + mainWindow.AdvancedTabControl.ComboBoxAomencTuneContent.Text; // Tune-Content
45 |
46 | if (mainWindow.AdvancedTabControl.TextBoxAomencMaxGOP.Text != "0")
47 | settings += " --kf-max-dist=" + mainWindow.AdvancedTabControl.TextBoxAomencMaxGOP.Text; // Keyframe Interval
48 | if (mainWindow.AdvancedTabControl.CheckBoxAomencRowMT.IsChecked == false)
49 | settings += " --row-mt=0"; // Row Based Multithreading
50 |
51 | if (mainWindow.AdvancedTabControl.ComboBoxAomencColorPrimaries.SelectedIndex != 0)
52 | settings += " --color-primaries=" + mainWindow.AdvancedTabControl.ComboBoxAomencColorPrimaries.Text; // Color Primaries
53 | if (mainWindow.AdvancedTabControl.ComboBoxAomencColorTransfer.SelectedIndex != 0)
54 | settings += " --transfer-characteristics=" + mainWindow.AdvancedTabControl.ComboBoxAomencColorTransfer.Text; // Color Transfer
55 | if (mainWindow.AdvancedTabControl.ComboBoxAomencColorMatrix.SelectedIndex != 0)
56 | settings += " --matrix-coefficients=" + mainWindow.AdvancedTabControl.ComboBoxAomencColorMatrix.Text; // Color Matrix
57 |
58 | if (mainWindow.AdvancedTabControl.CheckBoxAomencCDEF.IsChecked == false)
59 | settings += " --enable-cdef=0"; // Constrained Directional Enhancement Filter
60 |
61 | if (mainWindow.AdvancedTabControl.CheckBoxAomencARNRMax.IsChecked == true)
62 | {
63 | settings += " --arnr-maxframes=" + mainWindow.AdvancedTabControl.ComboBoxAomencARNRMax.Text; // ARNR Maxframes
64 | settings += " --arnr-strength=" + mainWindow.AdvancedTabControl.ComboBoxAomencARNRStrength.Text; // ARNR Strength
65 | }
66 |
67 | if (mainWindow.VideoTabVideoOptimizationControl.CheckBoxRealTimeMode.IsOn)
68 | settings += " --rt"; // Real Time Mode
69 | }
70 |
71 | return settings;
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Encoders/AOMAV1FFmpeg.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace NotEnoughAV1Encodes.Encoders
4 | {
5 | class AOMAV1FFmpeg : IEncoder
6 | {
7 | public string GetCommand()
8 | {
9 | // Get MainWindow instance to access UI elements
10 | MainWindow mainWindow = Application.Current.MainWindow as MainWindow;
11 |
12 | string settings = "-c:v libaom-av1";
13 |
14 | // Quality / Bitrate Selection
15 | string quality = mainWindow.VideoTabVideoQualityControl.ComboBoxQualityMode.SelectedIndex switch
16 | {
17 | 0 => " -crf " + mainWindow.VideoTabVideoQualityControl.SliderQualityAOMFFMPEG.Value + " -b:v 0",
18 | 1 => " -crf " + mainWindow.VideoTabVideoQualityControl.SliderQualityAOMFFMPEG.Value + " -b:v " + mainWindow.VideoTabVideoQualityControl.TextBoxMaxBitrateAOMFFMPEG.Text + "k",
19 | 2 => " -b:v " + mainWindow.VideoTabVideoQualityControl.TextBoxMinBitrateAOMFFMPEG.Text + "k",
20 | 3 => " -minrate " + mainWindow.VideoTabVideoQualityControl.TextBoxMinBitrateAOMFFMPEG.Text + "k -b:v " + mainWindow.VideoTabVideoQualityControl.TextBoxAVGBitrateAOMFFMPEG.Text + "k -maxrate " + mainWindow.VideoTabVideoQualityControl.TextBoxMaxBitrateAOMFFMPEG.Text + "k",
21 | 4 => " -crf {q_vmaf} -b:v 0",
22 | _ => ""
23 | };
24 |
25 | // Preset
26 | settings += quality + " -cpu-used " + mainWindow.VideoTabVideoOptimizationControl.SliderEncoderPreset.Value;
27 |
28 | // Advanced Settings
29 | if (mainWindow.VideoTabVideoOptimizationControl.ToggleSwitchAdvancedSettings.IsOn == false)
30 | {
31 | settings += " -threads 4 -tile-columns 2 -tile-rows 1 -g " + mainWindow.VideoTabVideoPartialControl.GenerateKeyFrameInerval();
32 | }
33 | else
34 | {
35 | settings += " -threads " + mainWindow.AdvancedTabControl.ComboBoxAomencThreads.Text + // Threads
36 | " -tile-columns " + mainWindow.AdvancedTabControl.ComboBoxAomencTileColumns.Text + // Tile Columns
37 | " -tile-rows " + mainWindow.AdvancedTabControl.ComboBoxAomencTileRows.Text + // Tile Rows
38 | " -lag-in-frames " + mainWindow.AdvancedTabControl.TextBoxAomencLagInFrames.Text + // Lag in Frames
39 | " -aq-mode " + mainWindow.AdvancedTabControl.ComboBoxAomencAQMode.SelectedIndex + // AQ-Mode
40 | " -tune " + mainWindow.AdvancedTabControl.ComboBoxAomencTune.Text; // Tune
41 |
42 | if (mainWindow.AdvancedTabControl.TextBoxAomencMaxGOP.Text != "0")
43 | settings += " -g " + mainWindow.AdvancedTabControl.TextBoxAomencMaxGOP.Text; // Keyframe Interval
44 | if (mainWindow.AdvancedTabControl.CheckBoxAomencRowMT.IsChecked == false)
45 | settings += " -row-mt 0"; // Row Based Multithreading
46 | if (mainWindow.AdvancedTabControl.CheckBoxAomencCDEF.IsChecked == false)
47 | settings += " -enable-cdef 0"; // Constrained Directional Enhancement Filter
48 | if (mainWindow.VideoTabVideoOptimizationControl.CheckBoxRealTimeMode.IsOn)
49 | settings += " -usage realtime "; // Real Time Mode
50 |
51 | if (mainWindow.AdvancedTabControl.CheckBoxAomencARNRMax.IsChecked == true)
52 | {
53 | settings += " -arnr-max-frames " + mainWindow.AdvancedTabControl.ComboBoxAomencARNRMax.Text; // ARNR Maxframes
54 | settings += " -arnr-strength " + mainWindow.AdvancedTabControl.ComboBoxAomencARNRStrength.Text; // ARNR Strength
55 | }
56 |
57 | settings += " -aom-params " +
58 | "tune-content=" + mainWindow.AdvancedTabControl.ComboBoxAomencTuneContent.Text + // Tune-Content
59 | ":sharpness=" + mainWindow.AdvancedTabControl.ComboBoxAomencSharpness.Text + // Sharpness (Filter)
60 | ":enable-keyframe-filtering=" + mainWindow.AdvancedTabControl.ComboBoxAomencKeyFiltering.SelectedIndex; // Key Frame Filtering
61 |
62 | if (mainWindow.AdvancedTabControl.ComboBoxAomencColorPrimaries.SelectedIndex != 0)
63 | settings += ":color-primaries=" + mainWindow.AdvancedTabControl.ComboBoxAomencColorPrimaries.Text; // Color Primaries
64 | if (mainWindow.AdvancedTabControl.ComboBoxAomencColorTransfer.SelectedIndex != 0)
65 | settings += ":transfer-characteristics=" + mainWindow.AdvancedTabControl.ComboBoxAomencColorTransfer.Text; // Color Transfer
66 | if (mainWindow.AdvancedTabControl.ComboBoxAomencColorMatrix.SelectedIndex != 0)
67 | settings += ":matrix-coefficients=" + mainWindow.AdvancedTabControl.ComboBoxAomencColorMatrix.Text; // Color Matrix
68 | }
69 |
70 | return settings;
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Controls/Partials/VideoTabVideo.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Controls/AudioTab.xaml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
25 |
26 |
27 |
28 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | Sets the Audio Encoder. Recommended: Opus
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 | Sets the audio bitrate. Recommended for Opus: 96 - 128 for Stereo
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Build results
17 | [Dd]ebug/
18 | [Dd]ebugPublic/
19 | [Rr]elease/
20 | [Rr]eleases/
21 | x64/
22 | x86/
23 | [Aa][Rr][Mm]/
24 | [Aa][Rr][Mm]64/
25 | bld/
26 | [Bb]in/
27 | [Oo]bj/
28 | [Ll]og/
29 |
30 | # Visual Studio 2015/2017 cache/options directory
31 | .vs/
32 | # Uncomment if you have tasks that create the project's static files in wwwroot
33 | #wwwroot/
34 |
35 | # Visual Studio 2017 auto generated files
36 | Generated\ Files/
37 |
38 | # MSTest test Results
39 | [Tt]est[Rr]esult*/
40 | [Bb]uild[Ll]og.*
41 |
42 | # NUNIT
43 | *.VisualState.xml
44 | TestResult.xml
45 |
46 | # Build Results of an ATL Project
47 | [Dd]ebugPS/
48 | [Rr]eleasePS/
49 | dlldata.c
50 |
51 | # Benchmark Results
52 | BenchmarkDotNet.Artifacts/
53 |
54 | # .NET Core
55 | project.lock.json
56 | project.fragment.lock.json
57 | artifacts/
58 |
59 | # StyleCop
60 | StyleCopReport.xml
61 |
62 | # Files built by Visual Studio
63 | *_i.c
64 | *_p.c
65 | *_h.h
66 | *.ilk
67 | *.meta
68 | *.obj
69 | *.iobj
70 | *.pch
71 | *.pdb
72 | *.ipdb
73 | *.pgc
74 | *.pgd
75 | *.rsp
76 | *.sbr
77 | *.tlb
78 | *.tli
79 | *.tlh
80 | *.tmp
81 | *.tmp_proj
82 | *_wpftmp.csproj
83 | *.log
84 | *.vspscc
85 | *.vssscc
86 | .builds
87 | *.pidb
88 | *.svclog
89 | *.scc
90 |
91 | # Chutzpah Test files
92 | _Chutzpah*
93 |
94 | # Visual C++ cache files
95 | ipch/
96 | *.aps
97 | *.ncb
98 | *.opendb
99 | *.opensdf
100 | *.sdf
101 | *.cachefile
102 | *.VC.db
103 | *.VC.VC.opendb
104 |
105 | # Visual Studio profiler
106 | *.psess
107 | *.vsp
108 | *.vspx
109 | *.sap
110 |
111 | # Visual Studio Trace Files
112 | *.e2e
113 |
114 | # TFS 2012 Local Workspace
115 | $tf/
116 |
117 | # Guidance Automation Toolkit
118 | *.gpState
119 |
120 | # ReSharper is a .NET coding add-in
121 | _ReSharper*/
122 | *.[Rr]e[Ss]harper
123 | *.DotSettings.user
124 |
125 | # JustCode is a .NET coding add-in
126 | .JustCode
127 |
128 | # TeamCity is a build add-in
129 | _TeamCity*
130 |
131 | # DotCover is a Code Coverage Tool
132 | *.dotCover
133 |
134 | # AxoCover is a Code Coverage Tool
135 | .axoCover/*
136 | !.axoCover/settings.json
137 |
138 | # Visual Studio code coverage results
139 | *.coverage
140 | *.coveragexml
141 |
142 | # NCrunch
143 | _NCrunch_*
144 | .*crunch*.local.xml
145 | nCrunchTemp_*
146 |
147 | # MightyMoose
148 | *.mm.*
149 | AutoTest.Net/
150 |
151 | # Web workbench (sass)
152 | .sass-cache/
153 |
154 | # Installshield output folder
155 | [Ee]xpress/
156 |
157 | # DocProject is a documentation generator add-in
158 | DocProject/buildhelp/
159 | DocProject/Help/*.HxT
160 | DocProject/Help/*.HxC
161 | DocProject/Help/*.hhc
162 | DocProject/Help/*.hhk
163 | DocProject/Help/*.hhp
164 | DocProject/Help/Html2
165 | DocProject/Help/html
166 |
167 | # Click-Once directory
168 | publish/
169 |
170 | # Publish Web Output
171 | *.[Pp]ublish.xml
172 | *.azurePubxml
173 | # Note: Comment the next line if you want to checkin your web deploy settings,
174 | # but database connection strings (with potential passwords) will be unencrypted
175 | *.pubxml
176 | *.publishproj
177 |
178 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
179 | # checkin your Azure Web App publish settings, but sensitive information contained
180 | # in these scripts will be unencrypted
181 | PublishScripts/
182 |
183 | # NuGet Packages
184 | *.nupkg
185 | # The packages folder can be ignored because of Package Restore
186 | **/[Pp]ackages/*
187 | # except build/, which is used as an MSBuild target.
188 | !**/[Pp]ackages/build/
189 | # Uncomment if necessary however generally it will be regenerated when needed
190 | #!**/[Pp]ackages/repositories.config
191 | # NuGet v3's project.json files produces more ignorable files
192 | *.nuget.props
193 | *.nuget.targets
194 |
195 | # Microsoft Azure Build Output
196 | csx/
197 | *.build.csdef
198 |
199 | # Microsoft Azure Emulator
200 | ecf/
201 | rcf/
202 |
203 | # Windows Store app package directories and files
204 | AppPackages/
205 | BundleArtifacts/
206 | Package.StoreAssociation.xml
207 | _pkginfo.txt
208 | *.appx
209 |
210 | # Visual Studio cache files
211 | # files ending in .cache can be ignored
212 | *.[Cc]ache
213 | # but keep track of directories ending in .cache
214 | !?*.[Cc]ache/
215 |
216 | # Others
217 | ClientBin/
218 | ~$*
219 | *~
220 | *.dbmdl
221 | *.dbproj.schemaview
222 | *.jfm
223 | *.pfx
224 | *.publishsettings
225 | orleans.codegen.cs
226 |
227 | # Including strong name files can present a security risk
228 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
229 | #*.snk
230 |
231 | # Since there are multiple workflows, uncomment next line to ignore bower_components
232 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
233 | #bower_components/
234 |
235 | # RIA/Silverlight projects
236 | Generated_Code/
237 |
238 | # Backup & report files from converting an old project file
239 | # to a newer Visual Studio version. Backup files are not needed,
240 | # because we have git ;-)
241 | _UpgradeReport_Files/
242 | Backup*/
243 | UpgradeLog*.XML
244 | UpgradeLog*.htm
245 | ServiceFabricBackup/
246 | *.rptproj.bak
247 |
248 | # SQL Server files
249 | *.mdf
250 | *.ldf
251 | *.ndf
252 |
253 | # Business Intelligence projects
254 | *.rdl.data
255 | *.bim.layout
256 | *.bim_*.settings
257 | *.rptproj.rsuser
258 | *- Backup*.rdl
259 |
260 | # Microsoft Fakes
261 | FakesAssemblies/
262 |
263 | # GhostDoc plugin setting file
264 | *.GhostDoc.xml
265 |
266 | # Node.js Tools for Visual Studio
267 | .ntvs_analysis.dat
268 | node_modules/
269 |
270 | # Visual Studio 6 build log
271 | *.plg
272 |
273 | # Visual Studio 6 workspace options file
274 | *.opt
275 |
276 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
277 | *.vbw
278 |
279 | # Visual Studio LightSwitch build output
280 | **/*.HTMLClient/GeneratedArtifacts
281 | **/*.DesktopClient/GeneratedArtifacts
282 | **/*.DesktopClient/ModelManifest.xml
283 | **/*.Server/GeneratedArtifacts
284 | **/*.Server/ModelManifest.xml
285 | _Pvt_Extensions
286 |
287 | # Paket dependency manager
288 | .paket/paket.exe
289 | paket-files/
290 |
291 | # FAKE - F# Make
292 | .fake/
293 |
294 | # JetBrains Rider
295 | .idea/
296 | *.sln.iml
297 |
298 | # CodeRush personal settings
299 | .cr/personal
300 |
301 | # Python Tools for Visual Studio (PTVS)
302 | __pycache__/
303 | *.pyc
304 |
305 | # Cake - Uncomment if you are using it
306 | # tools/**
307 | # !tools/packages.config
308 |
309 | # Tabs Studio
310 | *.tss
311 |
312 | # Telerik's JustMock configuration file
313 | *.jmconfig
314 |
315 | # BizTalk build output
316 | *.btp.cs
317 | *.btm.cs
318 | *.odx.cs
319 | *.xsd.cs
320 |
321 | # OpenCover UI analysis results
322 | OpenCover/
323 |
324 | # Azure Stream Analytics local run output
325 | ASALocalRun/
326 |
327 | # MSBuild Binary and Structured Log
328 | *.binlog
329 |
330 | # NVidia Nsight GPU debugger configuration file
331 | *.nvuser
332 |
333 | # MFractors (Xamarin productivity tool) working folder
334 | .mfractor/
335 |
336 | # Local History for Visual Studio
337 | .localhistory/
338 |
339 | # BeatPulse healthcheck temp database
340 | healthchecksdb
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Controls/SummaryTab.xaml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Views/ProgramSettings.xaml.cs:
--------------------------------------------------------------------------------
1 | using ControlzEx.Theming;
2 | using MahApps.Metro.Controls;
3 | using Microsoft.Win32;
4 | using System.Diagnostics;
5 | using System.Globalization;
6 | using System.IO;
7 | using System.Reflection;
8 | using System.Windows;
9 | using System.Windows.Navigation;
10 | using WPFLocalizeExtension.Engine;
11 |
12 | namespace NotEnoughAV1Encodes.Views
13 | {
14 | public partial class ProgramSettings : MetroWindow
15 | {
16 | public Settings settingsDBTemp = new();
17 |
18 | public ProgramSettings(Settings settingsDB)
19 | {
20 | InitializeComponent();
21 | settingsDBTemp = settingsDB;
22 | ToggleSwitchDeleteTempFiles.IsOn = settingsDB.DeleteTempFiles;
23 | ToggleSwitchAutoPauseResume.IsOn = settingsDB.AutoResumePause;
24 | ToggleSwitchInputSeeking.IsOn = settingsDB.UseInputSeeking;
25 | ToggleSwitchShutdown.IsOn = settingsDB.ShutdownAfterEncode;
26 | ToggleSwitchLogging.IsOn = settingsDB.Logging;
27 | ToggleSwitchClearQueue.IsOn = settingsDB.AutoClearQueue;
28 | ToggleSwitchBatchSubFolders.IsOn = settingsDB.SubfolderBatch;
29 | ComboBoxAccentTheme.SelectedIndex = settingsDB.AccentTheme;
30 | ComboBoxBaseTheme.SelectedIndex = settingsDB.BaseTheme;
31 | TextBoxTempPath.Text = settingsDB.TempPath;
32 | TextBoxDefaultOutPath.Text = settingsDB.DefaultOutPath;
33 | settingsDBTemp.BGImage = settingsDB.BGImage;
34 | ComboBoxProcessPriority.SelectedIndex = settingsDB.PriorityNormal ? 0 : 1;
35 | string AssemblyVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString();
36 | LabelVersion1.Content = AssemblyVersion.Remove(AssemblyVersion.Length - 2);
37 | try
38 | {
39 | ThemeManager.Current.ChangeTheme(this, settingsDB.Theme);
40 | }
41 | catch { }
42 |
43 |
44 | ComboBoxLanguage.SelectedIndex = settingsDB.CultureInfo.Name switch
45 | {
46 | "en" => 0,
47 | "de" => 1,
48 | "zh-CN" => 2,
49 | "ru-RU" => 3,
50 | "ja-JP" => 4,
51 | "it-IT" => 5,
52 | "fr-FR" => 6,
53 | _ => 0,
54 | };
55 |
56 | ComboBoxDefaultOutContainer.SelectedIndex = settingsDB.DefaultOutContainer switch
57 | {
58 | ".mkv" => 0,
59 | ".webm" => 1,
60 | ".mp4" => 2,
61 | _ => 0,
62 | };
63 | }
64 |
65 | private void ButtonSelectBGImage_Click(object sender, RoutedEventArgs e)
66 | {
67 | OpenFileDialog openFileDialog = new()
68 | {
69 | Filter = "Image Files|*.jpg;*.jpeg;*.png;*.bmp"
70 | };
71 | if (openFileDialog.ShowDialog() == true)
72 | {
73 | settingsDBTemp.BGImage = openFileDialog.FileName;
74 | }
75 | }
76 |
77 | private void ButtonSelectTempPath_Click(object sender, RoutedEventArgs e)
78 | {
79 | using var dialog = new System.Windows.Forms.FolderBrowserDialog();
80 | dialog.SelectedPath = TextBoxTempPath.Text;
81 | System.Windows.Forms.DialogResult result = dialog.ShowDialog();
82 | if (result == System.Windows.Forms.DialogResult.OK)
83 | {
84 | TextBoxTempPath.Text = dialog.SelectedPath + "\\";
85 | }
86 | }
87 |
88 | private void ButtonSelectDefaultOutPath_Click(object sender, RoutedEventArgs e)
89 | {
90 | using var dialog = new System.Windows.Forms.FolderBrowserDialog();
91 | dialog.SelectedPath = TextBoxTempPath.Text;
92 | System.Windows.Forms.DialogResult result = dialog.ShowDialog();
93 | if (result == System.Windows.Forms.DialogResult.OK)
94 | {
95 | TextBoxDefaultOutPath.Text = dialog.SelectedPath + "\\";
96 | }
97 | }
98 |
99 | private void ButtonSelectDefaultOutPathReset_Click(object sender, RoutedEventArgs e)
100 | {
101 | TextBoxDefaultOutPath.Text = "";
102 | }
103 |
104 | private void ButtonSelectTempPathReset_Click(object sender, RoutedEventArgs e)
105 | {
106 | TextBoxTempPath.Text = Path.GetTempPath();
107 | }
108 |
109 | private void ButtonUpdater_Click(object sender, RoutedEventArgs e)
110 | {
111 | Updater updater = new(ComboBoxBaseTheme.Text, ComboBoxAccentTheme.Text);
112 | updater.ShowDialog();
113 | }
114 |
115 | private void MetroWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
116 | {
117 | settingsDBTemp.DeleteTempFiles = ToggleSwitchDeleteTempFiles.IsOn;
118 | settingsDBTemp.AutoResumePause = ToggleSwitchAutoPauseResume.IsOn;
119 | settingsDBTemp.UseInputSeeking = ToggleSwitchInputSeeking.IsOn;
120 | settingsDBTemp.ShutdownAfterEncode = ToggleSwitchShutdown.IsOn;
121 | settingsDBTemp.Logging = ToggleSwitchLogging.IsOn;
122 | settingsDBTemp.AutoClearQueue = ToggleSwitchClearQueue.IsOn;
123 | settingsDBTemp.SubfolderBatch = ToggleSwitchBatchSubFolders.IsOn;
124 | settingsDBTemp.BaseTheme = ComboBoxBaseTheme.SelectedIndex;
125 | settingsDBTemp.AccentTheme = ComboBoxAccentTheme.SelectedIndex;
126 | settingsDBTemp.Theme = ComboBoxBaseTheme.Text + "." + ComboBoxAccentTheme.Text;
127 | settingsDBTemp.TempPath = TextBoxTempPath.Text;
128 | settingsDBTemp.DefaultOutPath = TextBoxDefaultOutPath.Text;
129 | settingsDBTemp.DefaultOutContainer = ComboBoxDefaultOutContainer.Text;
130 | settingsDBTemp.PriorityNormal = ComboBoxProcessPriority.SelectedIndex == 0;
131 | }
132 |
133 | private void ButtonResetBGImage_Click(object sender, RoutedEventArgs e)
134 | {
135 | settingsDBTemp.BGImage = null;
136 | }
137 |
138 | private void ComboBoxLanguage_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
139 | {
140 | if (ComboBoxLanguage == null) return;
141 | settingsDBTemp.CultureInfo = ComboBoxLanguage.SelectedIndex switch
142 | {
143 | 0 => new CultureInfo("en"),
144 | 1 => new CultureInfo("de"),
145 | 2 => new CultureInfo("zh-CN"),
146 | 3 => new CultureInfo("ru-RU"),
147 | 4 => new CultureInfo("ja-JP"),
148 | 5 => new CultureInfo("it-IT"),
149 | 6 => new CultureInfo("fr-FR"),
150 | _ => new CultureInfo("en"),
151 | };
152 | LocalizeDictionary.Instance.Culture = settingsDBTemp.CultureInfo;
153 | }
154 |
155 | private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e)
156 | {
157 | ProcessStartInfo psi = new()
158 | {
159 | FileName = "cmd",
160 | WindowStyle = ProcessWindowStyle.Hidden,
161 | UseShellExecute = false,
162 | CreateNoWindow = true,
163 | Arguments = $"/c start {e.Uri}"
164 | };
165 | Process.Start(psi);
166 | }
167 |
168 | private void ButtonExit_Click(object sender, RoutedEventArgs e)
169 | {
170 | Close();
171 | }
172 | }
173 | }
174 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Controls/SummaryTab.xaml.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System.IO;
3 | using System;
4 | using System.Windows.Controls;
5 | using System.Windows;
6 | using System.Text.RegularExpressions;
7 | using System.Windows.Input;
8 | using NotEnoughAV1Encodes.Video;
9 | using System.Collections.Generic;
10 |
11 | namespace NotEnoughAV1Encodes.Controls
12 | {
13 | public partial class SummaryTab : UserControl
14 | {
15 | public string Encoder { get; set; }
16 |
17 | public SummaryTab()
18 | {
19 | InitializeComponent();
20 | }
21 |
22 | private void NumberValidationTextBox(object sender, TextCompositionEventArgs e)
23 | {
24 | // Validates that the TextBox Input are only numbers
25 | Regex regex = new("[^0-9]+");
26 | e.Handled = regex.IsMatch(e.Text);
27 | }
28 |
29 | private void ButtonDeletePreset_Click(object sender, RoutedEventArgs e)
30 | {
31 | try
32 | {
33 | File.Delete(Path.Combine(Global.AppData, "NEAV1E", "Presets", ComboBoxPresets.Text + ".json"));
34 | }
35 | catch (Exception ex) { MessageBox.Show(ex.Message); }
36 |
37 | try
38 | {
39 | ComboBoxPresets.Items.Clear();
40 | LoadPresets();
41 | }
42 | catch { }
43 |
44 | }
45 |
46 | public void LoadPresets()
47 | {
48 | // Load Presets
49 | if (Directory.Exists(Path.Combine(Global.AppData, "NEAV1E", "Presets")))
50 | {
51 | string[] filePaths = Directory.GetFiles(Path.Combine(Global.AppData, "NEAV1E", "Presets"), "*.json", SearchOption.TopDirectoryOnly);
52 |
53 | foreach (string file in filePaths)
54 | {
55 | ComboBoxPresets.Items.Add(Path.GetFileNameWithoutExtension(file));
56 | }
57 | }
58 | }
59 |
60 | private void ButtonSetPresetDefault_Click(object sender, RoutedEventArgs e)
61 | {
62 | // Get MainWindow instance to access UI elements
63 | MainWindow mainWindow = Application.Current.MainWindow as MainWindow;
64 | mainWindow.settingsDB.DefaultPreset = ComboBoxPresets.Text;
65 |
66 | SaveSettings();
67 | }
68 |
69 | private void SaveSettings()
70 | {
71 | try
72 | {
73 | // Get MainWindow instance to access UI elements
74 | MainWindow mainWindow = Application.Current.MainWindow as MainWindow;
75 |
76 | Directory.CreateDirectory(Path.Combine(Global.AppData, "NEAV1E"));
77 | File.WriteAllText(Path.Combine(Global.AppData, "NEAV1E", "settings.json"), JsonConvert.SerializeObject(mainWindow.settingsDB, Formatting.Indented));
78 | }
79 | catch (Exception ex) { MessageBox.Show(ex.Message); }
80 | }
81 |
82 | private void ButtonSavePreset_Click(object sender, RoutedEventArgs e)
83 | {
84 | // Get MainWindow instance to access UI elements
85 | MainWindow mainWindow = Application.Current.MainWindow as MainWindow;
86 |
87 | Views.SavePresetDialog savePresetDialog = new(mainWindow.settingsDB.Theme);
88 | savePresetDialog.ShowDialog();
89 | if (savePresetDialog.Quit)
90 | {
91 | Directory.CreateDirectory(Path.Combine(Global.AppData, "NEAV1E", "Presets"));
92 | mainWindow.PresetSettings.PresetBatchName = savePresetDialog.PresetBatchName;
93 | mainWindow.PresetSettings.AudioCodecMono = savePresetDialog.AudioCodecMono;
94 | mainWindow.PresetSettings.AudioCodecStereo = savePresetDialog.AudioCodecStereo;
95 | mainWindow.PresetSettings.AudioCodecSixChannel = savePresetDialog.AudioCodecSixChannel;
96 | mainWindow.PresetSettings.AudioCodecEightChannel = savePresetDialog.AudioCodecEightChannel;
97 | mainWindow.PresetSettings.AudioBitrateMono = savePresetDialog.AudioBitrateMono;
98 | mainWindow.PresetSettings.AudioBitrateStereo = savePresetDialog.AudioBitrateStereo;
99 | mainWindow.PresetSettings.AudioBitrateSixChannel = savePresetDialog.AudioBitrateSixChannel;
100 | mainWindow.PresetSettings.AudioBitrateEightChannel = savePresetDialog.AudioBitrateEightChannel;
101 | File.WriteAllText(Path.Combine(Global.AppData, "NEAV1E", "Presets", savePresetDialog.PresetName + ".json"), JsonConvert.SerializeObject(mainWindow.PresetSettings, Formatting.Indented));
102 | ComboBoxPresets.Items.Clear();
103 | LoadPresets();
104 | }
105 | }
106 |
107 | public bool presetLoadLock = false;
108 | private void ComboBoxPresets_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
109 | {
110 | if (ComboBoxPresets.SelectedItem == null) return;
111 | try
112 | {
113 | // Get MainWindow instance to access UI elements
114 | MainWindow mainWindow = Application.Current.MainWindow as MainWindow;
115 |
116 | presetLoadLock = true;
117 | mainWindow.PresetSettings = JsonConvert.DeserializeObject(File.ReadAllText(Path.Combine(Global.AppData, "NEAV1E", "Presets", ComboBoxPresets.SelectedItem.ToString() + ".json")));
118 | mainWindow.DataContext = mainWindow.PresetSettings;
119 | presetLoadLock = false;
120 |
121 | ApplyPresetAudioToCurrentVideo();
122 | }
123 | catch { }
124 | }
125 |
126 | private void ApplyPresetAudioToCurrentVideo()
127 | {
128 | try
129 | {
130 | // Get MainWindow instance to access UI elements
131 | MainWindow mainWindow = Application.Current.MainWindow as MainWindow;
132 |
133 | if (mainWindow.AudioTabControl.ListBoxAudioTracks.ItemsSource == null) return;
134 | mainWindow.videoDB.AudioTracks = (List) mainWindow.AudioTabControl.ListBoxAudioTracks.ItemsSource;
135 | try { mainWindow.AudioTabControl.ListBoxAudioTracks.Items.Clear(); } catch { }
136 | try { mainWindow.AudioTabControl.ListBoxAudioTracks.ItemsSource = null; } catch { }
137 |
138 | foreach (Audio.AudioTracks audioTrack in mainWindow.videoDB.AudioTracks)
139 | {
140 | switch (audioTrack.Channels)
141 | {
142 | case 0:
143 | audioTrack.Bitrate = mainWindow.PresetSettings.AudioBitrateMono.ToString();
144 | audioTrack.Codec = mainWindow.PresetSettings.AudioCodecMono;
145 | break;
146 | case 1:
147 | audioTrack.Bitrate = mainWindow.PresetSettings.AudioBitrateStereo.ToString();
148 | audioTrack.Codec = mainWindow.PresetSettings.AudioCodecStereo;
149 | break;
150 | case 2:
151 | audioTrack.Bitrate = mainWindow.PresetSettings.AudioBitrateSixChannel.ToString();
152 | audioTrack.Codec = mainWindow.PresetSettings.AudioCodecSixChannel;
153 | break;
154 | case 3:
155 | audioTrack.Bitrate = mainWindow.PresetSettings.AudioBitrateEightChannel.ToString();
156 | audioTrack.Codec = mainWindow.PresetSettings.AudioCodecEightChannel;
157 | break;
158 | default:
159 | break;
160 | }
161 | }
162 |
163 | mainWindow.AudioTabControl.ListBoxAudioTracks.ItemsSource = mainWindow.videoDB.AudioTracks;
164 | }
165 | catch { }
166 | }
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Views/SavePresetDialog.xaml:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | Sets the Audio Encoder. Recommended: Opus
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | Sets the audio bitrate. Recommended for Opus: 96 - 128 for Stereo
37 |
38 |
39 |
40 |
41 | Sets the Audio Encoder. Recommended: Opus
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | Sets the audio bitrate. Recommended for Opus: 96 - 128 for Stereo
52 |
53 |
54 | Sets the Audio Encoder. Recommended: Opus
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 | Sets the audio bitrate. Recommended for Opus: 96 - 128 for Stereo
65 |
66 |
67 | Sets the Audio Encoder. Recommended: Opus
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 | Sets the audio bitrate. Recommended for Opus: 96 - 128 for Stereo
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Controls/QueueTab.xaml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
23 |
24 |
25 |
26 |
31 |
36 |
41 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Controls/FiltersTab.xaml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/NotEnoughAV1Encodes/Queue/QueueElement.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.ComponentModel;
5 | using System.Diagnostics;
6 | using System.IO;
7 |
8 | namespace NotEnoughAV1Encodes.Queue
9 | {
10 | public class QueueElement : INotifyPropertyChanged
11 | {
12 | public event PropertyChangedEventHandler PropertyChanged;
13 | private double _progress;
14 | private double _progressSecondPass;
15 | private string _status;
16 |
17 | /// Current Status displayed in the Queue.
18 | public string Status
19 | {
20 | get => _status;
21 | set { _status = value; NotifyPropertyChanged("Status"); }
22 | }
23 | /// Full Video Input Path.
24 | public string Input { get; set; }
25 | /// Full Video Output Path.
26 | public string Output { get; set; }
27 | /// Video Encoding parameters.
28 | public string VideoCommand { get; set; }
29 | /// Video HDR Muxing parameters.
30 | public string VideoHDRMuxCommand { get; set; }
31 | /// Target VMAF Chunk List.
32 | public List ChunkVMAF { get; set; } = new();
33 | /// Audio Encoding parameters.
34 | public string AudioCommand { get; set; }
35 | /// Softsub Command
36 | public string SubtitleCommand { get; set; }
37 | /// Hardsub Command
38 | public string SubtitleBurnCommand { get; set; }
39 | /// Filtering parameters.
40 | public string FilterCommand { get; set; }
41 | /// Unique Identifier to avoid Filesystem conflicts.
42 | public string UniqueIdentifier { get; set; }
43 | /// Encoding Method; 0=aom ffmpeg, 1=rav1e ffmpeg, 2=svt-av1 ffmpeg ...
44 | public int EncodingMethod { get; set; }
45 | /// Amount of Encoding Passes.
46 | public int Passes { get; set; }
47 | /// If two progressbars should be displayed for two pass encoding.
48 | public bool TwoProgressbars { get => Passes > 1; }
49 | /// If Video should be handled as VFR.
50 | public bool VFR { get; set; }
51 | /// If true, then there was some Error during the process.
52 | public bool Error { get; set; }
53 | /// Amount of Errors
54 | public int ErrorCount { get; set; } = 0;
55 | /// Framecount of Source Video.
56 | public long FrameCount { get; set; }
57 | /// Date Added to Queue.
58 | public DateTime DateAdded { get; set; } = DateTime.Now;
59 | /// Amount of already encoded time.
60 | public TimeSpan TimeEncoded { get; set; } = TimeSpan.Zero;
61 | /// List of Progress of each Chunk.
62 | public List ChunkProgress { get; set; } = new();
63 | /// State of UI Settings
64 | public VideoSettings Preset { get; set; } = new();
65 | /// Video DB
66 | public Video.VideoDB VideoDB { get; set; } = new();
67 | /// Encoding Process
68 | public double Progress
69 | {
70 | get => _progress;
71 | set { _progress = value; NotifyPropertyChanged("Progress"); }
72 | }
73 | /// Encoding Process of Second Pass
74 | public double ProgressSecondPass
75 | {
76 | get => _progressSecondPass;
77 | set { _progressSecondPass = value; NotifyPropertyChanged("ProgressSecondPass"); }
78 | }
79 |
80 | private void NotifyPropertyChanged(string property)
81 | {
82 | if (PropertyChanged != null)
83 | {
84 | PropertyChanged(this, new PropertyChangedEventArgs(property));
85 | PropertyChanged(this, new PropertyChangedEventArgs("DisplayMember"));
86 | }
87 | }
88 |
89 | public void GetFrameCount()
90 | {
91 | Global.Logger("DEBUG - GetFrameCount() ", Output + ".log");
92 | // Only do manual Framecount, if MediaInfo did not detect it
93 | if (FrameCount == 0)
94 | {
95 | try
96 | {
97 | Global.Logger("INFO - GetFrameCount() => Detecting with FFmpeg", Output + ".log");
98 | // This function calculates the total number of frames
99 | Process process = new()
100 | {
101 | StartInfo = new ProcessStartInfo()
102 | {
103 | UseShellExecute = false,
104 | CreateNoWindow = true,
105 | WindowStyle = ProcessWindowStyle.Hidden,
106 | FileName = "cmd.exe",
107 | WorkingDirectory = Path.Combine(Directory.GetCurrentDirectory(), "Apps", "FFmpeg"),
108 | Arguments = "/C ffmpeg.exe -i \"" + VideoDB.InputPath + "\" -hide_banner -loglevel 32 -map 0:v:0 -f null -",
109 | RedirectStandardError = true,
110 | RedirectStandardOutput = true
111 | }
112 | };
113 | process.Start();
114 | string stream = process.StandardError.ReadToEnd();
115 | process.WaitForExit();
116 | string tempStream = stream[stream.LastIndexOf("frame=")..];
117 | string data = GetBetween(tempStream, "frame=", "fps=");
118 | FrameCount = long.Parse(data);
119 |
120 | if (Passes == 2)
121 | {
122 | FrameCount += FrameCount;
123 | }
124 | }
125 | catch(Exception ex)
126 | {
127 | Global.Logger("ERROR - Exception => GetFrameCount() : " + ex.Message, Output + ".log");
128 | }
129 | }
130 | Global.Logger("INFO - GetFrameCount() => " + FrameCount, Output + ".log");
131 | }
132 |
133 | public void GetVFRTimeStamps()
134 | {
135 | Global.Logger("TRACE - GetVFRTimeStamps()", Output + ".log");
136 | if (!VFR || File.Exists(Path.Combine(Global.Temp, "NEAV1E", UniqueIdentifier, "vsync.txt")))
137 | {
138 | Global.Logger("TRACE - GetVFRTimeStamps() => return", Output + ".log");
139 | return;
140 | }
141 |
142 | try
143 | {
144 | Global.Logger("DEBUG - GetVFRTimeStamps() => Extracting...", Output + ".log");
145 | // Run mkvextract command
146 | Process mkvExtract = new();
147 | ProcessStartInfo startInfo = new()
148 | {
149 | WindowStyle = ProcessWindowStyle.Hidden,
150 | FileName = "cmd.exe",
151 | WorkingDirectory = Path.Combine(Directory.GetCurrentDirectory(), "Apps", "MKVToolNix"),
152 | Arguments = "/C mkvextract.exe \"" + VideoDB.InputPath + "\" timestamps_v2 0:\"" + Path.Combine(Global.Temp, "NEAV1E", UniqueIdentifier, "vsync.txt") + "\""
153 | };
154 | Debug.WriteLine("VSYNC Extract: " + startInfo.Arguments);
155 | mkvExtract.StartInfo = startInfo;
156 | mkvExtract.Start();
157 | Status = "Extracting VFR Timestamps";
158 | mkvExtract.WaitForExit();
159 | if(mkvExtract.ExitCode == 0)
160 | {
161 | Global.Logger("DEBUG - GetVFRTimeStamps() => Exit Code 0", Output + ".log");
162 | }
163 | else
164 | {
165 | Global.Logger("FATAL - GetVFRTimeStamps() => Exit Code " + mkvExtract.ExitCode, Output + ".log");
166 | }
167 | }
168 | catch (Exception ex)
169 | {
170 | Global.Logger("FATAL - GetVFRTimeStamps() => Exception: " + ex.Message, Output + ".log");
171 | }
172 | }
173 |
174 | private static string GetBetween(string strSource, string strStart, string strEnd)
175 | {
176 | // This function parses data between two points
177 | if (strSource.Contains(strStart) && strSource.Contains(strEnd))
178 | {
179 | int Start, End;
180 | Start = strSource.IndexOf(strStart, 0) + strStart.Length;
181 | End = strSource.IndexOf(strEnd, Start);
182 | return strSource[Start..End];
183 | }
184 | return "0";
185 | }
186 |
187 | public static QueueElement DeepCopy(QueueElement queueElement)
188 | {
189 | // Cursed
190 | var serialized = JsonConvert.SerializeObject(queueElement);
191 | return JsonConvert.DeserializeObject(serialized);
192 | }
193 | }
194 | }
195 |
--------------------------------------------------------------------------------