301 Commits
2.7.1 ... 4.2.0

Author SHA1 Message Date
k4yt3x
676e70f088 updated drivers tooltips 2020-05-17 16:15:38 -04:00
k4yt3x
f57b5e9d04 bumped GUI version number 2020-05-17 16:15:26 -04:00
k4yt3x
f48e23a890 ignore FileNotFoundError while clearing cache 2020-05-17 15:50:05 -04:00
k4yt3x
826b4e9829 renamed stream copy checkbox 2020-05-17 15:48:21 -04:00
k4yt3x
c56be51e21 updated output path generation logic, organized lines 2020-05-17 15:48:06 -04:00
k4yt3x
d2b3175ccd changed default output codec to yuv420p for wider compatibility, added frame interpolation comment 2020-05-17 15:47:33 -04:00
k4yt3x
a98d1c7277 added stopping confirmation 2020-05-17 10:51:17 -04:00
k4yt3x
e107ddc96e updated translations 2020-05-17 10:13:43 -04:00
k4yt3x
289f5441eb added FFmpeg frame interpolation option 2020-05-17 09:57:07 -04:00
k4yt3x
179bd6afc8 updated GUI 2.1.0 screenshot 2020-05-16 08:01:11 -04:00
k4yt3x
5af49012c8 upscaler 4.1.0: removed Anime4KCPP workaround to enable support for GIF and progress bar 2020-05-16 07:12:25 -04:00
k4yt3x
192c6ef38b setup script 2.1.0: added uninstallation option, other minor enhancements 2020-05-16 07:04:44 -04:00
k4yt3x
0b67ec879d updated Jekyll site settings 2020-05-16 06:32:49 -04:00
k4yt3x
288f21f7ce updated Jekyll config 2020-05-16 06:21:30 -04:00
k4yt3x
60af2a2782 updated mirror site information 2020-05-16 05:40:44 -04:00
k4yt3x
53aa27409e fixing Jekyll theme plugin 2020-05-16 04:00:26 -04:00
k4yt3x
ab22fb2359 changing GitHub Pages theme attempt 2 2020-05-16 03:54:07 -04:00
k4yt3x
fc18307b22 changing GitHub Pages theme 2020-05-16 03:36:58 -04:00
k4yt3x
04d598a525 CLI and GUI now displays upscaler version 2020-05-15 21:28:22 -04:00
k4yt3x
748f1e5799 updated run from source code URL 2020-05-15 21:15:03 -04:00
k4yt3x
c384bb91c4 added checkbox to ensure width and height are divisible by 2 2020-05-14 22:34:27 -04:00
k4yt3x
0882f44e1f added Gifski settings, added config filter for ffmpeg 2020-05-14 20:17:10 -04:00
k4yt3x
99abb4f6df 2.1.0: added FFmpeg Settings tab 2020-05-14 19:56:06 -04:00
k4yt3x
54f8f19c7e added input_options import for every phase 2020-05-14 19:55:52 -04:00
k4yt3x
c1c96815cf adjusted FFmpeg options and added comments 2020-05-14 19:55:25 -04:00
k4yt3x
98a7fbf9cb fixed FFmpeg configuration key 2020-05-13 02:43:22 -04:00
k4yt3x
f2ba6033b7 added locale into pyinstaller packages 2020-05-13 02:42:56 -04:00
k4yt3x
f92d1a41a2 moved FFprobe general options before input and output options 2020-05-12 21:23:26 -04:00
k4yt3x
1b6c4b8c49 renamed FFmpeg phase names to match FFmpeg wrapper function names 2020-05-12 21:11:30 -04:00
k4yt3x
9b4ee89aee added FFmpeg Settings tab and Tools tab and FFprobe tool 2020-05-12 20:31:58 -04:00
k4yt3x
0953fc52a1 made image format optional 2020-05-12 20:31:39 -04:00
k4yt3x
759a3c7c96 updated FFmpeg parameters, moved debug info 2020-05-12 20:30:59 -04:00
k4yt3x
786ccaa610 upon stream migration fails, move intermediate file instead of copy 2020-05-12 19:27:37 -04:00
k4yt3x
0c3c136458 fixing issue #249 by @GitGerby 2020-05-12 19:25:39 -04:00
k4yt3x
1be2c1ead7 fixed pyinstaller 7z unpacking issues, replaced pyunpack with patoolib 2020-05-12 06:31:18 -04:00
k4yt3x
180bfcab20 added 7z files for pyinstaller 2020-05-12 06:30:49 -04:00
k4yt3x
0cc67857f7 changed setup script pyunpack to patoolib 2020-05-12 05:50:08 -04:00
k4yt3x
e07848f4bf updated GUI and CLI screenshots 2020-05-12 04:47:00 -04:00
k4yt3x
379d699c0d added patool hidden import for setup script 2020-05-12 04:39:24 -04:00
k4yt3x
e6702d4486 removed "recent change" as this info will be available in releases 2020-05-12 04:31:22 -04:00
k4yt3x
8f5edb720e updated translations 2020-05-12 04:30:04 -04:00
k4yt3x
b27e9b1fa5 added line breaks before image captions 2020-05-12 04:18:20 -04:00
k4yt3x
0b72236d95 added nightly build information, updated some other fields 2020-05-12 04:15:02 -04:00
k4yt3x
fdb813d6d6 moved build.yml to nightly.yml 2020-05-12 03:42:48 -04:00
k4yt3x
417dfc5deb changed nightly build workflow name 2020-05-12 03:42:13 -04:00
k4yt3x
12673f1c37 added pywin32 to fix build issues, renamed artifacts 2020-05-12 03:31:34 -04:00
k4yt3x
f7d8d551b3 corrected nightly build path 2020-05-12 03:23:17 -04:00
k4yt3x
9cbb213e55 added artifact collecting and uploading 2020-05-12 03:16:28 -04:00
k4yt3x
181e5c94e6 fixed path error for requirements.txt 2020-05-12 02:43:44 -04:00
k4yt3x
37547d1233 changed workflow default working directory 2020-05-12 02:40:55 -04:00
k4yt3x
8368cb1f49 replaced workflow forward slash with grave accent 2020-05-12 02:29:44 -04:00
k4yt3x
9643c96ed7 updated workflow to eliminate unix shell syntax 2020-05-12 02:26:07 -04:00
K4YT3X
1c5bf1604f Create build.yml 2020-05-12 06:18:24 +00:00
k4yt3x
23cfba86f8 updated GIF and image upscale examples 2020-05-11 22:41:06 -04:00
k4yt3x
0ef0d6e161 updated banner and social preview PSD file 2020-05-11 22:02:47 -04:00
k4yt3x
4e43ff9086 fixed Anime4KCPP attribute issue 2020-05-11 21:01:09 -04:00
k4yt3x
a93d18eb09 updated logo and banner 2020-05-11 21:00:55 -04:00
k4yt3x
e305d0188e added image and GIF upscale support 2020-05-11 20:24:18 -04:00
k4yt3x
5cf3271aad added Bad Apple!! to demo videos 2020-05-11 16:24:09 -04:00
k4yt3x
bcbead4d96 updated CLI usages 2020-05-11 06:57:16 -04:00
k4yt3x
a3d0465e44 updated GUI screenshot 2020-05-11 05:32:39 -04:00
k4yt3x
995fdec5c8 updated sample video URLs 2020-05-11 05:18:00 -04:00
k4yt3x
5c3ea51ccb updated demo video links 2020-05-11 05:13:06 -04:00
k4yt3x
a24b321088 updated translations 2020-05-11 04:41:05 -04:00
k4yt3x
a83249c670 fixed waifu2x-caffe pixel format check typo 2020-05-11 04:38:33 -04:00
k4yt3x
ab2f982a84 fixed waifu2x-caffe parsing error 2020-05-11 04:33:38 -04:00
k4yt3x
91401977da added frame preview, redesigned driver instance initiation and argument parsing 2020-05-11 04:17:21 -04:00
k4yt3x
99971bceb1 adjusted GUI dimensions 2020-05-10 00:59:16 -04:00
k4yt3x
0c6de8af16 re-added CLI usages 2020-05-09 23:31:34 -04:00
k4yt3x
4def30f516 added prerequisites in README 2020-05-09 23:22:36 -04:00
k4yt3x
8d553ac575 added a link for download builds 2020-05-09 23:14:24 -04:00
k4yt3x
e1a1cf578b moved badges below the icon 2020-05-09 23:13:12 -04:00
k4yt3x
4015617152 updated README for recent code updates 2020-05-09 23:12:37 -04:00
k4yt3x
648bf4fd3d added video2x banner files 2020-05-09 23:12:20 -04:00
k4yt3x
e3ed08ff40 updated logo files 2020-05-09 22:20:40 -04:00
k4yt3x
90f807655a better about and error dialog 2020-05-09 20:27:04 -04:00
k4yt3x
ab77d62c71 updated config file comments 2020-05-09 20:13:08 -04:00
k4yt3x
a64fabae87 added more GUI options for waifu2x-converter-cpp 2020-05-09 20:10:12 -04:00
k4yt3x
26558c6159 changed some wording in upscaler 2020-05-09 19:40:18 -04:00
k4yt3x
4fbbb20258 updated zh_CN translation files 2020-05-09 19:40:07 -04:00
k4yt3x
4659a9a9f5 changed gitignore to include translation files 2020-05-09 19:39:51 -04:00
k4yt3x
4c48af4fa4 output intermediate video-only file if stream migration fails 2020-05-09 19:30:24 -04:00
k4yt3x
4a6f90a1f0 fixing temp directory loading problem attempt 2 2020-05-09 05:49:59 -04:00
k4yt3x
2d9c5fe751 fixed custom cache path loading issues 2020-05-09 05:39:40 -04:00
k4yt3x
bef3861d3c fixed some spelling errors in waifu2x-caffe 2020-05-09 05:39:19 -04:00
k4yt3x
bcb54b6d2c yielding multithreading control to srmd/waifu2x-ncnn-vulkan, fixing FFmpeg framerate detection 2020-05-09 04:54:28 -04:00
k4yt3x
e82a26d44f deleted some unused imports 2020-05-09 02:23:21 -04:00
k4yt3x
14f7f34ee3 build script displays v2x version when building 2020-05-09 01:11:03 -04:00
k4yt3x
11ba334f16 added more comments and ffmpeg Video2X signature 2020-05-09 01:01:12 -04:00
k4yt3x
c451b14bd7 fixed waifu2x-converter-cpp path error 2020-05-09 00:54:57 -04:00
k4yt3x
80623a6bb7 fixed waifu2x-converter-cpp constraints 2020-05-09 00:47:12 -04:00
k4yt3x
a5dd87a72c updated build script to read version from args 2020-05-08 22:35:10 -04:00
k4yt3x
9b20ef89c9 fixed Anime4KCPP execution issues 2020-05-08 22:34:53 -04:00
k4yt3x
91efe2d684 updated zh_CN translation 2020-05-08 22:12:33 -04:00
k4yt3x
0d9d5c4f43 fixed progress monitor error, enhanced GUI error display 2020-05-08 22:12:24 -04:00
k4yt3x
e0e42b11c8 update qtcreator file 2020-05-08 20:29:08 -04:00
k4yt3x
790bb54598 redesigned UI progress display 2020-05-08 20:28:46 -04:00
k4yt3x
f2943802cb upgraded input QLineEdit to QTableView 2020-05-08 17:37:16 -04:00
k4yt3x
d12f2a3888 deleted blank lines 2020-05-08 17:32:36 -04:00
k4yt3x
871d6386a8 added file drag and drop to GUI 2020-05-07 21:11:33 -04:00
k4yt3x
589a68caf7 removed some obsolete items from gitignore 2020-05-07 19:59:04 -04:00
k4yt3x
afacc48e1e added qtcreator project file 2020-05-07 19:58:51 -04:00
k4yt3x
4a3553607b deleted some empty lines with indentations in the project 2020-05-07 19:55:33 -04:00
k4yt3x
988600a769 fixed checkbox return value type error 2020-05-07 19:50:40 -04:00
k4yt3x
36aa3bf1d4 GUI resolve driver paths into absolute paths 2020-05-07 16:31:05 -04:00
k4yt3x
9dde3c66f1 build script 1.0.1: building into directory with name of version 2020-05-07 16:30:36 -04:00
k4yt3x
e9c1c22788 better exception handling, soft task interruption, GUI stop button, GUI folder processing, better argument checks 2020-05-07 15:58:22 -04:00
k4yt3x
134e8b7080 uncommented some keys unmanaged by v2x 2020-05-07 10:03:42 -04:00
k4yt3x
a295b4a54f finished adding comments for all drivers 2020-05-07 09:58:25 -04:00
k4yt3x
c198082190 updated new Anime4KCPP parameters 2020-05-07 09:38:13 -04:00
k4yt3x
8f2dc43af3 updated UI for newest Anime4KCPP 2020-05-07 09:33:37 -04:00
k4yt3x
b0ce8f3ff9 added environment variable expansion support, updated for newest Anime4KCPP 2020-05-07 09:33:12 -04:00
k4yt3x
0b1f7b8422 replaced absolute paths with environment variables, updated for newest Anime4KCPP 2020-05-07 09:32:51 -04:00
k4yt3x
def20650e2 added environment variable expansion support 2020-05-07 09:32:15 -04:00
k4yt3x
7489376404 fixed srmd-ncnn-vulkan path not added issue in the setup script 2020-05-07 09:02:42 -04:00
k4yt3x
826279ce09 fixing image captions 2020-05-06 20:48:19 -04:00
k4yt3x
88d2cd9e14 updated README screenshots and added image captions 2020-05-06 20:40:35 -04:00
k4yt3x
31728ff625 added PowerShell automatic build script 2020-05-06 20:20:51 -04:00
k4yt3x
3168737fd4 added time elapsed, time remaining and speed rate 2020-05-06 20:20:38 -04:00
k4yt3x
5fbc195740 unified config path case 2020-05-06 20:19:49 -04:00
K4YT3X
40d0d79141 added a patreon badge 2020-05-06 20:03:49 +00:00
k4yt3x
37a0966bad added binary path loading and error dialog system 2020-05-06 15:36:55 -04:00
k4yt3x
baf4c5815f added pyqt5 into requirements 2020-05-06 14:30:59 -04:00
k4yt3x
d25a478e64 added automatic constraint update upon driver selection 2020-05-06 14:27:21 -04:00
K4YT3X
ba723c6216 enable sponsorships 2020-05-06 17:46:35 +00:00
k4yt3x
11ea8a7a21 added config descriptions for some drivers 2020-05-06 13:24:32 -04:00
k4yt3x
3bce37416b GUI 2.0 design and basic functionalities finished 2020-05-06 13:24:10 -04:00
k4yt3x
e3cfe13b5c fixed some bugs in GUI 2020-05-06 11:01:14 -04:00
k4yt3x
81d8ce78cb updated default values 2020-05-06 10:40:04 -04:00
k4yt3x
89fa91c8c5 updated GUI UI file for new settings 2020-05-06 10:39:47 -04:00
k4yt3x
c8dbb90f5b added waifu2x-caffe and waifu2x-converter-cpp settings to GUI 2020-05-06 10:39:34 -04:00
k4yt3x
685120011b added Waifu2x-Extension-GUI into the related projects section 2020-05-06 04:57:43 -04:00
k4yt3x
82da40327b updated Video2X GUI screenshot 2020-05-06 04:48:04 -04:00
k4yt3x
9b4fb3258a video2x GUI 2.0.0: completely redesigned and rewritten with PyQt5 2020-05-06 04:45:48 -04:00
k4yt3x
f00a10aa91 added image files and project files 2020-05-06 04:44:36 -04:00
k4yt3x
93e8f36ffb fixed a typo 2020-05-06 00:12:49 -04:00
k4yt3x
f10e59099c deprecated JSON config file 2020-05-06 00:12:31 -04:00
k4yt3x
82715ade18 addressed srmd-ncnn-vulkan and waifu2x-ncnn-vulkan model path issues 2020-05-05 02:49:10 -04:00
K4YT3X
63de63e594 added master branch version badge 2020-05-05 06:29:03 +00:00
K4YT3X
8daeb862a4 updated README terminal screenshot 2020-05-05 06:26:39 +00:00
k4yt3x
be0d1f1d08 added some badges 2020-05-05 02:22:37 -04:00
k4yt3x
ec1327b5d8 updated README for version 4.0.0 2020-05-05 01:51:24 -04:00
k4yt3x
5b3e5604cc fixed srmd-ncnn-vulkan binary path issue 2020-05-05 01:12:12 -04:00
k4yt3x
a2fc71d6c5 fixed Anime4KCPP upscaling bug 2020-05-05 01:11:50 -04:00
k4yt3x
ab684bcd48 updated default Anime4KCPP path 2020-05-05 01:11:37 -04:00
k4yt3x
d26b406813 setup script 1.8.0: added Anime4KCPP setup support 2020-05-05 01:11:26 -04:00
k4yt3x
133b837b15 added language zh_CN 2020-05-04 20:25:43 -04:00
k4yt3x
9aebc77883 removing default values for model directories for multi-platform support 2020-05-04 20:25:32 -04:00
k4yt3x
b8472f155a added internationalization support 2020-05-04 20:25:12 -04:00
k4yt3x
19e6d241d5 fixing driver argument TypeError 2020-05-04 17:19:48 -04:00
k4yt3x
89860f22cb 4.0.0 new argument parsing mechanism and project structure 2020-05-04 17:12:41 -04:00
k4yt3x
88299d404a removed anime4k support and added Anime4KCPP support; cleaned up the program 2020-05-03 19:20:23 -04:00
k4yt3x
0f1639ed62 adding Anime4KCPP support 2020-05-03 19:19:19 -04:00
k4yt3x
3b6462d1da removing support for Anime4K (Java) 2020-05-03 19:19:00 -04:00
k4yt3x
43a2078330 moving wrappers into a sub-directory 2020-05-03 19:18:39 -04:00
k4yt3x
b1e844dcad updated README for setup script 1.7.0 2020-04-26 20:12:42 -04:00
k4yt3x
becce32d3e setup script 1.7.0: added support for srmd-ncnn-vulkan 2020-04-26 20:12:06 -04:00
k4yt3x
d2ddf32527 updated README for 3.2.0 2020-04-26 20:04:37 -04:00
k4yt3x
7224c53997 3.2.0 added SRMD NCNN Vulkan support 2020-04-26 20:01:37 -04:00
k4yt3x
2ed9bd4da6 updated configuration files for SRMD NCNN Vulkan 2020-04-26 20:00:01 -04:00
k4yt3x
38c52cdfd2 updated JSON config file to match YAML 2020-04-26 19:40:21 -04:00
k4yt3x
80579d3fa9 updated absolutify paths function 2020-04-26 13:40:22 -04:00
k4yt3x
47f94dfd6c updated Anime4K ZIP file download URL 2020-04-24 00:22:39 -04:00
k4yt3x
c470dde5da fixing issue #220 2020-04-04 06:24:40 -04:00
k4yt3x
c532ac3c88 updated file modification dates and editor information 2020-03-23 09:05:24 -04:00
K4YT3X
f50ceecd62 Merge pull request #214 from 28598519a/master
Fix k4yt3x#211 bug
2020-03-23 08:55:16 -04:00
劃破黑夜
2ba0e951f9 Fix k4yt3x#211 bug 2020-03-17 22:01:56 +08:00
k4yt3x
5753ea8f52 updated readme for version 3.1.0 2020-02-26 22:31:51 -05:00
k4yt3x
09db8bedd0 3.1.0 switched to multi-processing and added KeyboardInterrupt support 2020-02-26 05:28:48 -05:00
k4yt3x
6a100b1526 removed multi-threading in favor of muti-processing 2020-02-26 05:27:57 -05:00
k4yt3x
a2150a8dbc fixing progress bar error due to string case mismatch 2020-02-22 02:31:39 -05:00
k4yt3x
78ded08ed5 changed default number of threads to 1 2020-02-21 23:16:22 -05:00
k4yt3x
5db2cfd2a3 added anime4k instructions 2020-01-12 03:32:25 -05:00
k4yt3x
652b9f34bd fixing #180 bug2 attempt 2 2020-01-04 17:03:16 -05:00
k4yt3x
f3c50ea728 fixing #180 bug2 2020-01-04 16:59:51 -05:00
k4yt3x
880087241d updated waifu2x-ncnn-vulkan path key for new config structure 2020-01-04 16:56:08 -05:00
k4yt3x
067e17290a 1.6.1 changed driver paths to 3.0.0 config style 2020-01-04 16:49:13 -05:00
k4yt3x
fc675e7899 updated copyright date 2020-01-04 16:48:37 -05:00
K4YT3X
2d81270e44 Set theme jekyll-theme-slate 2019-12-22 06:00:02 +00:00
K4YT3X
3ace2447c2 Create CNAME 2019-12-22 05:48:39 +00:00
K4YT3X
30b0e2c7bf Delete CNAME 2019-12-22 05:48:25 +00:00
k4yt3x
d54fea0310 enables available memory warning for Linux platform 2019-12-19 23:03:58 -05:00
k4yt3x
332055a4e5 fixed temp directory cleaning problem on exit 2019-12-11 22:20:01 -05:00
k4yt3x
19e17b1a8f updated platform information 2019-12-11 21:59:38 -05:00
k4yt3x
9e745fb747 video2x_gui 1.1.3: fixed driver path key name 2019-12-11 21:59:20 -05:00
K4YT3X
fd5edead7e Merge pull request #171 from YOUSIKI/master
Check platform correctly
2019-11-30 19:56:08 +00:00
YOUSIKI
aa7c0b3f12 Check platform correctly
Continue if running on win32.
Exit if running on other platforms.
2019-11-30 22:56:34 +08:00
k4yt3x
65cc4c6afb Merge branch '3.0.0' 2019-11-26 04:14:13 -05:00
k4yt3x
bd2da021bd updated README for 3.0.0 2019-11-26 04:12:04 -05:00
k4yt3x
7e888db7b2 formatted YAML file 2019-11-26 04:10:01 -05:00
k4yt3x
7726a86e35 added platform check, made PermissionError more obvious 2019-11-26 04:03:03 -05:00
K4YT3X
a0595136ab Create CNAME 2019-11-18 06:43:00 +00:00
K4YT3X
5c93a5a73b Delete CNAME 2019-11-18 06:42:54 +00:00
K4YT3X
7b9b87fa9b Create CNAME 2019-11-17 05:41:13 +00:00
k4yt3x
cb255da65c added missing sys library import 2019-11-16 02:54:25 -05:00
k4yt3x
d503325a62 changed YAML load to FullLoader to make it WIndows-compatible 2019-11-16 02:52:33 -05:00
k4yt3x
954233c238 changed default config path from JSON to YAML 2019-11-16 01:51:01 -05:00
k4yt3x
95416f68a8 make the GUI script YAML-compatible 2019-11-16 01:50:41 -05:00
k4yt3x
dce778b3bf 1.1.2 fixed repeated output file extensions 2019-11-15 22:40:48 -05:00
k4yt3x
c537dd726c changed YAML loader to Windows compatible FullLoader 2019-11-15 22:40:19 -05:00
k4yt3x
b1918a4a8a fixed pixel_formats print bug and subprocess execution bug 2019-11-15 02:39:27 -05:00
k4yt3x
7ae9618785 updated file modification date 2019-11-15 02:38:39 -05:00
k4yt3x
eb3d29103c fixed anime4k path key 2019-11-15 02:38:11 -05:00
k4yt3x
a188f6ebda 1.6.0 added support for YAML, better exception handling 2019-11-15 02:04:12 -05:00
k4yt3x
fd67dfca11 docstring modifications, added JDK warning 2019-11-15 02:03:44 -05:00
k4yt3x
b1f29f1098 fixed NCNN Vulkan driver argument error 2019-11-15 01:09:55 -05:00
k4yt3x
fe7c0c840d fixed type error for waifu2x-ncnn-vulkan argument 2019-10-24 21:33:05 -04:00
k4yt3x
dc2410d4da renaming variables, using YAML to replace JSON 2019-10-19 21:53:12 -04:00
k4yt3x
91ac512d57 remove .exe extension for Linux compatibility 2019-10-19 21:52:31 -04:00
k4yt3x
732288f075 renamed waifu2x_settings to driver_settings 2019-10-19 21:52:11 -04:00
k4yt3x
e812c228c3 updated file permissions 2019-10-19 21:51:18 -04:00
k4yt3x
9841fa9577 converted JSON config into YAML 2019-10-19 21:45:44 -04:00
k4yt3x
5391f59847 renamed bin to src since python isn't binary 2019-10-19 21:40:00 -04:00
k4yt3x
6180ccd9b2 fixing folder upscaling function 2019-08-29 16:03:15 -04:00
k4yt3x
e10315f89e using contextlib instead of try-catch 2019-08-25 23:03:37 -04:00
k4yt3x
6521e071ce enhanced logo-printing 2019-08-25 23:03:18 -04:00
k4yt3x
a685e91b14 removed unused dependencies 2019-08-25 23:02:59 -04:00
k4yt3x
9d72bad314 temporary fix for Anime4K download 2019-08-20 22:40:26 -04:00
k4yt3x
2b63b5f0a6 added total time display 2019-08-17 23:28:37 -04:00
k4yt3x
9c84228c17 added screenshot for video2x gui 2019-08-17 23:19:47 -04:00
k4yt3x
f9bb191336 fixed gui compatibility with anime4k, added constraints for a4k 2019-08-17 18:16:47 -04:00
K4YT3X
7a3af366f8 Merge pull request #137 from k4yt3x/2.10.0-anime4k
2.10.0 anime4k
2019-08-16 15:49:33 +00:00
k4yt3x
d4223f93ec fixed a4k not installed bug 2019-08-16 02:53:07 -04:00
k4yt3x
c5c764a91f GUI 1.1.1: Added support for Anime4K 2019-08-16 02:49:38 -04:00
k4yt3x
ba6472c9fc exe build is out of beta 2019-08-16 02:49:22 -04:00
k4yt3x
dc1244580f updated README for 2.10.0 2019-08-16 00:46:43 -04:00
k4yt3x
0347d05127 setup script 1.5.0: added support for Anime4K 2019-08-16 00:36:45 -04:00
k4yt3x
45f5bf91e6 updated anime4k path 2019-08-16 00:36:22 -04:00
k4yt3x
5e78beabcf added thread dialog for anime4k 2019-08-16 00:19:36 -04:00
k4yt3x
6c5b7ea17f moved constants into one single place 2019-08-15 23:57:24 -04:00
k4yt3x
d9610abae0 fixed thread-unsafe printing 2019-08-15 23:56:55 -04:00
k4yt3x
47471352ba 2.10.0 added anime4k support 2019-08-15 23:34:24 -04:00
k4yt3x
969cfe5c0d fixing issue #134 2019-08-11 23:57:10 -04:00
k4yt3x
e12db41213 updated bug report template for newest version of v2x 2019-08-07 23:07:55 -04:00
k4yt3x
7a69d58e28 placed version number into window title 2019-08-07 22:56:41 -04:00
k4yt3x
ad6308d385 relocated docstrings 2019-08-07 22:54:39 -04:00
k4yt3x
8c3a85ac42 GUI 1.1.0 added basic menu bar and better output file naming check 2019-08-07 22:54:33 -04:00
k4yt3x
db603062e9 updated main file date 2019-08-03 23:15:36 -04:00
k4yt3x
807276fcc3 fixing converter frame filename issues 2019-08-03 23:15:19 -04:00
k4yt3x
9be46f7d62 fixing support for waifu2x_ncnn_vulkan 2019-08-03 23:15:03 -04:00
k4yt3x
f42a8ab71f fixed waifu2x-ncnn-vulkan argument errors 2019-08-03 21:29:13 -04:00
k4yt3x
e3b2624977 fixed the issue where subprocess tries to execute pathlib.Path 2019-08-03 19:45:22 -04:00
k4yt3x
685d894bef Merge remote-tracking branch 'origin/master' 2019-07-30 01:28:43 -04:00
k4yt3x
b0167e9f08 Setup Script 1.4.0: fixed ncnn setup error, fixed JSON error 2019-07-30 01:28:29 -04:00
K4YT3X
74767743bd Merge pull request #130 from k4yt3x/video2x_gui
added alpha version of video2x gui
2019-07-30 05:12:08 +00:00
k4yt3x
ece345e531 added alpha version of video2x gui 2019-07-28 03:09:40 -04:00
k4yt3x
47e787c80c added more exceptions for better error handling 2019-07-27 17:52:31 -04:00
k4yt3x
4639555626 added a missing new line 2019-07-27 17:52:18 -04:00
k4yt3x
d423fa1b6e updated code contributors list 2019-07-27 17:38:52 -04:00
K4YT3X
734cf7bb0e Merge pull request #129 from k4yt3x/2.9.0
2.9.0
2019-07-27 21:34:35 +00:00
k4yt3x
77ad212b01 updated README for 2.9.0 2019-07-27 17:33:35 -04:00
k4yt3x
a27bdb4b63 changed file handling method from os to pathlib 2019-07-27 17:29:33 -04:00
k4yt3x
89dfd21f97 removed f_string support for legacy versions of Python 2019-07-27 13:39:40 -04:00
k4yt3x
5151be4122 fixing issue #94 2019-07-26 14:22:49 -04:00
K4YT3X
f8d3fa5c25 Merge pull request #122 from sat3ll/waifu2x_vk_update
update waifu2x_ncnn_vulkan wrapper
2019-07-13 05:07:47 +00:00
sat3ll
61abcc6a3a When batch upscaling (new behavior), for sub 8G VRAM gpus, the recommended value is 200. 2019-07-13 01:08:31 +01:00
sat3ll
40a4d3a602 update waifu2x_ncnn_vulkan wrapper for directory as input
add workaround for the double file extension
2019-07-12 23:12:08 +01:00
K4YT3X
9429b04528 Merge pull request #121 from sat3ll/w2x-vulkan-update
update waifu2x_ncnn_vulkan to new options
2019-07-10 02:51:15 +00:00
k4yt3x
55c2f7abfb extracting frames into rgba64be format 2019-07-09 22:48:29 -04:00
k4yt3x
c7c83d35ed updated README for 2.8.1 2019-07-09 20:48:54 -04:00
k4yt3x
ca90c5be02 2.8.1 added automatic pixel format and color depth detection 2019-07-09 20:47:55 -04:00
sat3ll
5a2b387b9d deduplicate code 2019-07-10 01:36:26 +01:00
sat3ll
eda5d70773 update waifu2x_ncnn_vulkan to new options 2019-07-10 01:30:50 +01:00
k4yt3x
8b845e35b3 matching JSON indentation 2019-06-29 13:49:34 -04:00
k4yt3x
e3b7110ff5 added vulkan reference link 2019-06-25 23:59:51 -04:00
k4yt3x
cefa2c4f30 updated README for 2.8.0 2019-06-25 23:48:41 -04:00
k4yt3x
4d9c0866ce 2.8.0 added support for waifu2x-ncnn-vulkan 2019-06-25 23:48:22 -04:00
K4YT3X
25fca78eb4 Merge pull request #112 from sat3ll/waifu2x-ncnn-vk
Add support for waifu2x-ncnn-vulkan engine
2019-06-26 03:40:34 +00:00
k4yt3x
4a0ffae6c8 updated key order for w2x ncnn 2019-06-25 23:39:53 -04:00
k4yt3x
f94f99eb1c sorted imports, updated dates 2019-06-25 23:36:03 -04:00
k4yt3x
a9586bf508 updated version to 1.3.0, using shutil.rmtree instead of os.rmdir 2019-06-25 23:35:42 -04:00
k4yt3x
5f69a44bf7 changed some wording 2019-06-25 23:35:17 -04:00
k4yt3x
1ee76c0224 removed redundant code block 2019-06-25 23:34:57 -04:00
sat3ll
0b99ac33a6 change waifu2x-ncnn-vulkan to underscores
agglomerate waifu2x choices to a list
2019-06-26 00:50:29 +01:00
sat3ll
4e3565b3ac Add support for waifu2x-ncnn-vulkan engine 2019-06-26 00:25:27 +01:00
K4YT3X
b40aee0cd7 Merge pull request #107 from BrianPetkovsek/Fix-encoding-problem
Fixed encoding problem
2019-06-18 14:28:20 +00:00
Brian Petkovsek
5b27cf26e1 Merge pull request #3 from BrianPetkovsek/master
remove uninstall not needed
2019-06-17 22:38:50 -04:00
BrianPetkovsek
8fe6fd4009 Fix encoding problem 2019-06-17 22:37:04 -04:00
BrianPetkovsek
d4d485e132 Revert "Added uninstall function to setup"
This reverts commit d25857a178.
2019-06-17 22:34:45 -04:00
BrianPetkovsek
53f5192896 Revert "Fix encoding problem"
This reverts commit 81af7b1c1b.
2019-06-17 22:33:27 -04:00
Brian Petkovsek
e6d865a80d Merge pull request #2 from BrianPetkovsek/master
Added uninstall function to setup
2019-06-17 12:06:43 -04:00
BrianPetkovsek
d25857a178 Added uninstall function to setup 2019-06-17 12:05:06 -04:00
BrianPetkovsek
81af7b1c1b Fix encoding problem 2019-06-16 17:32:41 -04:00
K4YT3X
81b8e45b6f Merge pull request #104 from BrianPetkovsek/master
make video2x backwards compatible
2019-06-15 14:44:32 -04:00
K4YT3X
e003cbc568 Merge branch 'master' into master 2019-06-15 14:42:56 -04:00
k4yt3x
f96b95563e code style adjustments 2019-06-15 14:35:22 -04:00
K4YT3X
76144b589a Merge pull request #103 from sat3ll/wip_1
use os.path.join
2019-06-15 14:26:28 -04:00
sat3ll
15d2dbb07a use os.path.join 2019-06-15 12:32:36 +01:00
BrianPetkovsek
9d5ad2f70c make video2x backwards compatible
adds future-fstrings package
transforms the source to .format() format on runtime
2019-06-14 21:43:18 -04:00
BrianPetkovsek
b5da9ebbf7 make setup backwards compatible
change the f'' to ''.format()
2019-06-14 21:37:38 -04:00
BrianPetkovsek
a1e1d98929 Make pip_install function more flexible
sys.executable gets the python.exe used to run the script
-r allows pip to use requirements.txt
2019-06-14 21:11:31 -04:00
BrianPetkovsek
fafd5fadd3 Merge remote-tracking branch 'upstream/master' 2019-06-14 20:54:04 -04:00
k4yt3x
1280a791ec fixing issue #102 2019-06-14 01:15:13 -04:00
k4yt3x
8e85d6a6d3 fixed threading bugs found by @Aidolii 2019-06-13 23:49:18 -04:00
k4yt3x
8b0f82e95e 2.7.2 fixed threading bugs found by @Aidolii 2019-06-13 23:49:10 -04:00
k4yt3x
a6666c3c3b added version option 2019-06-13 23:42:43 -04:00
BrianPetkovsek
585164a508 Merge remote-tracking branch 'upstream/master' 2019-06-12 18:06:08 -04:00
k4yt3x
6b3e1b9768 fixing video to frames ffmpeg config parsing order error 2019-06-09 21:31:13 -04:00
k4yt3x
0f4daa12d2 fixing a bug found by @CardinalPanda 2019-06-05 12:18:51 -04:00
k4yt3x
4cf83dc565 fixing progress bar bug found by @CardinalPanda 2019-05-25 23:20:31 -04:00
Brian Petkovsek
b984977227 Merge pull request #1 from K4YT3X/master
Pull latest updates
2019-03-25 02:14:50 -04:00
67 changed files with 8590 additions and 1580 deletions

12
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,12 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: k4yt3x
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

View File

@@ -11,10 +11,11 @@ assignees: K4YT3X
|Module|Version|
|-|-|
|`video2x`||
|`ffmpeg`||
|`Video2X`||
|`FFmpeg`||
|`waifu2x-caffe`||
|`waifu2x-converter-cpp`||
|`waifu2x-ncnn-vulkan`||
## Symptom

69
.github/workflows/nightly.yml vendored Normal file
View File

@@ -0,0 +1,69 @@
# Name: Video2X Nightly Build
# Creator: K4YT3X
# Date Created: May 12, 2020
# Last Modified: May 13, 2020
name: Video2X Nightly Build
on:
push:
branches: [master]
defaults:
run:
working-directory: src
jobs:
build:
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- name: Setup Python 3.8
uses: actions/setup-python@v2
with:
python-version: 3.8
- name: Install dependencies
run: |
python -m pip install -U pip
pip install -U pyinstaller pywin32
pip install -U -r requirements.txt
- name: Build Video2X CLI
run: |
pyinstaller --noconfirm --log-level=WARN `
--onefile `
--add-data="locale;locale" `
--add-data="wrappers;wrappers" `
--icon="images\video2x.ico" `
video2x.py
- name: Build Video2X GUI
run: |
pyinstaller --noconfirm --log-level=WARN `
--onefile `
--add-data="images;images" `
--add-data="locale;locale" `
--add-data="video2x_gui.ui;." `
--add-data="wrappers;wrappers" `
--icon="images\video2x.ico" `
video2x_gui.py
- name: Build Video2X setup script
run: |
pyinstaller --noconfirm --log-level=WARN `
--onefile `
--additional-hooks-dir "pyinstaller\hooks" `
--add-data="locale;locale" `
--add-data="pyinstaller\7z1900-extra;7z" `
--icon="images\video2x.ico" `
video2x_setup.py
- name: Collect artifacts into folder
run: |
New-Item "video2x-nightly-win32-light\" -ItemType Directory
Copy-Item "dist\video2x.exe" -Destination "video2x-nightly-win32-light\"
Copy-Item "dist\video2x_gui.exe" -Destination "video2x-nightly-win32-light\"
Copy-Item "dist\video2x_setup.exe" -Destination "video2x-nightly-win32-light\"
Copy-Item "video2x.yaml" -Destination "video2x-nightly-win32-light\"
- name: Upload artifacts
uses: actions/upload-artifact@v2
with:
name: video2x-nightly-win32-light
path: src/video2x-nightly-win32-light/

10
.gitignore vendored
View File

@@ -1,9 +1,3 @@
# Runtime files
upscaled/
frames/
waifu2x-caffe/
testvid.mp4
# PyCharm
.idea/
@@ -57,8 +51,8 @@ coverage.xml
.pytest_cache/
# Translations
*.mo
*.pot
#*.mo
#*.pot
# Django stuff:
*.log

1
CNAME Normal file
View File

@@ -0,0 +1 @@
video2x.org

357
README.md
View File

@@ -1,59 +1,175 @@
# Video2X Lossless Video Enlarger
<p align="center">
<img src="https://user-images.githubusercontent.com/21986859/81626588-ae5ab800-93eb-11ea-918f-ebe98c2de40a.png"/>
</p>
![Master Branch Version](https://img.shields.io/badge/master-v4.0.0-9cf?style=flat-square)
![GitHub release (latest by date)](https://img.shields.io/github/v/release/k4yt3x/video2x?style=flat-square)
![GitHub Workflow Status](https://img.shields.io/github/workflow/status/k4yt3x/video2x/Video2X%20Nightly%20Build?label=Nightly&style=flat-square)
![GitHub All Releases](https://img.shields.io/github/downloads/k4yt3x/video2x/total?style=flat-square)
![GitHub](https://img.shields.io/github/license/k4yt3x/video2x?style=flat-square)
![Platforms](https://img.shields.io/badge/Platforms-Windows%20%7C%20Linux%20%7C%20macOS-blue?style=flat-square)
<img alt="Become a Patron!" src="https://c5.patreon.com/external/logo/become_a_patron_button@2x.png" href="https://www.patreon.com/bePatron?u=34970782" height=20>
<!--# Video2X Lossless Video Enlarger-->
### Official Discussion Group (Telegram): https://t.me/video2x
## Download Builds (beta)
## [Download Stable/Beta Builds](https://github.com/k4yt3x/video2x/releases) (Windows)
You can go to the [releases page](https://github.com/k4yt3x/video2x/releases) to download the latest builds of `Video2X`. The exe files will require no Python or Python module installation.
- **`Full`**: full package comes pre-configured with **all** dependencies like `FFmpeg` and `waifu2x-caffe`.
- **`Light`**: ligt package comes with only Video2X binaries and a template configuration file. The user will either have to run the setup script or install and configure dependencies themselves.
The **`full`** package provides all packages that will possibly be needed by `Video2X`, including `FFmpeg`, `waifu2x-caffe` and `waifu2x-converter-cpp`. The config file (`video2x.json`) is also already configured for the environment. All you need to do is just to launch `video2x.exe`.
Go to the **[Quick Start](#quick-start)** section for usages.
The **`light`** package provides only the most basic functions of `Video2X`. Only `video2x.exe`, `video2x_setup.exe` and `video2x.json` are included. To setup `FFmpeg`, `waifu2x-caffe` or `waifu2x-converter-cpp` automatically, simply launch `video2x_setup.exe`.
### [Download From Mirror](https://files.k4yt3x.com/Projects/Video2X/)
## Prerequisites
In case you're unable to download the releases directly from GitHub, you can try downloading from the mirror site hosted by the author. Only releases will be updated in this directory, not nightly builds.
Component names that are **bolded** can be automatically downloaded and configured with the `video2x_setup.py` script.
## [Download Nightly Builds](https://github.com/k4yt3x/video2x/actions) (Windows)
1. Operating System: Windows
2. AMD GPU / Nvidia GPU
3. AMD GPU driver / Nvidia GPU driver / Nvidia CUDNN
4. [**FFmpeg**](https://ffmpeg.zeranoe.com/builds/)
5. [**waifu2x-caffe**](https://github.com/lltcggie/waifu2x-caffe/releases) / [**waifu2x-converter-cpp**](https://github.com/DeadSix27/waifu2x-converter-cpp/releases)
Nightly builds are built automatically every time a new commit is pushed to the master branch. The lates nightly build is always up-to-date with the latest version of the code, but is less stable and may contain bugs. Nightly builds are handled by GitHub's integrated CI/CD tool, GitHub Actions.
## Recent Changes
To download the latest nightly build, go to the [GitHub Actions](https://github.com/k4yt3x/video2x/actions) tab, enter the last run of workflow "Video2X Nightly Build, and download the artifacts generated from the run.
### 2.7.1 (April 18, 2019)
## Introduction
- Fixed video2x custom temp folder bug found by @cr08 .
Video2X is a video/GIF/image upscaling software based on Waifu2X, Anime4K and SRMD written in Python 3. It upscales videos, GIFs and images, restoring details from low-resolution inputs. Video2X also accepts GIF input to video output and video input to GIF output.
### 2.7.0 (March 30, 2019)
### Video Upscaling
- Added support for different extracted image formats.
- Redesigned FFmpeg wrapper, FFmpeg settings are now customizable in the `video2x.json` config file.
- Other minor enhancements and adjustments (e.g. argument -> method variable)
![Spirited Away Demo](https://user-images.githubusercontent.com/21986859/49412428-65083280-f73a-11e8-8237-bb34158a545e.png)\
*Upscale Comparison Demonstration*
### Setup Script 1.2.0 (March 26, 2019)
- `video2x_setup.py` script can now automatically download and configure `waifu2x-converter-cpp`.
- replaced old progress indicator with progress bar.
## Description
Video2X is an automation software based on waifu2x image enlarging engine. It extracts frames from a video, enlarge it by a number of times without losing any details or quality, keeping lines smooth and edges sharp.
For short: **Video2X enlarges your video without losing details**
Watch for the sharper edges in this screenshot around the shadows:
![preview](https://user-images.githubusercontent.com/21986859/49412428-65083280-f73a-11e8-8237-bb34158a545e.png)
**You can also watch the YouTube video Demo: https://www.youtube.com/watch?v=PG94iPoeoZk**
**You can watch the whole demo video on YouTube: https://youtu.be/mGEfasQl2Zo**
Clip is from trailer of animated movie "千と千尋の神隠し". Copyright belongs to "株式会社スタジオジブリ (STUDIO GHIBLI INC.)". Will delete immediately if use of clip is in violation of copyright.
## Screenshot
### GIF Upscaling
![screenshot](https://user-images.githubusercontent.com/21986859/40265170-39c0caae-5b01-11e8-8371-8b6c24769639.png)
This original input GIF is 160x120 in size. This image is downsized and accelerated to 20 FPS from its [original image](https://gfycat.com/craftyeasygoingankole-capoo-bug-cat).
![catfru](https://user-images.githubusercontent.com/21986859/81631069-96d4fc80-93f6-11ea-92fb-33d6545055e7.gif)\
*Catfru original 160x120 GIF image*
Below is what it looks like after getting upscaled to 640x480 (4x) using Video2X.
![catfru4x](https://user-images.githubusercontent.com/21986859/81631070-976d9300-93f6-11ea-9137-072a3b386110.gif)\
*Catfru 4x upscaled GIF*
### Image Upscaling
![jill_comparison](https://user-images.githubusercontent.com/21986859/81631903-79a12d80-93f8-11ea-9c3c-f340240cf08c.png)\
*Image upscaling example*
[Original image](https://72915.tumblr.com/post/173793265673) from [nananicu@twitter](https://twitter.com/nananicu/status/994546266968281088), edited by K4YT3X.
## All Demo Videos
Below is a list of all the demo videos available.
The list is sorted from new to old.
- **Bad Apple!!**
- YouTube: https://youtu.be/-RKLdCELgkQ
- Bilibili: https://www.bilibili.com/video/BV1s5411s7xV/
- **The Pet Girl of Sakurasou 240P to 1080P 60FPS**
- Original name: さくら荘のペットな彼女
- YouTube: https://youtu.be/M0vDI1HH2_Y
- Bilibili: https://www.bilibili.com/video/BV14k4y167KP/
- **Spirited Away (360P to 4K)**
- Original name: 千と千尋の神隠し
- YouTube: https://youtu.be/mGEfasQl2Zo
- Bilibili: https://www.bilibili.com/video/BV1V5411471i/
---
## Screenshots
### Video2X GUI
![GUI Preview](https://user-images.githubusercontent.com/21986859/82119295-bc526500-976c-11ea-9ea8-53264689023e.png)\
*Video2X GUI Screenshot*
### Video2X CLI
![Video2X CLI Screenshot](https://user-images.githubusercontent.com/21986859/81662415-0c5bbf80-942d-11ea-8aa6-aacf813f9368.png)\
*Video2X CLI Screenshot*
---
### Sample Videos
If you can't find a video clip to begin with, or if you want to see a before-after comparison, we have prepared some sample clips for you. The quick start guide down below will also be based on the name of the sample clips.
![sample_video](https://user-images.githubusercontent.com/21986859/52905766-d5512b00-3236-11e9-9aea-077636539679.png)\
*Sample Upscale Videos*
- [Sample Video (240P) 4.54MB](https://files.k4yt3x.com/Resources/Videos/sample_input.mp4)
- [Sample Video Upscaled (1080P) 4.54MB](https://files.k4yt3x.com/Resources/Videos/sample_output.mp4)
- [Sample Video Original (1080P) 22.2MB](https://files.k4yt3x.com/Resources/Videos/sample_original.mp4)
Clip is from anime "さくら荘のペットな彼女". Copyright belongs to "株式会社アニプレックス (Aniplex Inc.)". Will delete immediately if use of clip is in violation of copyright.
---
## Quick Start
### Prerequisites
Before running Video2X, you'll need to ensure you have installed the drivers' external dependencies such as GPU drivers.
- waifu2x-caffe
- GPU mode: Nvidia graphics card driver
- cuDNN mode: Nvidia CUDA and [cuDNN](https://docs.nvidia.com/deeplearning/sdk/cudnn-install/index.html#install-windows)
- Other Drivers
- GPU driver if you want to use GPU for processing
### Running Video2X (GUI)
The easiest way to run Video2X is to use the full build. Extract the full release zip file and you'll get these files.
![Video2X Release Files](https://user-images.githubusercontent.com/21986859/81489846-28633380-926a-11ea-9e81-fb92f492e14c.png)\
*Video2X release files*
Simply double click on video2x_gui.exe to launch the GUI.
![Video2X GUI Main Tab](https://user-images.githubusercontent.com/21986859/81489858-4c267980-926a-11ea-9ab2-38ec738f2fb6.png)\
*Video2X GUI main tab*
Then, drag the videos you wish to upscale into the window and select the appropriate output path.
![drag-drop](https://user-images.githubusercontent.com/21986859/81489880-7bd58180-926a-11ea-85ae-b72d2f4f5e72.png)\
*Drag and drop file into Video2X GUI*
Tweak the settings if you want to, then hit the start button at the bottom and the upscale will start. Now you'll just have to wait for it to complete.
![upscale-started](https://user-images.githubusercontent.com/21986859/81489924-ce16a280-926a-11ea-831c-6c66b950f957.png)\
*Video2X started processing input files*
### Running Video2X (CLI)
#### Basic Upscale Example
This example command below uses `waifu2x-caffe` to enlarge the video `sample-input.mp4` two double its original size.
```shell
python video2x.py -i sample-input.mp4 -o sample-output.mp4 -r 2 -d waifu2x_caffe
```
#### Advanced Upscale Example
If you would like to tweak engine-specific settings, either specify the corresponding argument after `--`, or edit the corresponding field in the configuration file `video2x.yaml`. **Command line arguments will overwrite default values in the config file.**
This example below adds enables TTA for `waifu2x-caffe`.
```shell
python video2x.py -i sample-input.mp4 -o sample-output.mp4 -r 2 -d waifu2x_caffe -- --tta 1
```
To see a help page for driver-specific settings, use `-d` to select the driver and append `-- --help` as demonstrated below. This will print all driver-specific settings and descriptions.
```shell
python video2x.py -d waifu2x_caffe -- --help
```
---
@@ -65,148 +181,66 @@ You can find all detailed user-facing and developer-facing documentations in the
### [Step-By-Step Tutorial](https://github.com/k4yt3x/video2x/wiki/Step-By-Step-Tutorial)
For those who want a detailed walk-through of how to use `Video2X`, you can head to the [Step-By-Step Tutorial](https://github.com/k4yt3x/video2x/wiki/Step-By-Step-Tutorial) wiki page. It includes almost every step you need to perform in order to enlarge your first video.
For those who want a detailed walk-through of how to use Video2X, you can head to the [Step-By-Step Tutorial](https://github.com/k4yt3x/video2x/wiki/Step-By-Step-Tutorial) wiki page. It includes almost every step you need to perform in order to enlarge your first video.
### [Waifu2X Drivers](https://github.com/k4yt3x/video2x/wiki/Waifu2X-Drivers)
### [Run From Source Code](https://github.com/k4yt3x/video2x/wiki/Run-From-Source-Code)
Go to the [Waifu2X Drivers](https://github.com/k4yt3x/video2x/wiki/Waifu2X-Drivers) wiki page if you want to see a detailed description on the different types of `waifu2x` drivers implemented by `Video2X`. This wiki page contains detailed difference between different drivers, and how to download and set each of them up for `Video2X`.
This wiki page contains all instructions for how you can run Video2X directly from Python source code.
### [Drivers](https://github.com/k4yt3x/video2x/wiki/Drivers)
Go to the [Drivers](https://github.com/k4yt3x/video2x/wiki/Drivers) wiki page if you want to see a detailed description on the different types of drivers implemented by Video2X. This wiki page contains detailed difference between different drivers, and how to download and set each of them up for Video2X.
### [Q&A](https://github.com/k4yt3x/video2x/wiki/Q&A)
If you have any questions, first try visiting our [Q&A](https://github.com/k4yt3x/video2x/wiki/Q&A) page to see if your question is answered there. If not, open an issue and we will respond to your questions ASAP.
If you have any questions, first try visiting our [Q&A](https://github.com/k4yt3x/video2x/wiki/Q&A) page to see if your question is answered there. If not, open an issue and we will respond to your questions ASAP. Alternatively, you can also join our [Telegram discussion group](https://t.me/video2x) and ask your questions there.
---
### [History](https://github.com/k4yt3x/video2x/wiki/History)
## Quick Start
### Prerequisites
- **Python 3**
Download: https://www.python.org/downloads/windows/
- **FFmpeg Windows Build**
Download: https://ffmpeg.org/download.html
- **waifu2x-caffe** (for Nvidia CUDA/CUDNN)
Download: https://github.com/lltcggie/waifu2x-caffe/releases
- **waifu2x-converter-cpp** (required for AMD, OpenCL and OpenGL processing)
Download: https://github.com/DeadSix27/waifu2x-converter-cpp/releases
### Installing Dependencies
First, clone the video2x repository.
```shell
git clone https://github.com/k4yt3x/video2x.git
cd video2x/bin
```
Then you may run the `video2x_setup.py` script to install and configure the dependencies automatically. This script is designed and tested on Windows 10.
This script will install the newest version of `ffmpeg`, either or both of `waifu2x-caffe` and `waifu2x-converter-cpp` to `%LOCALAPPDATA%\\video2x` and all required python libraries.
```shell
python video2x_setup.py
```
Alternatively, you can also install the dependencies manually. Please refer to the prerequisites section to see what's needed.
Then you'll need to install python dependencies before start using video2x. Install simply by executing the following command.
```shell
pip install -r requirements.txt
```
**Note that all command line arguments/options overwrite configuration file settings.**
### Sample Videos
If you can't find a video clip to begin with, or if you want to see a before-after comparison, we have prepared some sample clips for you. The quick start guide down below will also be based on the name of the sample clips.
![sample_video](https://user-images.githubusercontent.com/21986859/52905766-d5512b00-3236-11e9-9aea-077636539679.png)
- [Sample Video Original (240P) 1.7MB](https://files.flexio.org/Resources/Videos/sample_input.mp4)
- [Sample Video Upscaled (1080P) 4.8MB](https://files.flexio.org/Resources/Videos/sample_output.mp4)
Clip is from anime "さくら荘のペットな彼女". Copyright belongs to "株式会社アニプレックス (Aniplex Inc.)". Will delete immediately if use of clip is in violation of copyright.
### Nvidia CUDA (waifu2x-caffe)
Enlarge the video to 1920x1080 using CUDA. You may also use the `-r/--ratio` option.
```shell
python video2x.py -i sample_input.mp4 -o sample_output.mp4 -m gpu --width=1920 --height=1080
```
### Nvidia CNDNN
Enlarge the video to 1920x1080 using CUDNN. You may also use the `-r/--ratio` option.
```shell
python video2x.py -i sample_input.mp4 -o sample_output.mp4 -m cudnn --width=1920 --height=1080
```
### AMD or Nvidia (waifu2x-converter-cpp OpenCL)
Enlarge the video by 2 times using OpenCL. Note that `waifu2x-converter-cpp` doesn't support width and height. You'll also have to explicitly specify that the driver to be used is `waifu2x_converter`.
```shell
python video2x.py -i sample_input.mp4 -o sample_output.mp4 -m gpu -r 2 -d waifu2x_converter
```
### CPU
Enlarge the video to 1920x1080 using the CPU. You may also use the `-r/--ratio` option. This is potentially much slower than using a GPU. The configuration file for this method is similar to the previous methods.
```shell
python video2x.py -i sample_input.mp4 -o sample_output.mp4 -m cpu --width=1920 --height=1080
```
Are you interested in how the idea of Video2X was born? Do you want to know the stories and histories behind Video2X's development? Come into this page.
---
# Full Usage
## General Options
## Video2X Options
### -h, --help
show this help message and exit
## File Options
### -i INPUT, --input INPUT
Source video file/directory (default: None)
source video file/directory
### -o OUTPUT, --output OUTPUT
Output video file/directory (default: None)
output video file/directory
### -c CONFIG, --config CONFIG
video2x config file path
### -v, --version
display version, lawful information and exit
## Upscaling Options
### -m {cpu,gpu,cudnn}, --method {cpu,gpu,cudnn}
Upscaling method (default: gpu)
### -d DRIVER, --driver DRIVER
upscaling driver (default: waifu2x_caffe)
### -d {waifu2x_caffe,waifu2x_converter}, --driver {waifu2x_caffe,waifu2x_converter}
Waifu2x driver (default: waifu2x_caffe)
Available options are:
### -y MODEL_DIR, --model_dir MODEL_DIR
Folder containing model JSON files
### -t THREADS, --threads THREADS
Number of threads to use for upscaling (default: 5)
### -c CONFIG, --config CONFIG
Video2X config file location (default: video2x\bin\video2x.json)
### -b, --batch
Enable batch mode (select all default values to questions)
## Scaling Options
### --width WIDTH
Output video width
### --height HEIGHT
Output video height
- waifu2x_caffe
- waifu2x_converter_cpp
- waifu2x_ncnn_vulkan
- srmd_ncnn_vulkan
- anime4kcpp
### -r RATIO, --ratio RATIO
Scaling ratio
scaling ratio
### -p PROCESSES, --processes PROCESSES
number of processes to use for upscaling (default: 1)
### --preserve_frames
preserve extracted and upscaled frames (default: False)
---
@@ -217,22 +251,29 @@ https://www.gnu.org/licenses/gpl-3.0.txt
![GPLv3 Icon](https://www.gnu.org/graphics/gplv3-127x51.png)
(C) 2018-2019 K4YT3X
(C) 2018-2020 K4YT3X
## Credits
This project relies on the following software and projects.
- [FFmpeg]('https://www.ffmpeg.org/')
- [FFmpeg](https://www.ffmpeg.org/)
- [waifu2x-caffe](https://github.com/lltcggie/waifu2x-caffe)
- [waifu2x-converter-cpp](https://github.com/DeadSix27/waifu2x-converter-cpp)
- [waifu2x-ncnn-vulkan](https://github.com/nihui/waifu2x-ncnn-vulkan)
- [srmd-ncnn-vulkan](https://github.com/nihui/srmd-ncnn-vulkan)
- [Anime4K](https://github.com/bloc97/Anime4K)
- [Anime4KCPP](https://github.com/TianZerL/Anime4KCPP)
- [Gifski](https://github.com/ImageOptim/gifski)
## Special Thanks
Appreciations given to the following contributors:
Appreciations given to the following code contributors:
- @BrianPetkovsek
- @SAT3LL
## Related Resources
## Related Projects
- [Dandere2x](https://github.com/CardinalPanda/dandere2x): `Dandere2x` is a lossy video upscaler also built around `waifu2x`, but with video compression techniques to shorten the time needed to process a video.
- [Dandere2x](https://github.com/CardinalPanda/dandere2x): A lossy video upscaler also built around `waifu2x`, but with video compression techniques to shorten the time needed to process a video.
- [Waifu2x-Extension-GUI](https://github.com/AaronFeng753/Waifu2x-Extension-GUI): A similar project that focuses more and only on building a better graphical user interface. It is built using C++ and Qt5, and currently only supports the Windows platform.

20
_config.yml Normal file
View File

@@ -0,0 +1,20 @@
# site settings
locale: "en-US"
title: "Video2X"
title_separator: "-"
subtitle: "Machine learning video/GIF/image upscaling"
name: "K4YT3X"
description: "An amazing website."
url: "https://video2x.org"
repository: "k4yt3x/video2x"
# set rendering style to be GitHub flavor
kramdown:
input: GFM
# use Minimal Mistakes theme
remote_theme: mmistakes/minimal-mistakes
# plugin required for the Minimal Mistakes theme
plugins:
- jekyll-include-cache

View File

@@ -1,13 +0,0 @@
#!/usr/bin/env python3
# -*- code:utf-8 -*-
"""
Name: Video2X Exceptions
Dev: K4YT3X
Date Created: December 13, 2018
Last Modified: March 19, 2019
"""
class ArgumentError(Exception):
def __init__(self, message):
super().__init__(message)

View File

@@ -1,212 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Name: FFMPEG Class
Author: K4YT3X
Date Created: Feb 24, 2018
Last Modified: May 4, 2019
Description: This class handles all FFMPEG related
operations.
"""
from avalon_framework import Avalon
import json
import subprocess
class Ffmpeg:
"""This class communicates with ffmpeg
This class deals with ffmpeg. It handles extracitng
frames, stripping audio, converting images into videos
and inserting audio tracks to videos.
"""
def __init__(self, ffmpeg_settings, image_format):
self.ffmpeg_settings = ffmpeg_settings
self.ffmpeg_path = self.ffmpeg_settings['ffmpeg_path']
# add a forward slash to directory if not present
# otherwise there will be a format error
if self.ffmpeg_path[-1] != '/' and self.ffmpeg_path[-1] != '\\':
self.ffmpeg_path = f'{self.ffmpeg_path}\\'
self.ffmpeg_binary = f'{self.ffmpeg_path}ffmpeg.exe'
self.ffmpeg_probe_binary = f'{self.ffmpeg_path}ffprobe.exe'
self.image_format = image_format
def get_video_info(self, input_video):
""" Gets input video information
This method reads input video information
using ffprobe in dictionary.
Arguments:
input_video {string} -- input video file path
Returns:
dictionary -- JSON text of input video information
"""
# this execution command needs to be hard-coded
# since video2x only strictly recignizes this one format
execute = [
self.ffmpeg_probe_binary,
'-v',
'quiet',
'-print_format',
'json',
'-show_format',
'-show_streams',
'-i',
input_video
]
Avalon.debug_info(f'Executing: {" ".join(execute)}')
json_str = subprocess.run(execute, check=True, stdout=subprocess.PIPE).stdout
return json.loads(json_str.decode('utf-8'))
def extract_frames(self, input_video, extracted_frames):
"""Extract every frame from original videos
This method extracts every frame from videoin
using ffmpeg
Arguments:
input_video {string} -- input video path
extracted_frames {string} -- video output directory
"""
execute = [
self.ffmpeg_binary
]
execute.extend(self._read_configuration(phase='video_to_frames'))
execute.extend([
'-i',
input_video,
f'{extracted_frames}\\extracted_%0d.{self.image_format}'
])
self._execute(execute)
def convert_video(self, framerate, resolution, upscaled_frames):
"""Converts images into videos
This method converts a set of images into a
video.
Arguments:
framerate {float} -- target video framerate
resolution {string} -- target video resolution
upscaled_frames {string} -- source images directory
"""
execute = [
self.ffmpeg_binary,
'-r',
str(framerate),
'-s',
resolution
]
# read FFmpeg input options
execute.extend(self._read_configuration(phase='frames_to_video', section='input_options'))
# append input frames path into command
execute.extend([
'-i',
f'{upscaled_frames}\\extracted_%d.{self.image_format}'
])
# read FFmpeg output options
execute.extend(self._read_configuration(phase='frames_to_video', section='output_options'))
# read other options
execute.extend(self._read_configuration(phase='frames_to_video'))
# specify output file location
execute.extend([
f'{upscaled_frames}\\no_audio.mp4'
])
self._execute(execute)
def migrate_audio_tracks_subtitles(self, input_video, output_video, upscaled_frames):
""" Migrates audio tracks and subtitles from input video to output video
Arguments:
input_video {string} -- input video file path
output_video {string} -- output video file path
upscaled_frames {string} -- directory containing upscaled frames
"""
execute = [
self.ffmpeg_binary,
'-i',
f'{upscaled_frames}\\no_audio.mp4',
'-i',
input_video
]
execute.extend(self._read_configuration(phase='frames_to_video', section='output_options'))
execute.extend([
output_video
])
execute.extend(self._read_configuration(phase='migrating_tracks'))
self._execute(execute)
def _read_configuration(self, phase, section=None):
""" read configuration from JSON
Read the configurations (arguments) from the JSON
configuration file and append them to the end of the
FFmpeg command.
Arguments:
execute {list} -- list of arguments to be executed
phase {str} -- phase of operation
"""
configuration = []
# if section is specified, read configurations or keys
# from only that section
if section:
source = self.ffmpeg_settings[phase][section].keys()
else:
source = self.ffmpeg_settings[phase].keys()
for key in source:
if section:
value = self.ffmpeg_settings[phase][section][key]
else:
value = self.ffmpeg_settings[phase][key]
# null or None means that leave this option out (keep default)
if value is None or value is False or isinstance(value, list) or isinstance(value, dict):
continue
else:
configuration.append(key)
# true means key is an option
if value is True:
continue
configuration.append(str(value))
return configuration
def _execute(self, execute):
""" execute command
Arguments:
execute {list} -- list of arguments to be executed
Returns:
int -- execution return code
"""
Avalon.debug_info(f'Executing: {execute}')
return subprocess.run(execute, shell=True, check=True).returncode

View File

@@ -1,6 +0,0 @@
avalon_framework
colorama
GPUtil
psutil
requests
tqdm

View File

@@ -1,307 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Name: Video2X Upscaler
Author: K4YT3X
Date Created: December 10, 2018
Last Modified: April 28, 2019
Licensed under the GNU General Public License Version 3 (GNU GPL v3),
available at: https://www.gnu.org/licenses/gpl-3.0.txt
(C) 2018-2019 K4YT3X
"""
from avalon_framework import Avalon
from exceptions import *
from ffmpeg import Ffmpeg
from fractions import Fraction
from image_cleaner import ImageCleaner
from tqdm import tqdm
from waifu2x_caffe import Waifu2xCaffe
from waifu2x_converter import Waifu2xConverter
import os
import re
import shutil
import tempfile
import threading
import time
class Upscaler:
""" An instance of this class is a upscaler that will
upscale all images in the given directory.
Raises:
Exception -- all exceptions
ArgumentError -- if argument is not valid
"""
def __init__(self, input_video, output_video, method, waifu2x_settings, ffmpeg_settings):
# mandatory arguments
self.input_video = input_video
self.output_video = output_video
self.method = method
self.waifu2x_settings = waifu2x_settings
self.ffmpeg_settings = ffmpeg_settings
# optional arguments
self.waifu2x_driver = 'waifu2x_caffe'
self.scale_width = None
self.scale_height = None
self.scale_ratio = None
self.model_dir = None
self.threads = 5
self.video2x_cache_directory = f'{tempfile.gettempdir()}\\video2x'
self.image_format = 'png'
self.preserve_frames = False
def create_temp_directories(self):
"""create temporary directory
"""
self.extracted_frames = tempfile.mkdtemp(dir=self.video2x_cache_directory)
Avalon.debug_info(f'Extracted frames are being saved to: {self.extracted_frames}')
self.upscaled_frames = tempfile.mkdtemp(dir=self.video2x_cache_directory)
Avalon.debug_info(f'Upscaled frames are being saved to: {self.upscaled_frames}')
def cleanup_temp_directories(self):
"""delete temp directories when done
"""
if not self.preserve_frames:
for directory in [self.extracted_frames, self.upscaled_frames]:
try:
# avalon framework cannot be used if python is shutting down
# therefore, plain print is used
print(f'Cleaning up cache directory: {directory}')
shutil.rmtree(directory)
except (OSError, FileNotFoundError):
pass
def _check_arguments(self):
# check if arguments are valid / all necessary argument
# values are specified
if not self.input_video:
raise ArgumentError('You need to specify the video to process')
elif (not self.scale_width or not self.scale_height) and not self.scale_ratio:
raise ArgumentError('You must specify output video width and height or upscale factor')
elif not self.output_video:
raise ArgumentError('You need to specify the output video name')
elif not self.method:
raise ArgumentError('You need to specify the enlarging processing unit')
def _progress_bar(self, extracted_frames_directories):
""" This method prints a progress bar
This method prints a progress bar by keeping track
of the amount of frames in the input directory
and the output directory. This is originally
suggested by @ArmandBernard.
"""
# get number of extracted frames
total_frames = 0
for directory in extracted_frames_directories:
total_frames += len([f for f in os.listdir(directory) if f[-4:] == '.png'])
with tqdm(total=total_frames, ascii=True, desc='Upscaling Progress') as progress_bar:
# tqdm update method adds the value to the progress
# bar instead of setting the value. Therefore, a delta
# needs to be calculated.
previous_cycle_frames = 0
while not self.progress_bar_exit_signal:
try:
total_frames_upscaled = len([f for f in os.listdir(self.upscaled_frames) if f[-4:] == '.png'])
delta = total_frames_upscaled - previous_cycle_frames
previous_cycle_frames = total_frames_upscaled
# if upscaling is finished
if total_frames_upscaled >= total_frames:
return
# adds the detla into the progress bar
progress_bar.update(delta)
except FileNotFoundError:
pass
time.sleep(1)
def _upscale_frames(self, w2):
""" Upscale video frames with waifu2x-caffe
This function upscales all the frames extracted
by ffmpeg using the waifu2x-caffe binary.
Arguments:
w2 {Waifu2x Object} -- initialized waifu2x object
"""
# progress bar thread exit signal
self.progress_bar_exit_signal = False
# create a container for exceptions in threads
# if this thread is not empty, then an exception has occured
self.upscaler_exceptions = []
# it's easier to do multi-threading with waifu2x_converter
# the number of threads can be passed directly to waifu2x_converter
if self.waifu2x_driver == 'waifu2x_converter':
progress_bar = threading.Thread(target=self._progress_bar, args=([self.extracted_frames],))
progress_bar.start()
w2.upscale(self.extracted_frames, self.upscaled_frames, self.scale_ratio, self.threads, self.image_format, self.upscaler_exceptions)
for image in [f for f in os.listdir(self.upscaled_frames) if os.path.isfile(os.path.join(self.upscaled_frames, f))]:
renamed = re.sub(f'_\[.*-.*\]\[x(\d+(\.\d+)?)\]\.{self.image_format}', f'.{self.image_format}', image)
shutil.move(f'{self.upscaled_frames}\\{image}', f'{self.upscaled_frames}\\{renamed}')
self.progress_bar_exit_signal = True
progress_bar.join()
return
# create a container for all upscaler threads
upscaler_threads = []
# list all images in the extracted frames
frames = [os.path.join(self.extracted_frames, f) for f in os.listdir(self.extracted_frames) if os.path.isfile(os.path.join(self.extracted_frames, f))]
# if we have less images than threads,
# create only the threads necessary
if len(frames) < self.threads:
self.threads = len(frames)
# create a directory for each thread and append directory
# name into a list
thread_pool = []
thread_directories = []
for thread_id in range(self.threads):
thread_directory = f'{self.extracted_frames}\\{str(thread_id)}'
thread_directories.append(thread_directory)
# delete old directories and create new directories
if os.path.isdir(thread_directory):
shutil.rmtree(thread_directory)
os.mkdir(thread_directory)
# append directory path into list
thread_pool.append((thread_directory, thread_id))
# evenly distribute images into each directory
# until there is none left in the directory
for image in frames:
# move image
shutil.move(image, thread_pool[0][0])
# rotate list
thread_pool = thread_pool[-1:] + thread_pool[:-1]
# create threads and start them
for thread_info in thread_pool:
# create thread
if self.scale_ratio:
thread = threading.Thread(target=w2.upscale, args=(thread_info[0], self.upscaled_frames, self.scale_ratio, False, False, self.image_format, self.upscaler_exceptions))
else:
thread = threading.Thread(target=w2.upscale, args=(thread_info[0], self.upscaled_frames, False, self.scale_width, self.scale_height, self.image_format, self.upscaler_exceptions))
thread.name = thread_info[1]
# add threads into the pool
upscaler_threads.append(thread)
# start progress bar in a different thread
progress_bar = threading.Thread(target=self._progress_bar, args=(thread_directories,))
progress_bar.start()
# create the clearer and start it
Avalon.debug_info('Starting upscaled image cleaner')
image_cleaner = ImageCleaner(self.extracted_frames, self.upscaled_frames, len(upscaler_threads))
image_cleaner.start()
# start all threads
for thread in upscaler_threads:
thread.start()
# wait for threads to finish
for thread in upscaler_threads:
thread.join()
# upscaling done, kill the clearer
Avalon.debug_info('Killing upscaled image cleaner')
image_cleaner.stop()
self.progress_bar_exit_signal = True
if len(self.upscaler_exceptions) != 0:
raise(self.upscaler_exceptions[0])
def run(self):
"""Main controller for Video2X
This function controls the flow of video conversion
and handles all necessary functions.
"""
# parse arguments for waifu2x
# check argument sanity
self._check_arguments()
# convert paths to absolute paths
self.input_video = os.path.abspath(self.input_video)
self.output_video = os.path.abspath(self.output_video)
# initialize objects for ffmpeg and waifu2x-caffe
fm = Ffmpeg(self.ffmpeg_settings, self.image_format)
# initialize waifu2x driver
if self.waifu2x_driver == 'waifu2x_caffe':
w2 = Waifu2xCaffe(self.waifu2x_settings, self.method, self.model_dir)
elif self.waifu2x_driver == 'waifu2x_converter':
w2 = Waifu2xConverter(self.waifu2x_settings, self.model_dir)
else:
raise Exception(f'Unrecognized waifu2x driver: {self.waifu2x_driver}')
# extract frames from video
fm.extract_frames(self.input_video, self.extracted_frames)
Avalon.info('Reading video information')
video_info = fm.get_video_info(self.input_video)
# analyze original video with ffprobe and retrieve framerate
# width, height = info['streams'][0]['width'], info['streams'][0]['height']
# find index of video stream
video_stream_index = None
for stream in video_info['streams']:
if stream['codec_type'] == 'video':
video_stream_index = stream['index']
break
# exit if no video stream found
if video_stream_index is None:
Avalon.error('Aborting: No video stream found')
exit(1)
# get average frame rate of video stream
framerate = float(Fraction(video_info['streams'][video_stream_index]['avg_frame_rate']))
Avalon.info(f'Framerate: {framerate}')
# width/height will be coded width/height x upscale factor
if self.scale_ratio:
original_width = video_info['streams'][video_stream_index]['width']
original_height = video_info['streams'][video_stream_index]['height']
self.scale_width = int(self.scale_ratio * original_width)
self.scale_height = int(self.scale_ratio * original_height)
# upscale images one by one using waifu2x
Avalon.info('Starting to upscale extracted images')
self._upscale_frames(w2)
Avalon.info('Upscaling completed')
# frames to Video
Avalon.info('Converting extracted frames into video')
# use user defined output size
fm.convert_video(framerate, f'{self.scale_width}x{self.scale_height}', self.upscaled_frames)
Avalon.info('Conversion completed')
# migrate audio tracks and subtitles
Avalon.info('Migrating audio tracks and subtitles to upscaled video')
fm.migrate_audio_tracks_subtitles(self.input_video, self.output_video, self.upscaled_frames)

View File

@@ -1,79 +0,0 @@
{
"waifu2x_caffe": {
"waifu2x_caffe_path": "C:\\Users\\K4YT3X\\AppData\\Local\\video2x\\waifu2x-caffe\\waifu2x-caffe-cui.exe",
"input_extention_list": null,
"output_extention": null,
"mode": "noise_scale",
"scale_ratio": null,
"scale_width": null,
"scale_height": null,
"noise_level": 3,
"process": "gpu",
"crop_size": 128,
"output_quality": -1,
"output_depth": 8,
"batch_size": 1,
"gpu": 0,
"tta": 0,
"input_path": null,
"output_path": null,
"model_dir": null,
"crop_w": null,
"crop_h": null
},
"waifu2x_converter": {
"waifu2x_converter_path": "C:\\Users\\K4YT3X\\AppData\\Local\\video2x\\waifu2x-converter-cpp",
"output-format": null,
"png-compression": null,
"image-quality": null,
"block-size": null,
"disable-gpu": null,
"force-OpenCL": null,
"processor": null,
"jobs": null,
"model-dir": null,
"scale-ratio": null,
"noise-level": 3,
"mode": "noise-scale",
"silent": true,
"output": null,
"input": null
},
"ffmpeg": {
"ffmpeg_path": "C:\\Users\\K4YT3X\\AppData\\Local\\video2x\\ffmpeg-latest-win64-static\\bin",
"video_to_frames": {
"-qscale:v": null,
"-hwaccel": "auto",
"-y": true
},
"frames_to_video": {
"input_options":{
"-qscale:v": null,
"-qscale:a": null,
"-f": "image2"
},
"output_options":{
"-vcodec": "libx264",
"-crf": 17,
"-b:v": null,
"-pix_fmt": "yuv420p"
},
"-y": true
},
"migrating_tracks": {
"output_options":{
"-map": "0:v:0?",
"-map": "1?",
"-c": "copy",
"-map": "-1:v?",
"-pix_fmt": "yuv420p"
},
"-y": true
}
},
"video2x": {
"video2x_cache_directory": null,
"image_format": "png",
"preserve_frames": false
}
}

View File

@@ -1,358 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
__ __ _ _ ___ __ __
\ \ / / (_) | | |__ \ \ \ / /
\ \ / / _ __| | ___ ___ ) | \ V /
\ \/ / | | / _` | / _ \ / _ \ / / > <
\ / | | | (_| | | __/ | (_) | / /_ / . \
\/ |_| \__,_| \___| \___/ |____| /_/ \_\
Name: Video2X Controller
Author: K4YT3X
Date Created: Feb 24, 2018
Last Modified: April 28, 2019
Licensed under the GNU General Public License Version 3 (GNU GPL v3),
available at: https://www.gnu.org/licenses/gpl-3.0.txt
(C) 2018-2019 K4YT3X
Video2X is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Video2X is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Description: Video2X is an automation software based on waifu2x image
enlarging engine. It extracts frames from a video, enlarge it by a
number of times without losing any details or quality, keeping lines
smooth and edges sharp.
"""
from avalon_framework import Avalon
from upscaler import Upscaler
import argparse
import GPUtil
import json
import os
import psutil
import re
import shutil
import sys
import tempfile
import time
import traceback
VERSION = '2.7.1'
# each thread might take up to 2.5 GB during initialization.
# (system memory, not to be confused with GPU memory)
SYS_MEM_PER_THREAD = 2.5
GPU_MEM_PER_THREAD = 3.5
def process_arguments():
"""Processes CLI arguments
This function parses all arguments
This allows users to customize options
for the output video.
"""
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
# video options
file_options = parser.add_argument_group('File Options')
file_options.add_argument('-i', '--input', help='Source video file/directory', action='store', required=True)
file_options.add_argument('-o', '--output', help='Output video file/directory', action='store', required=True)
# upscaler options
upscaler_options = parser.add_argument_group('Upscaler Options')
upscaler_options.add_argument('-m', '--method', help='Upscaling method', action='store', default='gpu', choices=['cpu', 'gpu', 'cudnn'], required=True)
upscaler_options.add_argument('-d', '--driver', help='Waifu2x driver', action='store', default='waifu2x_caffe', choices=['waifu2x_caffe', 'waifu2x_converter'])
upscaler_options.add_argument('-y', '--model_dir', help='directory containing model JSON files', action='store')
upscaler_options.add_argument('-t', '--threads', help='Number of threads to use for upscaling', action='store', type=int, default=1)
upscaler_options.add_argument('-c', '--config', help='Video2X config file location', action='store', default=f'{os.path.dirname(os.path.abspath(sys.argv[0]))}\\video2x.json')
upscaler_options.add_argument('-b', '--batch', help='Enable batch mode (select all default values to questions)', action='store_true')
# scaling options
scaling_options = parser.add_argument_group('Scaling Options')
scaling_options.add_argument('--width', help='Output video width', action='store', type=int)
scaling_options.add_argument('--height', help='Output video height', action='store', type=int)
scaling_options.add_argument('-r', '--ratio', help='Scaling ratio', action='store', type=float)
# parse arguments
return parser.parse_args()
def print_logo():
print('__ __ _ _ ___ __ __')
print('\\ \\ / / (_) | | |__ \\ \\ \\ / /')
print(' \\ \\ / / _ __| | ___ ___ ) | \\ V /')
print(' \\ \\/ / | | / _` | / _ \\ / _ \\ / / > <')
print(' \\ / | | | (_| | | __/ | (_) | / /_ / . \\')
print(' \\/ |_| \\__,_| \\___| \\___/ |____| /_/ \\_\\')
print('\n Video2X Video Enlarger')
spaces = ((44 - len(f'Version {VERSION}')) // 2) * ' '
print(f'{Avalon.FM.BD}\n{spaces} Version {VERSION}\n{Avalon.FM.RST}')
def check_memory():
""" Check usable system memory
Warn the user if insufficient memory is available for
the number of threads that the user have chosen.
"""
memory_status = []
# get system available memory
system_memory_available = psutil.virtual_memory().available / (1024 ** 3)
memory_status.append(('system', system_memory_available))
# check if Nvidia-smi is available
# GPUtil requires nvidia-smi.exe to interact with GPU
if args.method == 'gpu' or args.method == 'cudnn':
if not os.path.isfile('C:\\Program Files\\NVIDIA Corporation\\NVSMI\\nvidia-smi.exe'):
# Nvidia System Management Interface not available
Avalon.warning('Nvidia-smi not available, skipping available memory check')
Avalon.warning('If you experience error \"cudaSuccess out of memory\", try reducing number of threads you\'re using')
else:
try:
# "0" is GPU ID. Both waifu2x drivers use the first GPU available, therefore only 0 makes sense
gpu_memory_available = (GPUtil.getGPUs()[0].memoryTotal - GPUtil.getGPUs()[0].memoryUsed) / 1024
memory_status.append(('GPU', gpu_memory_available))
except ValueError:
pass
# go though each checkable memory type and check availability
for memory_type, memory_available in memory_status:
if memory_type == 'system':
mem_per_thread = SYS_MEM_PER_THREAD
else:
mem_per_thread = GPU_MEM_PER_THREAD
# if user doesn't even have enough memory to run even one thread
if memory_available < mem_per_thread:
Avalon.warning(f'You might have insufficient amount of {memory_type} memory available to run this program ({memory_available} GB)')
Avalon.warning('Proceed with caution')
if args.threads > 1:
if Avalon.ask('Reduce number of threads to avoid crashing?', default=True, batch=args.batch):
args.threads = 1
# if memory available is less than needed, warn the user
elif memory_available < (mem_per_thread * args.threads):
Avalon.warning(f'Each waifu2x-caffe thread will require up to {SYS_MEM_PER_THREAD} GB of system memory')
Avalon.warning(f'You demanded {args.threads} threads to be created, but you only have {round(memory_available, 4)} GB {memory_type} memory available')
Avalon.warning(f'{mem_per_thread * args.threads} GB of {memory_type} memory is recommended for {args.threads} threads')
Avalon.warning(f'With your current amount of {memory_type} memory available, {int(memory_available // mem_per_thread)} threads is recommended')
# ask the user if he / she wants to change to the recommended
# number of threads
if Avalon.ask('Change to the recommended value?', default=True, batch=args.batch):
args.threads = int(memory_available // mem_per_thread)
else:
Avalon.warning('Proceed with caution')
def read_config(config_file):
""" Reads configuration file
Returns a dictionary read by JSON.
"""
with open(config_file, 'r') as raw_config:
config = json.load(raw_config)
return config
def absolutify_paths(config):
""" Check to see if paths to binaries are absolute
This function checks if paths to binary files are absolute.
If not, then absolutify the path.
Arguments:
config {dict} -- configuration file dictionary
Returns:
dict -- configuration file dictionary
"""
current_directory = os.path.dirname(os.path.abspath(sys.argv[0]))
# check waifu2x-caffe path
if not re.match('^[a-z]:', config['waifu2x_caffe']['waifu2x_caffe_path'], re.IGNORECASE):
config['waifu2x_caffe']['waifu2x_caffe_path'] = f'{current_directory}\\{config["waifu2x_caffe"]["waifu2x_caffe_path"]}'
# check waifu2x-converter-cpp path
if not re.match('^[a-z]:', config['waifu2x_converter']['waifu2x_converter_path'], re.IGNORECASE):
config['waifu2x_converter']['waifu2x_converter_path'] = f'{current_directory}\\{config["waifu2x_converter"]["waifu2x_converter_path"]}'
# check ffmpeg path
if not re.match('^[a-z]:', config['ffmpeg']['ffmpeg_path'], re.IGNORECASE):
config['ffmpeg']['ffmpeg_path'] = f'{current_directory}\\{config["ffmpeg"]["ffmpeg_path"]}'
# check video2x cache path
if config['video2x']['video2x_cache_directory']:
if not re.match('^[a-z]:', config['video2x']['video2x_cache_directory'], re.IGNORECASE):
config['video2x']['video2x_cache_directory'] = f'{current_directory}\\{config["video2x"]["video2x_cache_directory"]}'
return config
# /////////////////// Execution /////////////////// #
# this is not a library
if __name__ != '__main__':
Avalon.error('This file cannot be imported')
raise ImportError(f'{__file__} cannot be imported')
print_logo()
# process CLI arguments
args = process_arguments()
# arguments sanity check
if args.driver == 'waifu2x_converter' and args.width and args.height:
Avalon.error('Waifu2x Converter CPP accepts only scaling ratio')
exit(1)
if (args.width or args.height) and args.ratio:
Avalon.error('You can only specify either scaling ratio or output width and height')
exit(1)
if (args.width and not args.height) or (not args.width and args.height):
Avalon.error('You must specify both width and height')
exit(1)
# check available memory
check_memory()
# read configurations from JSON
config = read_config(args.config)
config = absolutify_paths(config)
# load waifu2x configuration
if args.driver == 'waifu2x_caffe':
waifu2x_settings = config['waifu2x_caffe']
if not os.path.isfile(waifu2x_settings['waifu2x_caffe_path']):
Avalon.error('Specified waifu2x-caffe directory doesn\'t exist')
Avalon.error('Please check the configuration file settings')
raise FileNotFoundError(waifu2x_settings['waifu2x_caffe_path'])
elif args.driver == 'waifu2x_converter':
waifu2x_settings = config['waifu2x_converter']
if not os.path.isdir(waifu2x_settings['waifu2x_converter_path']):
Avalon.error('Specified waifu2x-conver-cpp directory doesn\'t exist')
Avalon.error('Please check the configuration file settings')
raise FileNotFoundError(waifu2x_settings['waifu2x_converter_path'])
# check if waifu2x path is valid
# read FFMPEG configuration
ffmpeg_settings = config['ffmpeg']
# load video2x settings
video2x_cache_directory = config['video2x']['video2x_cache_directory']
image_format = config['video2x']['image_format'].lower()
preserve_frames = config['video2x']['preserve_frames']
# create temp directories if they don't exist
if not video2x_cache_directory:
video2x_cache_directory = f'{tempfile.gettempdir()}\\video2x'
if video2x_cache_directory and not os.path.isdir(video2x_cache_directory):
if not os.path.isfile(video2x_cache_directory) and not os.path.islink(video2x_cache_directory):
Avalon.warning(f'Specified cache directory {video2x_cache_directory} does not exist')
if Avalon.ask('Create directory?', default=True, batch=args.batch):
if os.mkdir(video2x_cache_directory) is None:
Avalon.info(f'{video2x_cache_directory} created')
else:
Avalon.error(f'Unable to create {video2x_cache_directory}')
Avalon.error('Aborting...')
exit(1)
else:
Avalon.error('Specified cache directory is a file/link')
Avalon.error('Unable to continue, exiting...')
exit(1)
# start execution
try:
# start timer
begin_time = time.time()
# if input specified is a single file
if os.path.isfile(args.input):
""" Upscale single video file """
Avalon.info(f'Upscaling single video file: {args.input}')
# check for input output format mismatch
if os.path.isdir(args.output):
Avalon.error('Input and output path type mismatch')
Avalon.error('Input is single file but output is directory')
raise Exception('input output path type mismatch')
if not re.search('.*\..*$', args.output):
Avalon.error('No suffix found in output file path')
Avalon.error('Suffix must be specified for FFmpeg')
raise Exception('No suffix specified')
upscaler = Upscaler(input_video=args.input, output_video=args.output, method=args.method, waifu2x_settings=waifu2x_settings, ffmpeg_settings=ffmpeg_settings)
# set optional options
upscaler.waifu2x_driver = args.driver
upscaler.scale_width = args.width
upscaler.scale_height = args.height
upscaler.scale_ratio = args.ratio
upscaler.model_dir = args.model_dir
upscaler.threads = args.threads
upscaler.video2x_cache_directory = video2x_cache_directory
upscaler.image_format = image_format
upscaler.preserve_frames = preserve_frames
# run upscaler
upscaler.create_temp_directories()
upscaler.run()
upscaler.cleanup_temp_directories()
# if input specified is a directory
elif os.path.isdir(args.input):
""" Upscale videos in a directory """
Avalon.info(f'Upscaling videos in directory: {args.input}')
for input_video in [f for f in os.listdir(args.input) if os.path.isfile(os.path.join(args.input, f))]:
output_video = f'{args.output}\\{input_video}'
upscaler = Upscaler(input_video=os.path.join(args.input, input_video), output_video=output_video, method=args.method, waifu2x_settings=waifu2x_settings, ffmpeg_settings=ffmpeg_settings)
# set optional options
upscaler.waifu2x_driver = args.driver
upscaler.scale_width = args.width
upscaler.scale_height = args.height
upscaler.scale_ratio = args.ratio
upscaler.model_dir = args.model_dir
upscaler.threads = args.threads
upscaler.video2x_cache_directory = video2x_cache_directory
upscaler.image_format = image_format
upscaler.preserve_frames = preserve_frames
# run upscaler
upscaler.create_temp_directories()
upscaler.run()
upscaler.cleanup_temp_directories()
else:
Avalon.error('Input path is neither a file nor a directory')
raise FileNotFoundError(f'{args.input} is neither file nor directory')
Avalon.info(f'Program completed, taking {round((time.time() - begin_time), 5)} seconds')
except Exception:
Avalon.error('An exception has occurred')
traceback.print_exc()
finally:
# remove Video2X Cache directory
try:
if not preserve_frames:
shutil.rmtree(video2x_cache_directory)
except FileNotFoundError:
pass

View File

@@ -1,233 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Name: Video2X Setup Script
Author: K4YT3X
Date Created: November 28, 2018
Last Modified: April 28, 2019
Licensed under the GNU General Public License Version 3 (GNU GPL v3),
available at: https://www.gnu.org/licenses/gpl-3.0.txt
(C) 2018-2019 K4YT3X
Description: This script helps installing all dependencies of video2x
and generates a configuration for it.
Installation Details:
- ffmpeg: %LOCALAPPDATA%\\video2x\\ffmpeg
- waifu2x-caffe: %LOCALAPPDATA%\\video2x\\waifu2x-caffe
"""
import argparse
import json
import os
import subprocess
import sys
import tempfile
import traceback
import zipfile
# Requests doesn't come with windows, therefore
# it will be installed as a dependency and imported
# later in the script.
# import requests
VERSION = '1.2.1'
def process_arguments():
"""Processes CLI arguments
"""
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
# video options
general_options = parser.add_argument_group('General Options')
general_options.add_argument('-d', '--driver', help='driver to download and configure', action='store', choices=['all', 'waifu2x_caffe', 'waifu2x_converter'], default='all')
# parse arguments
return parser.parse_args()
class Video2xSetup:
""" Install dependencies for video2x video enlarger
This library is meant to be executed as a stand-alone
script. All files will be installed under %LOCALAPPDATA%\\video2x.
"""
def __init__(self, driver, download_python_modules):
self.driver = driver
self.download_python_modules = download_python_modules
self.trash = []
def run(self):
if self.download_python_modules:
print('\nInstalling Python libraries')
self._install_python_requirements()
print('\nInstalling FFMPEG')
self._install_ffmpeg()
if self.driver == 'all':
self._install_waifu2x_caffe()
self._install_waifu2x_converter_cpp()
elif self.driver == 'waifu2x_caffe':
self._install_waifu2x_caffe()
elif self.driver == 'waifu2x_converter':
self._install_waifu2x_converter_cpp()
print('\nGenerating Video2X configuration file')
self._generate_config()
print('\nCleaning up temporary files')
self._cleanup()
def _install_python_requirements(self):
""" Read requirements.txt and return its content
"""
with open('requirements.txt', 'r') as req:
for line in req:
package = line.split('==')[0]
pip_install(package)
def _cleanup(self):
""" Cleanup all the temp files downloaded
"""
for file in self.trash:
try:
print(f'Deleting: {file}')
os.remove(file)
except FileNotFoundError:
pass
def _install_ffmpeg(self):
""" Install FFMPEG
"""
latest_release = 'https://ffmpeg.zeranoe.com/builds/win64/static/ffmpeg-latest-win64-static.zip'
ffmpeg_zip = download(latest_release, tempfile.gettempdir())
self.trash.append(ffmpeg_zip)
with zipfile.ZipFile(ffmpeg_zip) as zipf:
zipf.extractall(f'{os.getenv("localappdata")}\\video2x')
def _install_waifu2x_caffe(self):
""" Install waifu2x_caffe
"""
print('\nInstalling waifu2x-caffe')
import requests
# Get latest release of waifu2x-caffe via GitHub API
latest_release = json.loads(requests.get('https://api.github.com/repos/lltcggie/waifu2x-caffe/releases/latest').content)
for a in latest_release['assets']:
if 'waifu2x-caffe.zip' in a['browser_download_url']:
waifu2x_caffe_zip = download(a['browser_download_url'], tempfile.gettempdir())
self.trash.append(waifu2x_caffe_zip)
with zipfile.ZipFile(waifu2x_caffe_zip) as zipf:
zipf.extractall(f'{os.getenv("localappdata")}\\video2x')
def _install_waifu2x_converter_cpp(self):
""" Install waifu2x_caffe
"""
print('\nInstalling waifu2x-converter-cpp')
import re
import requests
# Get latest release of waifu2x-caffe via GitHub API
latest_release = json.loads(requests.get('https://api.github.com/repos/DeadSix27/waifu2x-converter-cpp/releases/latest').content)
for a in latest_release['assets']:
if re.search(r'waifu2x-DeadSix27-win64_v[0-9]*\.zip', a['browser_download_url']):
waifu2x_converter_cpp_zip = download(a['browser_download_url'], tempfile.gettempdir())
self.trash.append(waifu2x_converter_cpp_zip)
with zipfile.ZipFile(waifu2x_converter_cpp_zip) as zipf:
zipf.extractall(f'{os.getenv("localappdata")}\\video2x\\waifu2x-converter-cpp')
def _generate_config(self):
""" Generate video2x config
"""
# Open current video2x.json file as template
with open('video2x.json', 'r') as template:
template_dict = json.load(template)
template.close()
local_app_data = os.getenv('localappdata')
# configure only the specified drivers
if self.driver == 'all':
template_dict['waifu2x_caffe']['waifu2x_caffe_path'] = f'{local_app_data}\\video2x\\waifu2x-caffe\\waifu2x-caffe-cui.exe'
template_dict['waifu2x_converter']['waifu2x_converter_path'] = f'{local_app_data}\\video2x\\waifu2x-converter-cpp'
elif self.driver == 'waifu2x_caffe':
template_dict['waifu2x_caffe']['waifu2x_caffe_path'] = f'{local_app_data}\\video2x\\waifu2x-caffe\\waifu2x-caffe-cui.exe'
elif self.driver == 'waifu2x_converter':
template_dict['waifu2x_converter']['waifu2x_converter_path'] = f'{local_app_data}\\video2x\\waifu2x-converter-cpp'
template_dict['ffmpeg']['ffmpeg_path'] = f'{local_app_data}\\video2x\\ffmpeg-latest-win64-static\\bin'
template_dict['video2x']['video2x_cache_directory'] = None
template_dict['video2x']['preserve_frames'] = False
# Write configuration into file
with open('video2x.json', 'w') as config:
json.dump(template_dict, config, indent=4)
config.close()
def download(url, save_path, chunk_size=4096):
""" Download file to local with requests library
"""
from tqdm import tqdm
import requests
output_file = f'{save_path}\\{url.split("/")[-1]}'
print(f'Downloading: {url}')
print(f'Chunk size: {chunk_size}')
print(f'Saving to: {output_file}')
stream = requests.get(url, stream=True)
total_size = int(stream.headers['content-length'])
# Write content into file
with open(output_file, 'wb') as output:
with tqdm(total=total_size, ascii=True) as progress_bar:
for chunk in stream.iter_content(chunk_size=chunk_size):
if chunk:
output.write(chunk)
progress_bar.update(len(chunk))
return output_file
def pip_install(package):
""" Install python package via python pip module
pip.main() is not available after pip 9.0.1, thus
pip module is not used in this case.
"""
return subprocess.run(['python', '-m', 'pip', 'install', '-U', package]).returncode
if __name__ == "__main__":
try:
args = process_arguments()
print('Video2X Setup Script')
print(f'Version: {VERSION}')
# do not install pip modules if script
# is packaged in exe format
download_python_modules = True
if sys.argv[0].endswith('.exe'):
print('\nScript is packaged as exe, skipping pip module download')
download_python_modules = False
setup = Video2xSetup(args.driver, download_python_modules)
setup.run()
print('\nScript finished successfully')
except Exception:
traceback.print_exc()
print('An error has occurred')
print('Video2X Automatic Setup has failed')
exit(1)

View File

@@ -1,93 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Name: Waifu2x Caffe Driver
Author: K4YT3X
Date Created: Feb 24, 2018
Last Modified: April 28, 2019
Description: This class is a high-level wrapper
for waifu2x-caffe.
"""
from avalon_framework import Avalon
import subprocess
import threading
class Waifu2xCaffe:
"""This class communicates with waifu2x cui engine
An object will be created for this class, containing information
about the binary address and the processing method. When being called
by the main program, other detailed information will be passed to
the upscale function.
"""
def __init__(self, waifu2x_settings, process, model_dir):
self.waifu2x_settings = waifu2x_settings
self.waifu2x_settings['process'] = process
self.waifu2x_settings['model_dir'] = model_dir
# arguments passed through command line overwrites config file values
self.process = process
self.model_dir = model_dir
self.print_lock = threading.Lock()
def upscale(self, input_directory, output_directory, scale_ratio, scale_width, scale_height, image_format, upscaler_exceptions):
"""This is the core function for WAIFU2X class
Arguments:
input_directory {string} -- source directory path
output_directory {string} -- output directory path
width {int} -- output video width
height {int} -- output video height
"""
try:
# overwrite config file settings
self.waifu2x_settings['input_path'] = input_directory
self.waifu2x_settings['output_path'] = output_directory
if scale_ratio:
self.waifu2x_settings['scale_ratio'] = scale_ratio
elif scale_width and scale_height:
self.waifu2x_settings['scale_width'] = scale_width
self.waifu2x_settings['scale_height'] = scale_height
self.waifu2x_settings['output_extention'] = image_format
# print thread start message
self.print_lock.acquire()
Avalon.debug_info(f'[upscaler] Thread {threading.current_thread().name} started')
self.print_lock.release()
# list to be executed
execute = []
execute.append(self.waifu2x_settings['waifu2x_caffe_path'])
for key in self.waifu2x_settings.keys():
value = self.waifu2x_settings[key]
# is executable key or null or None means that leave this option out (keep default)
if key == 'waifu2x_caffe_path' or value is None or value is False:
continue
else:
if len(key) == 1:
execute.append(f'-{key}')
else:
execute.append(f'--{key}')
execute.append(str(value))
Avalon.debug_info(f'Executing: {execute}')
completed_command = subprocess.run(execute, check=True)
# print thread exiting message
self.print_lock.acquire()
Avalon.debug_info(f'[upscaler] Thread {threading.current_thread().name} exiting')
self.print_lock.release()
# return command execution return code
return completed_command.returncode
except Exception as e:
upscaler_exceptions.append(e)

View File

@@ -1,99 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Name: Waifu2x Converter CPP Driver
Author: K4YT3X
Date Created: February 8, 2019
Last Modified: April 28, 2019
Description: This class is a high-level wrapper
for waifu2x-converter-cpp.
"""
from avalon_framework import Avalon
import subprocess
import threading
class Waifu2xConverter:
"""This class communicates with waifu2x cui engine
An object will be created for this class, containing information
about the binary address and the processing method. When being called
by the main program, other detailed information will be passed to
the upscale function.
"""
def __init__(self, waifu2x_settings, model_dir):
self.waifu2x_settings = waifu2x_settings
self.waifu2x_settings['model_dir'] = model_dir
self.print_lock = threading.Lock()
def upscale(self, input_directory, output_directory, scale_ratio, jobs, image_format, upscaler_exceptions):
""" Waifu2x Converter Driver Upscaler
This method executes the upscaling of extracted frames.
Arguments:
input_directory {string} -- source directory path
output_directory {string} -- output directory path
scale_ratio {int} -- frames' scale ratio
threads {int} -- number of threads
"""
try:
# overwrite config file settings
self.waifu2x_settings['input'] = input_directory
self.waifu2x_settings['output'] = output_directory
# temporary fix for https://github.com/DeadSix27/waifu2x-converter-cpp/issues/109
"""
self.waifu2x_settings['i'] = input_directory
self.waifu2x_settings['o'] = output_directory
self.waifu2x_settings['input'] = None
self.waifu2x_settings['output'] = None
"""
self.waifu2x_settings['scale-ratio'] = scale_ratio
self.waifu2x_settings['jobs'] = jobs
self.waifu2x_settings['output-format'] = image_format
# models_rgb must be specified manually for waifu2x-converter-cpp
# if it's not specified in the arguments, create automatically
if self.waifu2x_settings['model-dir'] is None:
self.waifu2x_settings['model-dir'] = f'{self.waifu2x_settings["waifu2x_converter_path"]}\\models_rgb'
# print thread start message
self.print_lock.acquire()
Avalon.debug_info(f'[upscaler] Thread {threading.current_thread().name} started')
self.print_lock.release()
# list to be executed
execute = []
for key in self.waifu2x_settings.keys():
value = self.waifu2x_settings[key]
# the key doesn't need to be passed in this case
if key == 'waifu2x_converter_path':
execute.append(f'{str(value)}\\waifu2x-converter-cpp.exe')
# null or None means that leave this option out (keep default)
elif value is None or value is False:
continue
else:
if len(key) == 1:
execute.append(f'-{key}')
else:
execute.append(f'--{key}')
# true means key is an option
if value is True:
continue
execute.append(str(value))
Avalon.debug_info(f'Executing: {execute}')
return subprocess.run(execute, check=True).returncode
except Exception as e:
upscaler_exceptions.append(e)

96
src/build.ps1 Normal file
View File

@@ -0,0 +1,96 @@
<#
Name: Video2X Build Script
Creator: K4YT3X
Date Created: May 6, 2020
Last Modified: May 13, 2020
Description: A PowerShell script that will build Video2X
executable (PE) releases automatically using PyInstaller.
This script is currently only tuned for K4YT3X's environment.
To start a PowerShell session with execution policy bypass
powershell ExecutionPolicy Bypass
#>
if ($args.count -ne 1){
Write-Host -ForegroundColor White "Usage:`n .\build.ps1 VIDEO2X_VERSION"
Exit
}
# version number
$SCRIPT_VERSION = "1.0.1"
$VIDEO2X_VERSION = $args[0]
Write-Host -ForegroundColor White "Video2X Building Script Version $($SCRIPT_VERSION)
Starting to build Video2X release packages
Building Video2X release $($VIDEO2X_VERSION)"
# build Video2X CLI
Write-Host -ForegroundColor White "`nBuilding Video2X CLI"
pyinstaller --noconfirm --log-level=WARN `
--onefile `
--add-data="locale;locale" `
--add-data="wrappers;wrappers" `
--icon="images\video2x.ico" `
video2x.py
# build Video2X GUI
Write-Host -ForegroundColor White "`nBuilding Video2X GUI"
pyinstaller --noconfirm --log-level=WARN `
--onefile `
--add-data="images;images" `
--add-data="locale;locale" `
--add-data="video2x_gui.ui;." `
--add-data="wrappers;wrappers" `
--icon="images\video2x.ico" `
video2x_gui.py
# build setup script
Write-Host -ForegroundColor White "`nBuilding Video2X setup script"
pyinstaller --noconfirm --log-level=WARN `
--onefile `
--additional-hooks-dir "pyinstaller\hooks" `
--add-data="locale;locale" `
--add-data="pyinstaller\7z1900-extra;7z" `
--icon="images\video2x.ico" `
video2x_setup.py
# remove old builds if found
if (Test-Path "$($VIDEO2X_VERSION)" -PathType any) {
Remove-Item -path "$($VIDEO2X_VERSION)" -recurse
}
# create build directory
New-Item "$($VIDEO2X_VERSION)" -ItemType Directory
# copy files into corresponding builds
# full edition
Write-Host -ForegroundColor White "`nCreating full package"
New-Item "$($VIDEO2X_VERSION)\video2x-$($VIDEO2X_VERSION)-win32-full" -ItemType Directory
Copy-Item "dist\video2x.exe" -Destination "$($VIDEO2X_VERSION)\video2x-$($VIDEO2X_VERSION)-win32-full\"
Copy-Item "dist\video2x_gui.exe" -Destination "$($VIDEO2X_VERSION)\video2x-$($VIDEO2X_VERSION)-win32-full\"
Copy-Item -Path "$env:LOCALAPPDATA\video2x" -Destination "$($VIDEO2X_VERSION)\video2x-$($VIDEO2X_VERSION)-win32-full\dependencies" -Recurse
# overwrite paths to relative paths
(Get-Content "video2x.yaml").replace("%LOCALAPPDATA%\video2x", "dependencies") | Set-Content "video2x.yaml.relative"
Move-Item "video2x.yaml.relative" -Destination "$($VIDEO2X_VERSION)\video2x-$($VIDEO2X_VERSION)-win32-full\video2x.yaml"
# light edition
Write-Host -ForegroundColor White "`nCreating light package"
New-Item "$($VIDEO2X_VERSION)\video2x-$($VIDEO2X_VERSION)-win32-light" -ItemType Directory
Copy-Item "dist\video2x.exe" -Destination "$($VIDEO2X_VERSION)\video2x-$($VIDEO2X_VERSION)-win32-light\"
Copy-Item "dist\video2x_gui.exe" -Destination "$($VIDEO2X_VERSION)\video2x-$($VIDEO2X_VERSION)-win32-light\"
Copy-Item "dist\video2x_setup.exe" -Destination "$($VIDEO2X_VERSION)\video2x-$($VIDEO2X_VERSION)-win32-light\"
Copy-Item "video2x.yaml" -Destination "$($VIDEO2X_VERSION)\video2x-$($VIDEO2X_VERSION)-win32-light\"
Copy-Item "requirements.txt" -Destination "$($VIDEO2X_VERSION)\video2x-$($VIDEO2X_VERSION)-win32-light\"
# clean up temporary files
Write-Host -ForegroundColor White "`nDeleting temporary files"
$pathsToRemove = "__pycache__", "build", "dist", "*.spec"
foreach ($path in $pathsToRemove){
Write-Host "Removing path: $($path)"
Remove-Item -path $path -recurse
}
Write-Host -ForegroundColor White "`nBuild script finished"

28
src/exceptions.py Executable file
View File

@@ -0,0 +1,28 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Name: Video2X Exceptions
Dev: K4YT3X
Date Created: December 13, 2018
Last Modified: July 27, 2019
"""
class ArgumentError(Exception):
def __init__(self, message):
super().__init__(message)
class StreamNotFoundError(Exception):
def __init__(self, message):
super().__init__(message)
class UnrecognizedDriverError(Exception):
def __init__(self, message):
super().__init__(message)
class UnsupportedPixelError(Exception):
def __init__(self, message):
super().__init__(message)

27
bin/image_cleaner.py → src/image_cleaner.py Normal file → Executable file
View File

@@ -3,15 +3,20 @@
"""
Name: Video2X Image Cleaner
Author: BrianPetkovsek
Author: K4YT3X
Date Created: March 24, 2019
Last Modified: April 28, 2019
Last Modified: July 27, 2019
Editor: K4YT3X
Last Modified: March 23, 2020
Editor: 28598519a
Last Modified: March 23, 2020
Description: This class is to remove the extracted frames
that have already been upscaled.
"""
import os
# built-in imports
import threading
import time
@@ -58,19 +63,17 @@ class ImageCleaner(threading.Thread):
"""
# list all images in the extracted frames
output_frames = [f for f in os.listdir(self.output_directory) if os.path.isfile(os.path.join(self.output_directory, f))]
output_frames = [f.name for f in self.output_directory.iterdir() if f.is_file()]
# compare and remove frames downscaled images that finished being upscaled
# within each thread's extracted frames directory
for i in range(self.threads):
dir_path = os.path.join(self.input_directory, str(i))
for thread_id in range(self.threads):
dir_path = self.input_directory / str(thread_id)
# for each file within all the directories
for f in os.listdir(dir_path):
file_path = os.path.join(dir_path, f)
for file in dir_path.iterdir():
# if file also exists in the output directory, then the file
# has already been processed, thus not needed anymore
if os.path.isfile(file_path) and f in output_frames:
os.remove(file_path)
output_frames.remove(f)
if file.is_file() and file.name in output_frames:
file.unlink()
output_frames.remove(file.name)

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

BIN
src/images/Video2X Icon.psd Normal file

Binary file not shown.

BIN
src/images/Video2X Logo.psd Normal file

Binary file not shown.

BIN
src/images/video2x.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

BIN
src/images/video2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,326 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: \n"
"POT-Creation-Date: 2020-05-17 10:10-0400\n"
"PO-Revision-Date: 2020-05-17 10:13-0400\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: zh_CN\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
"X-Generator: Poedit 2.3.1\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: progress_monitor.py:42
msgid "Upscaling Progress"
msgstr "放大进度"
#: upscaler.py:109
msgid "Specified or default cache directory is a file/link"
msgstr "指定或默认的缓存目录是文件/链接"
#: upscaler.py:115
msgid "Creating cache directory {}"
msgstr "创建缓存目录 {}"
#: upscaler.py:118
msgid "Unable to create {}"
msgstr "无法创建 {}"
#: upscaler.py:123
msgid "Extracted frames are being saved to: {}"
msgstr "提取的帧将被保存到:{}"
#: upscaler.py:125
msgid "Upscaled frames are being saved to: {}"
msgstr "已放大的帧将被保存到:{}"
#: upscaler.py:135
msgid "Cleaning up cache directory: {}"
msgstr "清理缓存目录:{}"
#: upscaler.py:138
msgid "Unable to delete: {}"
msgstr "无法删除:{}"
#: upscaler.py:144 upscaler.py:159 upscaler.py:170
msgid "Input and output path type mismatch"
msgstr "输入和输出路径类型不匹配"
#: upscaler.py:145
msgid "Input is multiple files but output is not directory"
msgstr "输入是多个文件,但输出不是目录"
#: upscaler.py:149
msgid "Input path {} is neither a file nor a directory"
msgstr "输入路径 {} 既不是文件也不是目录"
#: upscaler.py:153 upscaler.py:175
msgid "Input directory and output directory cannot be the same"
msgstr "输入目录和输出目录不能相同"
#: upscaler.py:160
msgid "Input is single file but output is directory"
msgstr "所选的输入路径是单个文件,但输出路径是目录"
#: upscaler.py:163
msgid "No suffix found in output file path"
msgstr "在输出文件路径中未找到后缀"
#: upscaler.py:164
msgid "Suffix must be specified"
msgstr "必须指定文件后缀"
#: upscaler.py:171
msgid "Input is directory but output is existing single file"
msgstr "输入是目录,但输出是现有的单个文件"
#: upscaler.py:180
msgid "Input path is neither a file nor a directory"
msgstr "输入路径既不是文件也不是目录"
#: upscaler.py:189
msgid "FFmpeg or FFprobe cannot be found under the specified path"
msgstr "在指定的路径下找不到 FFmpeg 或 FFprobe"
#: upscaler.py:190 upscaler.py:200
msgid "Please check the configuration file settings"
msgstr "请检查配置文件设置"
#: upscaler.py:199
msgid "Specified driver executable directory doesn't exist"
msgstr "指定驱动的可执行文件不存在"
#: upscaler.py:226
msgid "Failed to parse driver argument: {}"
msgstr "解析驱动程序参数失败:{}"
#: upscaler.py:258
msgid "Unrecognized driver: {}"
msgstr "无法识别的驱动名称:{}"
#: upscaler.py:298
msgid "Starting progress monitor"
msgstr "启动进度监视器"
#: upscaler.py:303
msgid "Starting upscaled image cleaner"
msgstr "启动已放大图像清理程序"
#: upscaler.py:312 upscaler.py:329
msgid "Killing progress monitor"
msgstr "终结进度监视器"
#: upscaler.py:315 upscaler.py:332
msgid "Killing upscaled image cleaner"
msgstr "终结已放大图像清理程序"
#: upscaler.py:336
msgid "Terminating all processes"
msgstr "正在终止所有进程"
#: upscaler.py:343
msgid "Main process waiting for subprocesses to exit"
msgstr "主进程开始等待子进程结束"
#: upscaler.py:362 upscaler.py:366
msgid "Subprocess {} exited with code {}"
msgstr "子进程 {} 结束,返回码 {}"
#: upscaler.py:372
msgid "Stop signal received"
msgstr "收到停止信号"
#: upscaler.py:377
msgid "Subprocess execution ran into an error"
msgstr "子进程执行遇到错误"
#: upscaler.py:425
msgid "Upscaling single file: {}"
msgstr "放大单个文件:{}"
#: upscaler.py:461
msgid "Starting to upscale image"
msgstr "开始放大图像"
#: upscaler.py:464 upscaler.py:526
msgid "Upscaling completed"
msgstr "放大完成"
#: upscaler.py:478
msgid "Reading video information"
msgstr "读取视频信息"
#: upscaler.py:492
msgid "Aborting: No video stream found"
msgstr "程序中止:文件中未找到视频流"
#: upscaler.py:497
msgid "Framerate: {}"
msgstr "帧率:{}"
#: upscaler.py:514
msgid "Unsupported pixel format: {}"
msgstr "不支持的像素格式:{}"
#: upscaler.py:524
msgid "Starting to upscale extracted frames"
msgstr "开始对提取的帧进行放大"
#: upscaler.py:531
msgid "File {} ({}) neither an image of a video"
msgstr "文件 {} {} 既不是图片也不是视频"
#: upscaler.py:532
msgid "Skipping this file"
msgstr "将跳过此文件"
#: upscaler.py:542
msgid "Converting extracted frames into GIF image"
msgstr "正在将提取的帧转换为 GIF"
#: upscaler.py:546 upscaler.py:555
msgid "Conversion completed"
msgstr "转换已完成"
#: upscaler.py:551
msgid "Converting extracted frames into video"
msgstr "正在将提取的帧转换为视频"
#: upscaler.py:559
msgid "Migrating audio, subtitles and other streams to upscaled video"
msgstr "正在将音频、字幕和其他流迁移到放大后的视频"
#: upscaler.py:569
msgid "Failed to migrate streams"
msgstr "迁移流失败"
#: upscaler.py:570
msgid "Trying to output video without additional streams"
msgstr "正在尝试输出不含其他流的视频"
#: upscaler.py:586
msgid "Output video file exists"
msgstr "输出目标文件已存在"
#: upscaler.py:590
msgid "Created temporary directory to contain file"
msgstr "为文件创建了临时目录"
#: upscaler.py:593
msgid "Writing intermediate file to: {}"
msgstr "正在将中间视频文件写入至:{}"
#: video2x.py:85
msgid ""
"Video2X CLI Version: {}\n"
"Upscaler Version: {}\n"
"Author: K4YT3X\n"
"License: GNU GPL v3\n"
"Github Page: https://github.com/k4yt3x/video2x\n"
"Contact: k4yt3x@k4yt3x.com"
msgstr ""
"Video2X 版本: {}\n"
"放大组件版本:{}\n"
"作者: K4YT3X\n"
"开源许可: GNU GPL v3\n"
"GitHub 主页https://github.com/k4yt3x/video2x\n"
"联系方式k4yt3x@k4yt3x.com"
#: video2x.py:108
msgid "Video2X Options"
msgstr "Video2X 选项"
#: video2x.py:109
msgid "show this help message and exit"
msgstr "显示此帮助消息并退出"
#: video2x.py:110
msgid "source video file/directory"
msgstr "源视频文件/目录"
#: video2x.py:111
msgid "output video file/directory"
msgstr "输出视频文件/目录"
#: video2x.py:112
msgid "video2x config file path"
msgstr "video2x 配置文件路径"
#: video2x.py:114
msgid "display version, lawful information and exit"
msgstr "显示版本和法律信息并退出"
#: video2x.py:117
msgid "Upscaling Options"
msgstr "视频放大选项"
#: video2x.py:118
msgid "upscaling driver"
msgstr "视频放大驱动"
#: video2x.py:119
msgid "scaling ratio"
msgstr "缩放比"
#: video2x.py:120
msgid "number of processes to use for upscaling"
msgstr "并发进程数"
#: video2x.py:121
msgid "preserve extracted and upscaled frames"
msgstr "保留提取的和放大的帧"
#: video2x.py:161
msgid "This file cannot be imported"
msgstr "此文件无法被当作模块导入"
#: video2x.py:236
msgid "Program completed, taking {} seconds"
msgstr "程序执行完毕,总计花费 {} 秒"
#: video2x.py:239
msgid "An exception has occurred"
msgstr "发生了异常"
#~ msgid "Anime4KCPP doesn't yet support GIF processing"
#~ msgstr "Anime4KCPP 尚不支持GIF处理"
#~ msgid "Starting to upscale video with Anime4KCPP"
#~ msgstr "开始用 Anime4KCPP 放大视频"
#~ msgid "output video width"
#~ msgstr "输出视频宽度"
#~ msgid "output video height"
#~ msgstr "输出视频高度"
#~ msgid "You must specify input video file/directory path"
#~ msgstr "您必须指定输入视频文件/目录路径"
#~ msgid "You must specify output video file/directory path"
#~ msgstr "您必须指定输出视频文件/目录路径"
#~ msgid "Selected driver accepts only scaling ratio"
#~ msgstr "所选驱动程序仅接受缩放比率"
#~ msgid "Scaling ratio must be 1 or 2 for waifu2x_ncnn_vulkan"
#~ msgstr "waifu2x_ncnn_vulkan 的缩放比必须为 1 或 2"
#~ msgid "Scaling ratio must be one of 2, 3 or 4 for srmd_ncnn_vulkan"
#~ msgstr "srmd_ncnn_vulkan 的缩放比必须为 2、3 或 4"
#~ msgid "You can only specify either scaling ratio or output width and height"
#~ msgstr "您只能指定缩放比或输出宽度和高度两者之一"
#~ msgid "You must specify both width and height"
#~ msgstr "您必须同时指定宽度和高度"
#~ msgid "Upscaling videos in directory: {}"
#~ msgstr "放大该文件夹中的所有视频:{}"

64
src/progress_monitor.py Normal file
View File

@@ -0,0 +1,64 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Name: Video2X Upscale Progress Monitor
Author: BrianPetkovsek
Date Created: May 7, 2020
Last Modified: May 10, 2020
"""
# built-in imports
import contextlib
import threading
import time
# third-party imports
from tqdm import tqdm
class ProgressMonitor(threading.Thread):
""" progress monitor
This class provides progress monitoring functionalities
by keeping track of the amount of frames in the input
directory and the output directory. This is originally
suggested by @ArmandBernard.
"""
def __init__(self, upscaler, extracted_frames_directories):
threading.Thread.__init__(self)
self.upscaler = upscaler
self.extracted_frames_directories = extracted_frames_directories
self.running = False
def run(self):
self.running = True
# get number of extracted frames
self.upscaler.total_frames = 0
for directory in self.extracted_frames_directories:
self.upscaler.total_frames += len([f for f in directory.iterdir() if str(f).lower().endswith(self.upscaler.image_format.lower())])
with tqdm(total=self.upscaler.total_frames, ascii=True, desc=_('Upscaling Progress')) as progress_bar:
# tqdm update method adds the value to the progress
# bar instead of setting the value. Therefore, a delta
# needs to be calculated.
previous_cycle_frames = 0
while self.running:
with contextlib.suppress(FileNotFoundError):
upscaled_frames = [f for f in self.upscaler.upscaled_frames.iterdir() if str(f).lower().endswith(self.upscaler.image_format.lower())]
if len(upscaled_frames) >= 1:
self.upscaler.last_frame_upscaled = sorted(upscaled_frames)[-1]
self.upscaler.total_frames_upscaled = len(upscaled_frames)
# update progress bar
delta = self.upscaler.total_frames_upscaled - previous_cycle_frames
previous_cycle_frames = self.upscaler.total_frames_upscaled
progress_bar.update(delta)
time.sleep(1)
def stop(self):
self.running = False
self.join()

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,85 @@
.Language=English,English
.PluginContents=7-Zip Plugin
@Contents
$^#7-Zip Plugin 19.00#
$^#Copyright (c) 1999-2019 Igor Pavlov#
This FAR module performs transparent #archive# processing.
Files in the archive are handled in the same manner as if they
were in a folder.
~Extracting from the archive~@Extract@
~Add files to the archive~@Update@
~7-Zip Plugin configuration~@Config@
Web site: #www.7-zip.org#
@Extract
$ #Extracting from the archive#
In this dialog you may enter extracting mode.
Path mode
#Full pathnames# Extract files with full pathnames.
#Current pathnames# Extract files with all relative paths.
#No pathnames# Extract files without folder paths.
Overwrite mode
#Ask before overwrite# Ask before overwriting existing files.
#Overwrite without prompt# Overwrite existing files without prompt.
#Skip existing files# Skip extracting of existing files.
Files
#Selected files# Extract only selected files.
#All files# Extract all files from archive.
@Update
$ #Add files to the archive#
This dialog allows you to specify options for process of updating archive.
Compression method
#Store# Files will be copied to archive without compression.
#Normal# Files will be compressed.
#Maximum# Files will be compressed with method that gives
maximum compression ratio.
Update mode
#Add and replace files# Add all specified files to the archive.
#Update and add files# Update older files in the archive and add
files that are new to the archive.
#Freshen existing files# Update specified files in the archive that
are older than the selected disk files.
#Synchronize files# Replace specified files only if
added files are newer. Always add those
files, which are not present in the
archive. Delete from archive those files,
which are not present on the disk.
@Config
$ #7-Zip Plugin configuration#
In this dialog you may change following parameters:
#Plugin is used by default# Plugin is used by default.

View File

@@ -0,0 +1,211 @@
.Language=English,English
"Ok"
"&Cancel"
"Warning"
"Error"
"Format"
"Properties"
"Yes"
"No"
"Get password"
"Enter password"
"Extract"
"&Extract to"
"Path mode"
"&Full pathnames"
"C&urrent pathnames"
"&No pathnames"
"Overwrite mode"
"As&k before overwrite"
"&Overwrite without prompt"
"Sk&ip existing files"
"A&uto rename"
"A&uto rename existing files"
"Extract"
"&Selected files"
"A&ll files"
"&Password"
"Extr&act"
"&Cancel"
"Can not open output file '%s'."
"Unsupported compression method for '%s'."
"CRC failed in '%s'."
"Data error in '%s'."
"CRC failed in encrypted file '%s'. Wrong password?"
"Data error in encrypted file '%s'. Wrong password?"
"Confirm File Replace"
"Destination folder already contains processed file."
"Would you like to replace the existing file"
"with this one"
"bytes"
"modified on"
"&Yes"
"Yes to &All"
"&No"
"No to A&ll"
"A&uto rename"
"&Cancel"
"Update operations are not supported for this archive."
"Delete from archive"
"Delete \"%.40s\" from the archive"
"Delete selected files from the archive"
"Delete %d files from the archive"
"Delete"
"Cancel"
"Add files to archive"
"Add to %s a&rchive:"
"Compression method"
"&Store"
"Fas&test"
"&Fast"
"&Normal"
"&Maximum"
"&Ultra"
"Update mode"
"A&dd and replace files"
"&Update and add files"
"&Freshen existing files"
"S&ynchronize files"
"&Add"
"Se&lect archiver"
"Select archive format"
"Wait"
"Reading the archive"
"Extracting from the archive"
"Deleting from the archive"
"Updating the archive"
"Move operation is not supported"
"7-Zip"
"7-Zip (add to archive)"
"7-Zip"
"Plugin is used by default"
"0"
"1"
"2"
"Path"
"Name"
"Extension"
"Is Folder"
"Size"
"Packed Size"
"Attributes"
"Created"
"Accessed"
"Modified"
"Solid"
"Commented"
"Encrypted"
"Splited Before"
"Splited After"
"Dictionary Size"
"CRC"
"Type"
"Anti"
"Method"
"Host OS"
"File System"
"User"
"Group"
"Block"
"Comment"
"Position"
"Path Prefix"
"Folders"
"Files"
"Version"
"Volume"
"Multivolume"
"Offset"
"Links"
"Blocks"
"Volumes"
"Time Type"
"64-bit"
"Big-endian"
"CPU"
"Physical Size"
"Headers Size"
"Checksum"
"Characteristics"
"Virtual Address"
"ID"
"Short Name"
"Creator Application"
"Sector Size"
"Mode"
"Symbolic Link"
"Error"
"Total Size"
"Free Space"
"Cluster Size"
"Label"
"Local Name"
"Provider"
"NT Security"
"Alternate Stream"
"Aux"
"Deleted"
"Tree"
"SHA-1"
"SHA-256"
"Error Type"
"Errors"
"Errors"
"Warnings"
"Warning"
"Streams"
"Alternate Streams"
"Alternate Streams Size"
"Virtual Size"
"Unpack Size"
"Total Physical Size"
"Volume Index"
"SubType"
"Short Comment"
"Code Page"
"Is not archive type"
"Physical Size can't be detected"
"Zeros Tail Is Allowed"
"Tail Size"
"Embedded Stub Size"
"Link"
"Hard Link"
"iNode"
"Stream ID"
"Read-only"
"Out Name"
"Copy Link"

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,84 @@
.Language=Russian,Russian (<28><><EFBFBD><EFBFBD>)
.PluginContents=<3D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 7-Zip
@Contents
$^#7-Zip Plugin 19.00#
$^#Copyright (c) 1999-2019 Igor Pavlov#
<20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> FAR <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><><E0A0A1><EFBFBD><EFBFBD><EFBFBD> <20> #<23><><EFBFBD><E5A8A2><EFBFBD>#. <20><><EFBFBD> <20><><EFBFBD><EFBFBD><ECA7AE><EFBFBD>
<EFBFBD><EFBFBD> <20> <20><><EFBFBD><E5A8A2> <20><> <20><EFBFBD><E2ABA8><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><><E4A0A9><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
~<7E><><EFBFBD><E1AFA0><EFBFBD><EFBFBD><EFBFBD><><E4A0A9><EFBFBD> <20><> <20><><EFBFBD>~@Extract@
~<7E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><><E4A0A9><EFBFBD> <20> <20><><EFBFBD>~@Update@
~<7E><><EFBFBD><E0A0AC><EFBFBD><EFBFBD><><E0A0A1><EFBFBD> <20> <20><><EFBFBD><E5A8A2><EFBFBD>~@Config@
Web site: #www.7-zip.org#
@Extract
$ #<23><><EFBFBD><E1AFA0><EFBFBD><EFBFBD><EFBFBD><><E4A0A9><EFBFBD> <20><> <20><><EFBFBD>#
<20> <20><20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><E1AFA0><EFBFBD><EFBFBD><EFBFBD><><E4A0A9><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD> <20><><EFBFBD><E1AFA0><EFBFBD><EFBFBD><EFBFBD>.
<20><><EFBFBD><EFBFBD>
#<23><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD># <20><><EFBFBD><E1AFA0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><><E4A0A9> <20> <20><><EFBFBD><EFBFBD><20><><EFBFBD>ﬨ.
#<23><EFBFBD><E2ADAE><EFBFBD><E2A5AB><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD># <20><><EFBFBD><E1AFA0><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><EFBFBD><E2ADAE><EFBFBD><E2A5AB><20><><EFBFBD>ﬨ.
#<23><><EFBFBD> <20><>⥩# <20><><EFBFBD><E1AFA0><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><>⥩.
<20><><EFBFBD><E0A5A7><EFBFBD><EFBFBD><EFBFBD>
#<23><><EFBFBD><EFBFBD><EFBFBD><E8A8A2><EFBFBD> <20><><EFBFBD>⢥ত<E2A2A5><E0A6A4><EFBFBD><EFBFBD># <20><><EFBFBD><EFBFBD><EFBFBD><E8A8A2><EFBFBD> <20><><EFBFBD>⢥ত<E2A2A5><E0A6A4><EFBFBD><EFBFBD> <20><>
<20><><EFBFBD><E0A5A7><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><><E4A0A9>.
#<23><><EFBFBD> <20><><EFBFBD>⢥ত<E2A2A5><E0A6A4><EFBFBD><EFBFBD># <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>騩 䠩<>
<20><><EFBFBD> <20><><EFBFBD>⢥ত<E2A2A5><E0A6A4><EFBFBD><EFBFBD>.
#<23><EFBFBD><EFBFBD><E1AAA0># <20><EFBFBD><EFBFBD><E1AAA0> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>騥 䠩<><E4A0A9>.
<20><><EFBFBD><E1AFA0><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
#<23><><EFBFBD><EFBFBD><E0A0AD><EFBFBD><><E4A0A9># <20><><EFBFBD><E1AFA0><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ⮫쪮 <20><EFBFBD><EBA4A5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><><E4A0A9> <20><> <20><><EFBFBD>.
#<23><><EFBFBD><><E4A0A9># <20><><EFBFBD><E1AFA0><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><><E4A0A9> <20><> <20><><EFBFBD>.
@Update
$ #<23><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><><E4A0A9><EFBFBD> <20> <20><><EFBFBD>#
<20> <20><20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <><E0A5A6><><E3AFA0><EFBFBD><EFBFBD><EFBFBD>.
<20><>⮤ ᦠ<><E1A6A0><EFBFBD>:
#<23><><EFBFBD><><E1A6A0><EFBFBD># <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><><E1AAAE><EFBFBD><E0AEA2><EFBFBD> <20><><EFBFBD><><E1A6A0><EFBFBD>.
#<23><><EFBFBD><EFBFBD> ᦠ⨥# <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><><E1A6A0>.
#<23><><EFBFBD><EFBFBD><E1A8AC><EFBFBD> ᦠ⨥# <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><><E1A6A0> <20> <20><><EFBFBD><EFBFBD><E1A8AC><EFBFBD>
<20><EFBFBD><E2A5AF><EFBFBD><EFBFBD><><E1A6A0><EFBFBD>.
<20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>:
#<23><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD># <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><E0A0AD><EFBFBD><><E4A0A9> <20> <20><>娢.
#<23><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD># <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>ॢ訥 䠩<><E4A0A9> <20> <20><><EFBFBD> <20>
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><><E4A0A9>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20> <20><><EFBFBD>.
#<23><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD># <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>ॢ訥 䠩<><E4A0A9> <20> <20><><EFBFBD>.
#<23><><EFBFBD><EFBFBD><EFBFBD><E0AEAD><EFBFBD><EFBFBD><E0AEA2><EFBFBD># <20><><EFBFBD><EFBFBD><EFBFBD><E0AEAD><EFBFBD><EFBFBD><E0AEA2><EFBFBD><><EFBFBD><E0A6A8><EFBFBD> <20><><EFBFBD>
<20> <20><><EFBFBD><EFBFBD>묨 䠩<><E4A0A9><EFBFBD><EFBFBD>.
@Config
$ #<23><><EFBFBD><E0A0AC><EFBFBD><EFBFBD><><E0A0A1><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 7-Zip#
<20> <20><20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><><E1ABA5><EFBFBD><20><><EFBFBD><E0A0AC><EFBFBD><EFBFBD>:
#<23><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><EFBFBD><E1AFAE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><><EFBFBD><E7A0AD># <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><EFBFBD><E1AFAE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><><EFBFBD><E7A0AD>

View File

@@ -0,0 +1,211 @@
.Language=Russian,Russian (<28><><EFBFBD><EFBFBD>)
"<22><EFBFBD><E0AEA4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"&<26><EFBFBD><E2ACA5><EFBFBD><EFBFBD>"
"<22><EFBFBD><E0A5A4><EFBFBD><E0A5A6><EFBFBD><EFBFBD><EFBFBD>"
"<22><EFBFBD><E8A8A1>"
"<22><><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD>⢠"
"<22><>"
"<22><><EFBFBD>"
"<22><><EFBFBD><EFBFBD> <20><><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>"
"<22><><EFBFBD><E1AFA0><EFBFBD><EFBFBD><EFBFBD>"
"&<26><><EFBFBD><E1AFA0><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>"
"<22><><EFBFBD><EFBFBD>"
"<22><>&<26><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>"
"<22>&⭮<><E2ADAE><EFBFBD><E2A5AB><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>"
"&<26><><EFBFBD> <20><>⥩"
"<22><><EFBFBD><E0A5A7><EFBFBD><EFBFBD><EFBFBD>"
"&<26><><EFBFBD><EFBFBD><EFBFBD><E8A8A2><EFBFBD> <20><><EFBFBD>⢥ত<E2A2A5><E0A6A4><EFBFBD><EFBFBD>"
"<22>&<26><> <20><><EFBFBD>⢥ত<E2A2A5><E0A6A4><EFBFBD><EFBFBD>"
"<22>ய&<26><EFBFBD><E1AAA0>"
"<22><><EFBFBD><E0A5A8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>⮬."
"<22><><EFBFBD>. <20><>⮬. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>."
"<22><><EFBFBD><E1AFA0><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22>&<26><><EFBFBD><E0A0AD><EFBFBD><><E4A0A9>"
"<22><><EFBFBD> &䠩<><E4A0A9>"
"&<26><><EFBFBD>"
"<22>&<26><EFBFBD><E1AFA0><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"&<26><EFBFBD><E2ACA5><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><> '%s'."
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E0A6A8><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>⮤ ᦠ<><E1A6A0><EFBFBD> <20><><EFBFBD><><E4A0A9> '%s'."
"<22><EFBFBD><E8A8A1> CRC <20> '%s'."
"<22><EFBFBD><E8A8A1> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> '%s'."
"<22><EFBFBD><E8A8A1> CRC <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E0AEA2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><><E4A0A9> '%s'. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>?"
"<22><EFBFBD><E8A8A1> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E0AEA2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><><E4A0A9> '%s'. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>?"
"<22><><EFBFBD>⢥न<E2A2A5><E0A4A8> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><><E4A0A9>"
"<22><><EFBFBD><EFBFBD><EFBFBD> 㦥 ᮤ<><EFBFBD> <20><><EFBFBD><E0A0A1><EFBFBD><EBA2A0><EFBFBD><EFBFBD><>."
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>騩 䠩<>"
"᫥<><E1ABA5><EFBFBD>騬 䠩<><E4A0A9><EFBFBD>"
"<22><><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"&<26><>"
"<22><> <20><><EFBFBD> &<26><><EFBFBD><EFBFBD>"
"&<26><><EFBFBD>"
"<22><><EFBFBD> <20><><EFBFBD> <20>&<26><><EFBFBD>"
"<22><><EFBFBD><E0A5A8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><E2AEAC><EFBFBD><EFBFBD><EFBFBD>᪨"
"&<26><EFBFBD><E2ACA5><EFBFBD><EFBFBD>"
"<22><><EFBFBD> <20><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E0A6A8><EFBFBD><EFBFBD><EFBFBD><EFBFBD>."
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> \"%.40s\" <20><> <20><><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><E0A0AD><EFBFBD><><E4A0A9> <20><> <20><><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> %d 䠩<><E4A0A9><EFBFBD> <20><> <20><><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><EFBFBD><E2ACA5>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><><E4A0A9> <20> <20><><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> %s &<26><><EFBFBD>"
"<22><>⮤ ᦠ<><E1A6A0><EFBFBD>"
"<22><><EFBFBD><><E1A6A0><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><E0ACA0><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><E1A8AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><E0AEAD><EFBFBD><EFBFBD><E0AEA2><EFBFBD>"
"&<26><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22>&<26><EFBFBD><E5A8A2><EFBFBD><EFBFBD>"
"<22><EFBFBD> <20><><EFBFBD><E5A8A2><EFBFBD><EFBFBD> <20><><EFBFBD><E0ACA0>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><EFBFBD><E2A5AD> <20><><EFBFBD>"
"<22><><EFBFBD><E1AFA0><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><E9A5AD><><E4A0A9><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E0A6A8><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"7-Zip"
"7-Zip (<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><>娢)"
"7-Zip configuration"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><EFBFBD><E1AFAE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><><EFBFBD><E7A0AD>"
"0"
"1"
"2"
"<22><><EFBFBD><EFBFBD>"
"<22><><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E0A5AD>"
"<22><><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><E0A8A1><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EBA2AD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>਩"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E0AEA2>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>᫥"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"CRC"
"<22><><EFBFBD>"
"<22><><EFBFBD><EFBFBD>"
"<22><>⮤"
"<22><><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><ECA7AE><EFBFBD>"
"<22><><EFBFBD>"
"<22><><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>਩"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E2AEAC><EFBFBD>"
"<22><><EFBFBD><EFBFBD><E9A5AD>"
"<22><><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD>"
"Time Type"
"64-bit"
"Big-endian"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD>. <20><EFBFBD>"
"<22><><EFBFBD><E0A0AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><E3A0AB><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>"
"ID"
"<22><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>"
"<22>ணࠬ<E0AEA3><E0A0AC>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><><E1A5AA><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>"
"<22><EFBFBD><E8A8A1>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><>⪠"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>"
"<22><EFBFBD><E0AEA2><EFBFBD><EFBFBD><EFBFBD>"
"NT <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E1ADAE><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD>ୠ⨢<E0ADA0><E2A8A2><EFBFBD> <20><>⮪"
"Aux"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD>"
"SHA-1"
"SHA-256"
"<22><><EFBFBD> <20><EFBFBD><E8A8A1>"
"<22><EFBFBD><E8A8A1>"
"<22><EFBFBD><E8A8A1>"
"<22><EFBFBD><E0A5A4><EFBFBD><E0A5A6><EFBFBD><EFBFBD><EFBFBD>"
"<22><EFBFBD><E0A5A4><EFBFBD><E0A5A6><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD>ୠ⨢<E0ADA0><E2A8A2><EFBFBD> <20><><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ୠ⨢<E0ADA0><E2A8A2><EFBFBD> <20><><EFBFBD><E2AEAA>"
"<22><><EFBFBD><EFBFBD><EFBFBD><E3A0AB><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><E1AFA0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><><20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>"
"<22><><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>਩"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><E0A0AD><EFBFBD>"
"Is not archive type"
"Physical Size can't be detected"
"Zeros Tail Is Allowed"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>⪠"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><E0AEA5><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD>"
"<22><><EFBFBD><EFBFBD> <20><><EFBFBD>"
"iNode"
"ID <20><><EFBFBD>"
"<22><><EFBFBD><20><><EFBFBD> <20><EFBFBD><E2A5AD>"
"Out Name"
"Copy Link"

View File

@@ -0,0 +1,67 @@
; 7z supporting for MutiArc in Far
; Append the following strings to file
; ..\Program Files\Far\Plugins\MultiArc\Formats\Custom.ini
[7z]
TypeName=7z
ID=37 7A BC AF 27 1C
IDPos=
IDOnly=1
Extension=7z
List=7z l -- %%AQ
Start="^-----"
End="^-----"
Format0="yyyy tt dd hh mm ss aaaaa zzzzzzzzzzzz pppppppppppp nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn"
Extract=7z x {-p%%P} -r0 -y -scsDOS -i@%%LQMN -- %%A
ExtractWithoutPath=7z e {-p%%P} -r0 -y -scsDOS -i@%%LQMN -- %%A
Test=7z t {-p%%P} -r0 -scsDOS -i@%%LQMN -- %%A
Delete=7z d {-p%%P} -r0 -ms=off -scsDOS -i@%%LQMN -- %%A
Add=7z a {-p%%P} -r0 -t7z {%%S} -scsDOS -i@%%LQMN -- %%A
AddRecurse=7z a {-p%%P} -r0 -t7z {%%S} -scsDOS -i@%%LQMN -- %%A
AllFilesMask="*"
[rpm]
TypeName=rpm
ID=ED AB EE DB
IDPos=
IDOnly=1
Extension=rpm
List=7z l -- %%AQ
Start="^-----"
End="^-----"
Format0="yyyy tt dd hh mm ss aaaaa zzzzzzzzzzzz pppppppppppp nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn"
Extract=7z x {-p%%P} -r0 -y -scsDOS -i@%%LQMN -- %%A
ExtractWithoutPath=7z e {-p%%P} -r0 -y -scsDOS -i@%%LQMN -- %%A
Test=7z t {-p%%P} -r0 -scsDOS -i@%%LQMN -- %%A
AllFilesMask="*"
[cpio]
TypeName=cpio
ID=
IDPos=
IDOnly=0
Extension=cpio
List=7z l -- %%AQ
Start="^-----"
End="^-----"
Format0="yyyy tt dd hh mm ss aaaaa zzzzzzzzzzzz pppppppppppp nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn"
Extract=7z x {-p%%P} -r0 -y -scsDOS -i@%%LQMN -- %%A
ExtractWithoutPath=7z e {-p%%P} -r0 -y -scsDOS -i@%%LQMN -- %%A
Test=7z t {-p%%P} -r0 -scsDOS -i@%%LQMN -- %%A
AllFilesMask="*"
[deb]
TypeName=deb
ID=
IDPos=
IDOnly=0
Extension=deb
List=7z l -- %%AQ
Start="^-----"
End="^-----"
Format0="yyyy tt dd hh mm ss aaaaa zzzzzzzzzzzz pppppppppppp nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn"
Extract=7z x {-p%%P} -r0 -y -scsDOS -i@%%LQMN -- %%A
ExtractWithoutPath=7z e {-p%%P} -r0 -y -scsDOS -i@%%LQMN -- %%A
Test=7z t {-p%%P} -r0 -scsDOS -i@%%LQMN -- %%A
AllFilesMask="*"

View File

@@ -0,0 +1,67 @@
REGEDIT4
[HKEY_LOCAL_MACHINE\SOFTWARE\Far\Plugins\MultiArc\ZIP]
"Extract"="7z x {-p%%P} -r0 -y {-w%%W} -scsDOS -i@%%LQMN -- %%A"
"ExtractWithoutPath"="7z e {-p%%P} -r0 -y {-w%%W} -scsDOS -i@%%LQMN -- %%A"
"Test"="7z t {-p%%P} -r0 -scsDOS -i@%%LQMN -- %%A"
"Delete"="7z d {-p%%P} -r0 {-w%%W} -scsDOS -i@%%LQMN -- %%A"
"Add"="7z a {-p%%P} -r0 -tzip {-w%%W} {%%S} -scsDOS -i@%%LQMN -- %%A"
"AddRecurse"="7z a {-p%%P} -r0 -tzip {-w%%W} {%%S} -scsDOS -i@%%LQMN -- %%A"
"AllFilesMask"="*"
[HKEY_LOCAL_MACHINE\SOFTWARE\Far\Plugins\MultiArc\TAR]
"Extract"="7z x -r0 -y {-w%%W} -scsDOS -i@%%LQMN -- %%A"
"ExtractWithoutPath"="7z e -r0 -y {-w%%W} -scsDOS -i@%%LQMN -- %%A"
"Test"="7z t -r0 -scsDOS -i@%%LQMN -- %%A"
"Delete"="7z d -r0 {-w%%W} -scsDOS -i@%%LQMN -- %%A"
"Add"="7z a -r0 -y -ttar {-w%%W} {%%S} -scsDOS -i@%%LQMN -- %%A"
"AddRecurse"="7z a -r0 -y -ttar {-w%%W} {%%S} -scsDOS -i@%%LQMN -- %%A"
"AllFilesMask"="*"
[HKEY_LOCAL_MACHINE\SOFTWARE\Far\Plugins\MultiArc\GZIP]
"Extract"="7z x -r0 -y {-w%%W} -scsDOS -i@%%LQMN -- %%A"
"ExtractWithoutPath"="7z e -r0 -y {-w%%W} -scsDOS -i@%%LQMN -- %%A"
"Test"="7z t -r0 -scsDOS -i@%%LQMN -- %%A"
"Delete"="7z d -r0 {-w%%W} -scsDOS -i@%%LQMN -- %%A"
"Add"="7z a -r0 -tgzip {-w%%W} {%%S} -scsDOS -i@%%LQMN -- %%A"
"AddRecurse"="7z a -r0 -tgzip {-w%%W} {%%S} -scsDOS -i@%%LQMN -- %%A"
"AllFilesMask"="*"
[HKEY_LOCAL_MACHINE\SOFTWARE\Far\Plugins\MultiArc\BZIP]
"Extract"="7z x -r0 -y {-w%%W} -scsDOS -i@%%LQMN -- %%A"
"ExtractWithoutPath"="7z e -r0 -y {-w%%W} -scsDOS -i@%%LQMN -- %%A"
"Test"="7z t -r0 -scsDOS -i@%%LQMN -- %%A"
"Delete"="7z d -r0 {-w%%W} -scsDOS -i@%%LQMN -- %%A"
"Add"="7z a -r0 -tbzip2 {-w%%W} {%%S} -scsDOS -i@%%LQMN -- %%A"
"AddRecurse"="7z a -r0 -tbzip2 {-w%%W} {%%S} -scsDOS -i@%%LQMN -- %%A"
"AllFilesMask"="*"
[HKEY_LOCAL_MACHINE\SOFTWARE\Far\Plugins\MultiArc\ARJ]
"Extract"="7z x -r0 -y {-w%%W} -scsDOS -i@%%LQMN -- %%A"
"ExtractWithoutPath"="7z e -r0 -y {-w%%W} -scsDOS -i@%%LQMN -- %%A"
"Test"="7z t -r0 -scsDOS -i@%%LQMN -- %%A"
"AllFilesMask"="*"
[HKEY_LOCAL_MACHINE\SOFTWARE\Far\Plugins\MultiArc\CAB]
"Extract"="7z x -r0 -y {-w%%W} -scsDOS -i@%%LQMN -- %%A"
"ExtractWithoutPath"="7z e -r0 -y {-w%%W} -scsDOS -i@%%LQMN -- %%A"
"Test"="7z t -r0 -scsDOS -i@%%LQMN -- %%A"
"AllFilesMask"="*"
[HKEY_LOCAL_MACHINE\SOFTWARE\Far\Plugins\MultiArc\LZH]
"Extract"="7z x -r0 -y {-w%%W} -scsDOS -i@%%LQMN -- %%A"
"ExtractWithoutPath"="7z e -r0 -y {-w%%W} -scsDOS -i@%%LQMN -- %%A"
"Test"="7z t -r0 -scsDOS -i@%%LQMN -- %%A"
"AllFilesMask"="*"
[HKEY_LOCAL_MACHINE\SOFTWARE\Far\Plugins\MultiArc\RAR]
"Extract"="7z x -r0 -y {-w%%W} -scsDOS -i@%%LQMN -- %%A"
"ExtractWithoutPath"="7z e -r0 -y {-w%%W} -scsDOS -i@%%LQMN -- %%A"
"Test"="7z t -r0 -scsDOS -i@%%LQMN -- %%A"
"AllFilesMask"="*"
[HKEY_LOCAL_MACHINE\SOFTWARE\Far\Plugins\MultiArc\Z(Unix)]
"Extract"="7z x -r0 -y {-w%%W} -scsDOS -i@%%LQMN -- %%A"
"ExtractWithoutPath"="7z e -r0 -y {-w%%W} -scsDOS -i@%%LQMN -- %%A"
"Test"="7z t -r0 -scsDOS -i@%%LQMN -- %%A"
"AllFilesMask"="*"

View File

@@ -0,0 +1,67 @@
7-Zip Plugin for FAR Manager
----------------------------
FAR Manager is a file manager working in text mode.
You can download "FAR Manager" from site:
http://www.farmanager.com
Files:
far7z.txt - This file
far7z.reg - Regisrty file for MultiArc Plugin
7zToFar.ini - Supporting 7z for MultiArc Plugin
7-ZipFar.dll - 7-Zip Plugin for FAR Manager
7-ZipEng.hlf - Help file in English for FAR Manager
7-ZipRus.hlf - Help file in Russian for FAR Manager
7-ZipEng.lng - Plugin message strings in English for FAR Manager
7-ZipRus.lng - Plugin message strings in Russian for FAR Manager
There are two ways to use 7-Zip with FAR Manager:
1) Via 7-Zip FAR Plugin (it's recommended way).
2) Via standard MultiArc Plugin.
7-Zip FAR Plugin
~~~~~~~~~~~~~~~~
7-Zip FAR Plugin is first level plugin for FAR Manager, like MultiArc plugin.
It very fast extracts and updates files in archive, since it doesn't use
external programs. It supports all formats supported by 7-Zip:
7z, ZIP, RAR, CAB, ARJ, GZIP, BZIP2, Z, TAR, CPIO, RPM and DEB.
To install 7-Zip FAR Plugin:
1) Create "7-Zip" folder in ...\Program Files\Far\Plugins folder.
2) Copy all files from "FAR" folder of this package to created folder.
3) Install 7-Zip, or copy 7z.dll from 7-Zip to Program Files\Far\Plugins\7-Zip\
4) Restart FAR.
You can open archives with one of the following ways:
* Pressing Enter.
* Pressing Ctrl-PgDown.
* Pressing F11 and selecting 7-Zip item.
You can create new archives with 7-Zip by pressing F11 and
selecting 7-Zip (add to archive) item.
If you think that some operations with archives is better to do with MultiArc Plugin,
you can disable 7-Zip plugin via Options / Pligin configuration / 7-Zip. In such mode
opening archives by pressing Enter and Ctrl-PgDown will start MultiArc Plugin. And
if you want to open archive with 7-Zip, press F11 and select 7-Zip item.
Using command line 7-Zip via MultiArc Plugin
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you want to use 7-Zip via MultiArc Plugin, you must
register file far7z.reg.
If you want to use 7z archives via MultiArc Plugin, you must
append contents of file Far\7zToFar.ini to file
..\Program Files\Far\Plugins\MultiArc\Formats\Custom.ini.
If you want to cancel using 7-Zip by MultiArc, just remove lines that contain
7-Zip (7z) program name from HKEY_LOCAL_MACHINE\SOFTWARE\Far\Plugins\MultiArc\ZIP
registry key.

View File

@@ -0,0 +1,31 @@
7-Zip Extra
~~~~~~~~~~~
License for use and distribution
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Copyright (C) 1999-2019 Igor Pavlov.
7-Zip Extra files are under the GNU LGPL license.
Notes:
You can use 7-Zip Extra on any computer, including a computer in a commercial
organization. You don't need to register or pay for 7-Zip.
GNU LGPL information
--------------------
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You can receive a copy of the GNU Lesser General Public License from
http://www.gnu.org/

View File

@@ -0,0 +1,111 @@
7-Zip Extra history
-------------------
This file contains only information about changes related to that package exclusively.
The full history of changes is listed in history.txt in main 7-Zip program.
19.00 2019-02-21
-------------------------
- Encryption strength for 7z archives was increased:
the size of random initialization vector was increased from 64-bit to 128-bit,
and the pseudo-random number generator was improved.
- Some bugs were fixed.
18.06 2018-12-30
-------------------------
- The speed for LZMA/LZMA2 compressing was increased by 3-10%,
and there are minor changes in compression ratio.
- Some bugs were fixed.
18.05 2018-04-30
-------------------------
- The speed for LZMA/LZMA2 compressing was increased
by 8% for fastest/fast compression levels and
by 3% for normal/maximum compression levels.
18.03 beta 2018-03-04
-------------------------
- The speed for single-thread LZMA/LZMA2 decoding
was increased by 30% in x64 version and by 3% in x86 version.
- 7-Zip now can use multi-threading for 7z/LZMA2 decoding,
if there are multiple independent data chunks in LZMA2 stream.
9.35 beta 2014-12-07
------------------------------
- SFX modules were moved to LZMA SDK package.
9.34 alpha 2014-06-22
------------------------------
- Minimum supported system now is Windows 2000 for EXE and DLL files.
- all EXE and DLL files use msvcrt.dll.
- 7zr.exe now support AES encryption.
9.18 2010-11-02
------------------------------
- New small SFX module for installers.
9.17 2010-10-04
------------------------------
- New 7-Zip plugin for FAR Manager x64.
9.10 2009-12-30
------------------------------
- 7-Zip for installers now supports LZMA2.
9.09 2009-12-12
------------------------------
- LZMA2 compression method support.
- Some bugs were fixed.
4.65 2009-02-03
------------------------------
- Some bugs were fixed.
4.38 beta 2006-04-13
------------------------------
- SFX for installers now supports new properties in config file:
Progress, Directory, ExecuteFile, ExecuteParameters.
4.34 beta 2006-02-27
------------------------------
- ISetProperties::SetProperties:
it's possible to specify desirable number of CPU threads:
PROPVARIANT: name=L"mt", vt = VT_UI4, ulVal = NumberOfThreads
If "mt" is not defined, 7za.dll will check number of processors in system to set
number of desirable threads.
Now 7za.dll can use:
2 threads for LZMA compressing
N threads for BZip2 compressing
4 threads for BZip2 decompressing
Other codecs use only one thread.
Note: 7za.dll can use additional "small" threads with low CPU load.
- It's possible to call ISetProperties::SetProperties to specify "mt" property for decoder.
4.33 beta 2006-02-05
------------------------------
- Compressing speed and Memory requirements were increased.
Default dictionary size was increased: Fastest: 64 KB, Fast: 1 MB,
Normal: 4 MB, Max: 16 MB, Ultra: 64 MB.
- 7z/LZMA now can use only these match finders: HC4, BT2, BT3, BT4
4.27 2005-09-21
------------------------------
- Some GUIDs/interfaces were changed.
IStream.h:
ISequentialInStream::Read now works as old ReadPart
ISequentialOutStream::Write now works as old WritePart

View File

@@ -0,0 +1,124 @@
7-Zip Extra 19.00
-----------------
7-Zip Extra is package of extra modules of 7-Zip.
7-Zip Copyright (C) 1999-2019 Igor Pavlov.
7-Zip is free software. Read License.txt for more information about license.
Source code of binaries can be found at:
http://www.7-zip.org/
This package contains the following files:
7za.exe - standalone console version of 7-Zip with reduced formats support.
7za.dll - library for working with 7z archives
7zxa.dll - library for extracting from 7z archives
License.txt - license information
readme.txt - this file
Far\ - plugin for Far Manager
x64\ - binaries for x64
All 32-bit binaries can work in:
Windows 2000 / 2003 / 2008 / XP / Vista / 7 / 8 / 10
and in any Windows x64 version with WoW64 support.
All x64 binaries can work in any Windows x64 version.
All binaries use msvcrt.dll.
7za.exe
-------
7za.exe - is a standalone console version of 7-Zip with reduced formats support.
Extra: 7za.exe : support for only some formats of 7-Zip.
7-Zip: 7z.exe with 7z.dll : support for all formats of 7-Zip.
7za.exe and 7z.exe from 7-Zip have same command line interface.
7za.exe doesn't use external DLL files.
You can read Help File (7-zip.chm) from 7-Zip package for description
of all commands and switches for 7za.exe and 7z.exe.
7za.exe features:
- High compression ratio in 7z format
- Supported formats:
- Packing / unpacking: 7z, xz, ZIP, GZIP, BZIP2 and TAR
- Unpacking only: Z, lzma, CAB.
- Highest compression ratio for ZIP and GZIP formats.
- Fast compression and decompression
- Strong AES-256 encryption in 7z and ZIP formats.
Note: LZMA SDK contains 7zr.exe - more reduced version of 7za.exe.
But you can use 7zr.exe as "public domain" code.
DLL files
---------
7za.dll and 7zxa.dll are reduced versions of 7z.dll from 7-Zip.
7za.dll and 7zxa.dll support only 7z format.
Note: 7z.dll is main DLL file that works with all archive types in 7-Zip.
7za.dll and 7zxa.dll support the following decoding methods:
- LZMA, LZMA2, PPMD, BCJ, BCJ2, COPY, 7zAES, BZip2, Deflate.
7za.dll also supports 7z encoding with the following encoding methods:
- LZMA, LZMA2, PPMD, BCJ, BCJ2, COPY, 7zAES.
7za.dll and 7zxa.dll work via COM interfaces.
But these DLLs don't use standard COM interfaces for objects creating.
Look also example code that calls DLL functions (in source code of 7-Zip):
7zip\UI\Client7z
Another example of binary that uses these interface is 7-Zip itself.
The following binaries from 7-Zip use 7z.dll:
- 7z.exe (console version)
- 7zG.exe (GUI version)
- 7zFM.exe (7-Zip File Manager)
Note: The source code of LZMA SDK also contains the code for similar DLLs
(DLLs without BZip2, Deflate support). And these files from LZMA SDK can be
used as "public domain" code. If you use LZMA SDK files, you don't need to
follow GNU LGPL rules, if you want to change the code.
License FAQ
-----------
Can I use the EXE or DLL files from 7-Zip in a commercial application?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Yes, but you are required to specify in documentation for your application:
(1) that you used parts of the 7-Zip program,
(2) that 7-Zip is licensed under the GNU LGPL license and
(3) you must give a link to www.7-zip.org, where the source code can be found.
Can I use the source code of 7-Zip in a commercial application?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Since 7-Zip is licensed under the GNU LGPL you must follow the rules of that license.
In brief, it means that any LGPL'ed code must remain licensed under the LGPL.
For instance, you can change the code from 7-Zip or write a wrapper for some
code from 7-Zip and compile it into a DLL; but, the source code of that DLL
(including your modifications / additions / wrapper) must be licensed under
the LGPL or GPL.
Any other code in your application can be licensed as you wish. This scheme allows
users and developers to change LGPL'ed code and recompile that DLL. That is the
idea of free software. Read more here: http://www.gnu.org/.
Note: You can look also LZMA SDK, which is available under a more liberal license.
---
End of document

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,80 @@
# -----------------------------------------------------------------------------
# Copyright (c) 2013-2017, PyInstaller Development Team.
#
# Distributed under the terms of the GNU General Public License with exception
# for distributing bootloader.
#
# The full license is in the file COPYING.txt, distributed with this software.
# -----------------------------------------------------------------------------
"""
Name: PyInstaller patoolib Hook
Original solution: https://github.com/pyinstaller/pyinstaller/issues/3013
PyInstaller cannot find libraries imported by patoolib,
since it uses importlib to import these modules.
"""
hiddenimports = [
"patoolib.programs",
"patoolib.programs.ar",
"patoolib.programs.arc",
"patoolib.programs.archmage",
"patoolib.programs.bsdcpio",
"patoolib.programs.bsdtar",
"patoolib.programs.bzip2",
"patoolib.programs.cabextract",
"patoolib.programs.chmlib",
"patoolib.programs.clzip",
"patoolib.programs.compress",
"patoolib.programs.cpio",
"patoolib.programs.dpkg",
"patoolib.programs.flac",
"patoolib.programs.genisoimage",
"patoolib.programs.gzip",
"patoolib.programs.isoinfo",
"patoolib.programs.lbzip2",
"patoolib.programs.lcab",
"patoolib.programs.lha",
"patoolib.programs.lhasa",
"patoolib.programs.lrzip",
"patoolib.programs.lzip",
"patoolib.programs.lzma",
"patoolib.programs.lzop",
"patoolib.programs.mac",
"patoolib.programs.nomarch",
"patoolib.programs.p7azip",
"patoolib.programs.p7rzip",
"patoolib.programs.p7zip",
"patoolib.programs.pbzip2",
"patoolib.programs.pdlzip",
"patoolib.programs.pigz",
"patoolib.programs.plzip",
"patoolib.programs.py_bz2",
"patoolib.programs.py_echo",
"patoolib.programs.py_gzip",
"patoolib.programs.py_lzma",
"patoolib.programs.py_tarfile",
"patoolib.programs.py_zipfile",
"patoolib.programs.rar",
"patoolib.programs.rpm",
"patoolib.programs.rpm2cpio",
"patoolib.programs.rzip",
"patoolib.programs.shar",
"patoolib.programs.shorten",
"patoolib.programs.star",
"patoolib.programs.tar",
"patoolib.programs.unace",
"patoolib.programs.unadf",
"patoolib.programs.unalz",
"patoolib.programs.uncompress",
"patoolib.programs.unrar",
"patoolib.programs.unshar",
"patoolib.programs.unzip",
"patoolib.programs.xdms",
"patoolib.programs.xz",
"patoolib.programs.zip",
"patoolib.programs.zoo",
"patoolib.programs.zopfli",
"patoolib.programs.zpaq",
]

11
src/requirements.txt Normal file
View File

@@ -0,0 +1,11 @@
avalon_framework
colorama
patool
psutil
pyqt5
python-magic
python-magic-bin
pyunpack
pyyaml
requests
tqdm

610
src/upscaler.py Executable file
View File

@@ -0,0 +1,610 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Name: Video2X Upscaler
Author: K4YT3X
Date Created: December 10, 2018
Last Modified: May 17, 2020
Description: This file contains the Upscaler class. Each
instance of the Upscaler class is an upscaler on an image or
a folder.
"""
# local imports
from exceptions import *
from image_cleaner import ImageCleaner
from progress_monitor import ProgressMonitor
from wrappers.ffmpeg import Ffmpeg
from wrappers.gifski import Gifski
# built-in imports
from fractions import Fraction
import contextlib
import copy
import gettext
import importlib
import locale
import pathlib
import queue
import re
import shutil
import subprocess
import tempfile
import time
import traceback
# third-party imports
from avalon_framework import Avalon
import magic
# internationalization constants
DOMAIN = 'video2x'
LOCALE_DIRECTORY = pathlib.Path(__file__).parent.absolute() / 'locale'
# getting default locale settings
default_locale, encoding = locale.getdefaultlocale()
language = gettext.translation(DOMAIN, LOCALE_DIRECTORY, [default_locale], fallback=True)
language.install()
_ = language.gettext
# version information
UPSCALER_VERSION = '4.1.0'
# these names are consistent for
# - driver selection in command line
# - driver wrapper file names
# - config file keys
AVAILABLE_DRIVERS = ['waifu2x_caffe',
'waifu2x_converter_cpp',
'waifu2x_ncnn_vulkan',
'srmd_ncnn_vulkan',
'anime4kcpp']
class Upscaler:
""" An instance of this class is a upscaler that will
upscale all images in the given directory.
Raises:
Exception -- all exceptions
ArgumentError -- if argument is not valid
"""
def __init__(self, input_path, output_path, driver_settings, ffmpeg_settings, gifski_settings):
# mandatory arguments
self.input = input_path
self.output = output_path
self.driver_settings = driver_settings
self.ffmpeg_settings = ffmpeg_settings
self.gifski_settings = gifski_settings
# optional arguments
self.driver = 'waifu2x_caffe'
self.scale_ratio = None
self.processes = 1
self.video2x_cache_directory = pathlib.Path(tempfile.gettempdir()) / 'video2x'
self.image_format = 'png'
self.preserve_frames = False
# other internal members and signals
self.running = False
self.total_frames_upscaled = 0
self.total_frames = 0
self.total_files = 0
self.total_processed = 0
self.current_input_file = pathlib.Path()
self.last_frame_upscaled = pathlib.Path()
def create_temp_directories(self):
"""create temporary directories
"""
# if cache directory unspecified, use %TEMP%\video2x
if self.video2x_cache_directory is None:
self.video2x_cache_directory = pathlib.Path(tempfile.gettempdir()) / 'video2x'
# if specified cache path exists and isn't a directory
if self.video2x_cache_directory.exists() and not self.video2x_cache_directory.is_dir():
Avalon.error(_('Specified or default cache directory is a file/link'))
raise FileExistsError('Specified or default cache directory is a file/link')
# if cache directory doesn't exist, try creating it
if not self.video2x_cache_directory.exists():
try:
Avalon.debug_info(_('Creating cache directory {}').format(self.video2x_cache_directory))
self.video2x_cache_directory.mkdir(parents=True, exist_ok=True)
except Exception as exception:
Avalon.error(_('Unable to create {}').format(self.video2x_cache_directory))
raise exception
# create temp directories for extracted frames and upscaled frames
self.extracted_frames = pathlib.Path(tempfile.mkdtemp(dir=self.video2x_cache_directory))
Avalon.debug_info(_('Extracted frames are being saved to: {}').format(self.extracted_frames))
self.upscaled_frames = pathlib.Path(tempfile.mkdtemp(dir=self.video2x_cache_directory))
Avalon.debug_info(_('Upscaled frames are being saved to: {}').format(self.upscaled_frames))
def cleanup_temp_directories(self):
"""delete temp directories when done
"""
if not self.preserve_frames:
for directory in [self.extracted_frames, self.upscaled_frames, self.video2x_cache_directory]:
try:
# avalon framework cannot be used if python is shutting down
# therefore, plain print is used
print(_('Cleaning up cache directory: {}').format(directory))
shutil.rmtree(directory)
except FileNotFoundError:
pass
except OSError:
print(_('Unable to delete: {}').format(directory))
traceback.print_exc()
def _check_arguments(self):
if isinstance(self.input, list):
if self.output.exists() and not self.output.is_dir():
Avalon.error(_('Input and output path type mismatch'))
Avalon.error(_('Input is multiple files but output is not directory'))
raise ArgumentError('input output path type mismatch')
for input_path in self.input:
if not input_path.is_file() and not input_path.is_dir():
Avalon.error(_('Input path {} is neither a file nor a directory').format(input_path))
raise FileNotFoundError(f'{input_path} is neither file nor directory')
with contextlib.suppress(FileNotFoundError):
if input_path.samefile(self.output):
Avalon.error(_('Input directory and output directory cannot be the same'))
raise FileExistsError('input directory and output directory are the same')
# if input is a file
elif self.input.is_file():
if self.output.is_dir():
Avalon.error(_('Input and output path type mismatch'))
Avalon.error(_('Input is single file but output is directory'))
raise ArgumentError('input output path type mismatch')
if self.output.suffix == '':
Avalon.error(_('No suffix found in output file path'))
Avalon.error(_('Suffix must be specified'))
raise ArgumentError('no output file suffix specified')
# if input is a directory
elif self.input.is_dir():
if self.output.is_file():
Avalon.error(_('Input and output path type mismatch'))
Avalon.error(_('Input is directory but output is existing single file'))
raise ArgumentError('input output path type mismatch')
with contextlib.suppress(FileNotFoundError):
if self.input.samefile(self.output):
Avalon.error(_('Input directory and output directory cannot be the same'))
raise FileExistsError('input directory and output directory are the same')
# if input is neither
else:
Avalon.error(_('Input path is neither a file nor a directory'))
raise FileNotFoundError(f'{self.input} is neither file nor directory')
# check FFmpeg settings
ffmpeg_path = pathlib.Path(self.ffmpeg_settings['ffmpeg_path'])
if not ((pathlib.Path(ffmpeg_path / 'ffmpeg.exe').is_file() and
pathlib.Path(ffmpeg_path / 'ffprobe.exe').is_file()) or
(pathlib.Path(ffmpeg_path / 'ffmpeg').is_file() and
pathlib.Path(ffmpeg_path / 'ffprobe').is_file())):
Avalon.error(_('FFmpeg or FFprobe cannot be found under the specified path'))
Avalon.error(_('Please check the configuration file settings'))
raise FileNotFoundError(self.ffmpeg_settings['ffmpeg_path'])
# check if driver settings
driver_settings = copy.deepcopy(self.driver_settings)
driver_path = driver_settings.pop('path')
# check if driver path exists
if not (pathlib.Path(driver_path).is_file() or pathlib.Path(f'{driver_path}.exe').is_file()):
Avalon.error(_('Specified driver executable directory doesn\'t exist'))
Avalon.error(_('Please check the configuration file settings'))
raise FileNotFoundError(driver_path)
# parse driver arguments using driver's parser
# the parser will throw AttributeError if argument doesn't satisfy constraints
try:
driver_arguments = []
for key in driver_settings.keys():
value = driver_settings[key]
if value is None or value is False:
continue
else:
if len(key) == 1:
driver_arguments.append(f'-{key}')
else:
driver_arguments.append(f'--{key}')
# true means key is an option
if value is not True:
driver_arguments.append(str(value))
DriverWrapperMain = getattr(importlib.import_module(f'wrappers.{self.driver}'), 'WrapperMain')
DriverWrapperMain.parse_arguments(driver_arguments)
except AttributeError as e:
Avalon.error(_('Failed to parse driver argument: {}').format(e.args[0]))
raise e
# waifu2x-caffe scale_ratio, scale_width and scale_height check
if self.driver == 'waifu2x_caffe':
if (driver_settings['scale_width'] != 0 and driver_settings['scale_height'] == 0 or
driver_settings['scale_width'] == 0 and driver_settings['scale_height'] != 0):
Avalon.error('Only one of scale_width and scale_height is specified for waifu2x-caffe')
raise AttributeError('only one of scale_width and scale_height is specified for waifu2x-caffe')
# if scale_width and scale_height are specified, ensure scale_ratio is None
elif self.driver_settings['scale_width'] != 0 and self.driver_settings['scale_height'] != 0:
self.driver_settings['scale_ratio'] = None
# if scale_width and scale_height not specified
# ensure they are None, not 0
else:
self.driver_settings['scale_width'] = None
self.driver_settings['scale_height'] = None
def _upscale_frames(self):
""" Upscale video frames with waifu2x-caffe
This function upscales all the frames extracted
by ffmpeg using the waifu2x-caffe binary.
Arguments:
w2 {Waifu2x Object} -- initialized waifu2x object
"""
# initialize waifu2x driver
if self.driver not in AVAILABLE_DRIVERS:
raise UnrecognizedDriverError(_('Unrecognized driver: {}').format(self.driver))
# list all images in the extracted frames
frames = [(self.extracted_frames / f) for f in self.extracted_frames.iterdir() if f.is_file]
# if we have less images than processes,
# create only the processes necessary
if len(frames) < self.processes:
self.processes = len(frames)
# create a directory for each process and append directory
# name into a list
process_directories = []
for process_id in range(self.processes):
process_directory = self.extracted_frames / str(process_id)
process_directories.append(process_directory)
# delete old directories and create new directories
if process_directory.is_dir():
shutil.rmtree(process_directory)
process_directory.mkdir(parents=True, exist_ok=True)
# waifu2x-converter-cpp will perform multi-threading within its own process
if self.driver in ['waifu2x_converter_cpp', 'waifu2x_ncnn_vulkan', 'srmd_ncnn_vulkan']:
process_directories = [self.extracted_frames]
else:
# evenly distribute images into each directory
# until there is none left in the directory
for image in frames:
# move image
image.rename(process_directories[0] / image.name)
# rotate list
process_directories = process_directories[-1:] + process_directories[:-1]
# create driver processes and start them
for process_directory in process_directories:
self.process_pool.append(self.driver_object.upscale(process_directory, self.upscaled_frames))
# start progress bar in a different thread
Avalon.debug_info(_('Starting progress monitor'))
self.progress_monitor = ProgressMonitor(self, process_directories)
self.progress_monitor.start()
# create the clearer and start it
Avalon.debug_info(_('Starting upscaled image cleaner'))
self.image_cleaner = ImageCleaner(self.extracted_frames, self.upscaled_frames, len(self.process_pool))
self.image_cleaner.start()
# wait for all process to exit
try:
self._wait()
except (Exception, KeyboardInterrupt, SystemExit) as e:
# cleanup
Avalon.debug_info(_('Killing progress monitor'))
self.progress_monitor.stop()
Avalon.debug_info(_('Killing upscaled image cleaner'))
self.image_cleaner.stop()
raise e
# if the driver is waifu2x-converter-cpp
# images need to be renamed to be recognizable for FFmpeg
if self.driver == 'waifu2x_converter_cpp':
for image in [f for f in self.upscaled_frames.iterdir() if f.is_file()]:
renamed = re.sub(f'_\\[.*\\]\\[x(\\d+(\\.\\d+)?)\\]\\.{self.image_format}',
f'.{self.image_format}',
str(image.name))
(self.upscaled_frames / image).rename(self.upscaled_frames / renamed)
# upscaling done, kill helper threads
Avalon.debug_info(_('Killing progress monitor'))
self.progress_monitor.stop()
Avalon.debug_info(_('Killing upscaled image cleaner'))
self.image_cleaner.stop()
def _terminate_subprocesses(self):
Avalon.warning(_('Terminating all processes'))
for process in self.process_pool:
process.terminate()
def _wait(self):
""" wait for subprocesses in process pool to complete
"""
Avalon.debug_info(_('Main process waiting for subprocesses to exit'))
try:
# while process pool not empty
while self.process_pool:
# if stop signal received, terminate all processes
if self.running is False:
raise SystemExit
for process in self.process_pool:
process_status = process.poll()
# if process finished
if process_status is None:
continue
# if return code is not 0
elif process_status != 0:
Avalon.error(_('Subprocess {} exited with code {}').format(process.pid, process_status))
raise subprocess.CalledProcessError(process_status, process.args)
else:
Avalon.debug_info(_('Subprocess {} exited with code {}').format(process.pid, process_status))
self.process_pool.remove(process)
time.sleep(0.1)
except (KeyboardInterrupt, SystemExit) as e:
Avalon.warning(_('Stop signal received'))
self._terminate_subprocesses()
raise e
except (Exception, subprocess.CalledProcessError) as e:
Avalon.error(_('Subprocess execution ran into an error'))
self._terminate_subprocesses()
raise e
def run(self):
""" Main controller for Video2X
This function controls the flow of video conversion
and handles all necessary functions.
"""
# external stop signal when called in a thread
self.running = True
# define process pool to contain processes
self.process_pool = []
# load driver modules
DriverWrapperMain = getattr(importlib.import_module(f'wrappers.{self.driver}'), 'WrapperMain')
self.driver_object = DriverWrapperMain(self.driver_settings)
# load options from upscaler class into driver settings
self.driver_object.load_configurations(self)
# initialize FFmpeg object
self.ffmpeg_object = Ffmpeg(self.ffmpeg_settings, image_format=self.image_format)
# define processing queue
self.processing_queue = queue.Queue()
# if input is a list of files
if isinstance(self.input, list):
# make output directory if it doesn't exist
self.output.mkdir(parents=True, exist_ok=True)
for input_path in self.input:
if input_path.is_file():
output_path = self.output / input_path.name
self.processing_queue.put((input_path.absolute(), output_path.absolute()))
elif input_path.is_dir():
for input_path in [f for f in input_path.iterdir() if f.is_file()]:
output_path = self.output / input_path.name
self.processing_queue.put((input_path.absolute(), output_path.absolute()))
# if input specified is single file
elif self.input.is_file():
Avalon.info(_('Upscaling single file: {}').format(self.input))
self.processing_queue.put((self.input.absolute(), self.output.absolute()))
# if input specified is a directory
elif self.input.is_dir():
# make output directory if it doesn't exist
self.output.mkdir(parents=True, exist_ok=True)
for input_path in [f for f in self.input.iterdir() if f.is_file()]:
output_path = self.output / input_path.name
self.processing_queue.put((input_path.absolute(), output_path.absolute()))
# check argument sanity before running
self._check_arguments()
# record file count for external calls
self.total_files = self.processing_queue.qsize()
try:
while not self.processing_queue.empty():
# reset current processing progress for new job
self.total_frames_upscaled = 0
self.total_frames = 0
# get new job from queue
self.current_input_file, output_path = self.processing_queue.get()
# get file type
input_file_mime_type = magic.from_file(str(self.current_input_file.absolute()), mime=True)
input_file_type = input_file_mime_type.split('/')[0]
input_file_subtype = input_file_mime_type.split('/')[1]
# start handling input
# if input file is a static image
if input_file_type == 'image' and input_file_subtype != 'gif':
Avalon.info(_('Starting to upscale image'))
self.process_pool.append(self.driver_object.upscale(self.current_input_file, output_path))
self._wait()
Avalon.info(_('Upscaling completed'))
# static images don't require GIF or video encoding
# go to the next task
self.processing_queue.task_done()
self.total_processed += 1
continue
# if input file is a image/gif file or a video
elif input_file_mime_type == 'image/gif' or input_file_type == 'video':
self.create_temp_directories()
# get video information JSON using FFprobe
Avalon.info(_('Reading video information'))
video_info = self.ffmpeg_object.probe_file_info(self.current_input_file)
# analyze original video with FFprobe and retrieve framerate
# width, height = info['streams'][0]['width'], info['streams'][0]['height']
# find index of video stream
video_stream_index = None
for stream in video_info['streams']:
if stream['codec_type'] == 'video':
video_stream_index = stream['index']
break
# exit if no video stream found
if video_stream_index is None:
Avalon.error(_('Aborting: No video stream found'))
raise StreamNotFoundError('no video stream found')
# get average frame rate of video stream
framerate = float(Fraction(video_info['streams'][video_stream_index]['r_frame_rate']))
Avalon.info(_('Framerate: {}').format(framerate))
# self.ffmpeg_object.pixel_format = video_info['streams'][video_stream_index]['pix_fmt']
# extract frames from video
self.process_pool.append((self.ffmpeg_object.extract_frames(self.current_input_file, self.extracted_frames)))
self._wait()
# if driver is waifu2x-caffe
# pass pixel format output depth information
if self.driver == 'waifu2x_caffe':
# get a dict of all pixel formats and corresponding bit depth
pixel_formats = self.ffmpeg_object.get_pixel_formats()
# try getting pixel format's corresponding bti depth
try:
self.driver_settings['output_depth'] = pixel_formats[self.ffmpeg_object.pixel_format]
except KeyError:
Avalon.error(_('Unsupported pixel format: {}').format(self.ffmpeg_object.pixel_format))
raise UnsupportedPixelError(f'unsupported pixel format {self.ffmpeg_object.pixel_format}')
# width/height will be coded width/height x upscale factor
# original_width = video_info['streams'][video_stream_index]['width']
# original_height = video_info['streams'][video_stream_index]['height']
# scale_width = int(self.scale_ratio * original_width)
# scale_height = int(self.scale_ratio * original_height)
# upscale images one by one using waifu2x
Avalon.info(_('Starting to upscale extracted frames'))
self._upscale_frames()
Avalon.info(_('Upscaling completed'))
# if file is none of: image, image/gif, video
# skip to the next task
else:
Avalon.error(_('File {} ({}) neither an image of a video').format(self.current_input_file, input_file_mime_type))
Avalon.warning(_('Skipping this file'))
self.processing_queue.task_done()
self.total_processed += 1
continue
# start handling output
# output can be either GIF or video
# if the desired output is gif file
if output_path.suffix.lower() == '.gif':
Avalon.info(_('Converting extracted frames into GIF image'))
gifski_object = Gifski(self.gifski_settings)
self.process_pool.append(gifski_object.make_gif(self.upscaled_frames, output_path, framerate, self.image_format))
self._wait()
Avalon.info(_('Conversion completed'))
# if the desired output is video
else:
# frames to video
Avalon.info(_('Converting extracted frames into video'))
self.process_pool.append(self.ffmpeg_object.assemble_video(framerate, self.upscaled_frames))
# f'{scale_width}x{scale_height}'
self._wait()
Avalon.info(_('Conversion completed'))
try:
# migrate audio tracks and subtitles
Avalon.info(_('Migrating audio, subtitles and other streams to upscaled video'))
self.process_pool.append(self.ffmpeg_object.migrate_streams(self.current_input_file,
output_path,
self.upscaled_frames))
self._wait()
# if failed to copy streams
# use file with only video stream
except subprocess.CalledProcessError:
traceback.print_exc()
Avalon.error(_('Failed to migrate streams'))
Avalon.warning(_('Trying to output video without additional streams'))
if input_file_mime_type == 'image/gif':
# copy will overwrite destination content if exists
shutil.copy(self.upscaled_frames / self.ffmpeg_object.intermediate_file_name, output_path)
else:
# construct output file path
output_file_name = f'{output_path.stem}{self.ffmpeg_object.intermediate_file_name.suffix}'
output_video_path = output_path.parent / output_file_name
# if output file already exists
# create temporary directory in output folder
# temporary directories generated by tempfile are guaranteed to be unique
# and won't conflict with other files
if output_video_path.exists():
Avalon.error(_('Output video file exists'))
temporary_directory = pathlib.Path(tempfile.mkdtemp(dir=output_path.parent))
output_video_path = temporary_directory / output_file_name
Avalon.info(_('Created temporary directory to contain file'))
# move file to new destination
Avalon.info(_('Writing intermediate file to: {}').format(output_video_path.absolute()))
shutil.move(self.upscaled_frames / self.ffmpeg_object.intermediate_file_name, output_video_path)
# increment total number of files processed
self.cleanup_temp_directories()
self.processing_queue.task_done()
self.total_processed += 1
except (Exception, KeyboardInterrupt, SystemExit) as e:
with contextlib.suppress(ValueError, AttributeError):
self.cleanup_temp_directories()
self.running = False
raise e
# signal upscaling completion
self.running = False

283
src/video2x.pot Normal file
View File

@@ -0,0 +1,283 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2020-05-17 10:10-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=cp1252\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
#: progress_monitor.py:42
msgid "Upscaling Progress"
msgstr ""
#: upscaler.py:109
msgid "Specified or default cache directory is a file/link"
msgstr ""
#: upscaler.py:115
msgid "Creating cache directory {}"
msgstr ""
#: upscaler.py:118
msgid "Unable to create {}"
msgstr ""
#: upscaler.py:123
msgid "Extracted frames are being saved to: {}"
msgstr ""
#: upscaler.py:125
msgid "Upscaled frames are being saved to: {}"
msgstr ""
#: upscaler.py:135
msgid "Cleaning up cache directory: {}"
msgstr ""
#: upscaler.py:138
msgid "Unable to delete: {}"
msgstr ""
#: upscaler.py:144 upscaler.py:159 upscaler.py:170
msgid "Input and output path type mismatch"
msgstr ""
#: upscaler.py:145
msgid "Input is multiple files but output is not directory"
msgstr ""
#: upscaler.py:149
msgid "Input path {} is neither a file nor a directory"
msgstr ""
#: upscaler.py:153 upscaler.py:175
msgid "Input directory and output directory cannot be the same"
msgstr ""
#: upscaler.py:160
msgid "Input is single file but output is directory"
msgstr ""
#: upscaler.py:163
msgid "No suffix found in output file path"
msgstr ""
#: upscaler.py:164
msgid "Suffix must be specified"
msgstr ""
#: upscaler.py:171
msgid "Input is directory but output is existing single file"
msgstr ""
#: upscaler.py:180
msgid "Input path is neither a file nor a directory"
msgstr ""
#: upscaler.py:189
msgid "FFmpeg or FFprobe cannot be found under the specified path"
msgstr ""
#: upscaler.py:190 upscaler.py:200
msgid "Please check the configuration file settings"
msgstr ""
#: upscaler.py:199
msgid "Specified driver executable directory doesn't exist"
msgstr ""
#: upscaler.py:226
msgid "Failed to parse driver argument: {}"
msgstr ""
#: upscaler.py:258
msgid "Unrecognized driver: {}"
msgstr ""
#: upscaler.py:298
msgid "Starting progress monitor"
msgstr ""
#: upscaler.py:303
msgid "Starting upscaled image cleaner"
msgstr ""
#: upscaler.py:312 upscaler.py:329
msgid "Killing progress monitor"
msgstr ""
#: upscaler.py:315 upscaler.py:332
msgid "Killing upscaled image cleaner"
msgstr ""
#: upscaler.py:336
msgid "Terminating all processes"
msgstr ""
#: upscaler.py:343
msgid "Main process waiting for subprocesses to exit"
msgstr ""
#: upscaler.py:362 upscaler.py:366
msgid "Subprocess {} exited with code {}"
msgstr ""
#: upscaler.py:372
msgid "Stop signal received"
msgstr ""
#: upscaler.py:377
msgid "Subprocess execution ran into an error"
msgstr ""
#: upscaler.py:425
msgid "Upscaling single file: {}"
msgstr ""
#: upscaler.py:461
msgid "Starting to upscale image"
msgstr ""
#: upscaler.py:464 upscaler.py:526
msgid "Upscaling completed"
msgstr ""
#: upscaler.py:478
msgid "Reading video information"
msgstr ""
#: upscaler.py:492
msgid "Aborting: No video stream found"
msgstr ""
#: upscaler.py:497
msgid "Framerate: {}"
msgstr ""
#: upscaler.py:514
msgid "Unsupported pixel format: {}"
msgstr ""
#: upscaler.py:524
msgid "Starting to upscale extracted frames"
msgstr ""
#: upscaler.py:531
msgid "File {} ({}) neither an image of a video"
msgstr ""
#: upscaler.py:532
msgid "Skipping this file"
msgstr ""
#: upscaler.py:542
msgid "Converting extracted frames into GIF image"
msgstr ""
#: upscaler.py:546 upscaler.py:555
msgid "Conversion completed"
msgstr ""
#: upscaler.py:551
msgid "Converting extracted frames into video"
msgstr ""
#: upscaler.py:559
msgid "Migrating audio, subtitles and other streams to upscaled video"
msgstr ""
#: upscaler.py:569
msgid "Failed to migrate streams"
msgstr ""
#: upscaler.py:570
msgid "Trying to output video without additional streams"
msgstr ""
#: upscaler.py:586
msgid "Output video file exists"
msgstr ""
#: upscaler.py:590
msgid "Created temporary directory to contain file"
msgstr ""
#: upscaler.py:593
msgid "Writing intermediate file to: {}"
msgstr ""
#: video2x.py:85
msgid ""
"Video2X CLI Version: {}\n"
"Upscaler Version: {}\n"
"Author: K4YT3X\n"
"License: GNU GPL v3\n"
"Github Page: https://github.com/k4yt3x/video2x\n"
"Contact: k4yt3x@k4yt3x.com"
msgstr ""
#: video2x.py:108
msgid "Video2X Options"
msgstr ""
#: video2x.py:109
msgid "show this help message and exit"
msgstr ""
#: video2x.py:110
msgid "source video file/directory"
msgstr ""
#: video2x.py:111
msgid "output video file/directory"
msgstr ""
#: video2x.py:112
msgid "video2x config file path"
msgstr ""
#: video2x.py:114
msgid "display version, lawful information and exit"
msgstr ""
#: video2x.py:117
msgid "Upscaling Options"
msgstr ""
#: video2x.py:118
msgid "upscaling driver"
msgstr ""
#: video2x.py:119
msgid "scaling ratio"
msgstr ""
#: video2x.py:120
msgid "number of processes to use for upscaling"
msgstr ""
#: video2x.py:121
msgid "preserve extracted and upscaled frames"
msgstr ""
#: video2x.py:161
msgid "This file cannot be imported"
msgstr ""
#: video2x.py:236
msgid "Program completed, taking {} seconds"
msgstr ""
#: video2x.py:239
msgid "An exception has occurred"
msgstr ""

240
src/video2x.py Executable file
View File

@@ -0,0 +1,240 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
r"""
__ __ _ _ ___ __ __
\ \ / / (_) | | |__ \ \ \ / /
\ \ / / _ __| | ___ ___ ) | \ V /
\ \/ / | | / _` | / _ \ / _ \ / / > <
\ / | | | (_| | | __/ | (_) | / /_ / . \
\/ |_| \__,_| \___| \___/ |____| /_/ \_\
Name: Video2X Controller
Creator: K4YT3X
Date Created: Feb 24, 2018
Last Modified: May 15, 2020
Editor: BrianPetkovsek
Last Modified: June 17, 2019
Editor: SAT3LL
Last Modified: June 25, 2019
Editor: 28598519a
Last Modified: March 23, 2020
Licensed under the GNU General Public License Version 3 (GNU GPL v3),
available at: https://www.gnu.org/licenses/gpl-3.0.txt
(C) 2018 - 2020 K4YT3X
Video2X is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Video2X is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Description: Video2X is an automation software based on waifu2x image
enlarging engine. It extracts frames from a video, enlarge it by a
number of times without losing any details or quality, keeping lines
smooth and edges sharp.
"""
# local imports
from upscaler import AVAILABLE_DRIVERS
from upscaler import UPSCALER_VERSION
from upscaler import Upscaler
# built-in imports
import argparse
import gettext
import importlib
import locale
import os
import pathlib
import sys
import tempfile
import time
import traceback
import yaml
# third-party imports
from avalon_framework import Avalon
# internationalization constants
DOMAIN = 'video2x'
LOCALE_DIRECTORY = pathlib.Path(__file__).parent.absolute() / 'locale'
# getting default locale settings
default_locale, encoding = locale.getdefaultlocale()
language = gettext.translation(DOMAIN, LOCALE_DIRECTORY, [default_locale], fallback=True)
language.install()
_ = language.gettext
CLI_VERSION = '4.0.0'
LEGAL_INFO = _('''Video2X CLI Version: {}
Upscaler Version: {}
Author: K4YT3X
License: GNU GPL v3
Github Page: https://github.com/k4yt3x/video2x
Contact: k4yt3x@k4yt3x.com''').format(CLI_VERSION, UPSCALER_VERSION)
LOGO = r'''
__ __ _ _ ___ __ __
\ \ / / (_) | | |__ \ \ \ / /
\ \ / / _ __| | ___ ___ ) | \ V /
\ \/ / | | / _` | / _ \ / _ \ / / > <
\ / | | | (_| | | __/ | (_) | / /_ / . \
\/ |_| \__,_| \___| \___/ |____| /_/ \_\
'''
def parse_arguments():
""" parse CLI arguments
"""
parser = argparse.ArgumentParser(prog='video2x', formatter_class=argparse.ArgumentDefaultsHelpFormatter, add_help=False)
# video options
video2x_options = parser.add_argument_group(_('Video2X Options'))
video2x_options.add_argument('-h', '--help', action='help', help=_('show this help message and exit'))
video2x_options.add_argument('-i', '--input', type=pathlib.Path, help=_('source video file/directory'))
video2x_options.add_argument('-o', '--output', type=pathlib.Path, help=_('output video file/directory'))
video2x_options.add_argument('-c', '--config', type=pathlib.Path, help=_('video2x config file path'), action='store',
default=pathlib.Path(__file__).parent.absolute() / 'video2x.yaml')
video2x_options.add_argument('-v', '--version', help=_('display version, lawful information and exit'), action='store_true')
# scaling options
upscaling_options = parser.add_argument_group(_('Upscaling Options'))
upscaling_options.add_argument('-d', '--driver', help=_('upscaling driver'), choices=AVAILABLE_DRIVERS, default='waifu2x_caffe')
upscaling_options.add_argument('-r', '--ratio', help=_('scaling ratio'), action='store', type=float, default=2.0)
upscaling_options.add_argument('-p', '--processes', help=_('number of processes to use for upscaling'), action='store', type=int, default=1)
upscaling_options.add_argument('--preserve_frames', help=_('preserve extracted and upscaled frames'), action='store_true')
# if no driver arguments are specified
if '--' not in sys.argv:
video2x_args = parser.parse_args()
return video2x_args, None
# if driver arguments are specified
else:
video2x_args = parser.parse_args(sys.argv[1:sys.argv.index('--')])
wrapper = getattr(importlib.import_module(f'wrappers.{video2x_args.driver}'), 'WrapperMain')
driver_args = wrapper.parse_arguments(sys.argv[sys.argv.index('--') + 1:])
return video2x_args, driver_args
def print_logo():
"""print video2x logo"""
print(LOGO)
print(f'\n{"Video2X Video Enlarger".rjust(40, " ")}')
print(f'\n{Avalon.FM.BD}{f"Version {CLI_VERSION}".rjust(36, " ")}{Avalon.FM.RST}\n')
def read_config(config_file: pathlib.Path) -> dict:
""" read video2x configurations from config file
Arguments:
config_file {pathlib.Path} -- video2x configuration file pathlib.Path
Returns:
dict -- dictionary of video2x configuration
"""
with open(config_file, 'r') as config:
return yaml.load(config, Loader=yaml.FullLoader)
# /////////////////// Execution /////////////////// #
# this is not a library
if __name__ != '__main__':
Avalon.error(_('This file cannot be imported'))
raise ImportError(f'{__file__} cannot be imported')
# print video2x logo
print_logo()
# parse command line arguments
video2x_args, driver_args = parse_arguments()
# display version and lawful informaition
if video2x_args.version:
print(LEGAL_INFO)
sys.exit(0)
# read configurations from configuration file
config = read_config(video2x_args.config)
# load waifu2x configuration
driver_settings = config[video2x_args.driver]
driver_settings['path'] = os.path.expandvars(driver_settings['path'])
# read FFmpeg configuration
ffmpeg_settings = config['ffmpeg']
ffmpeg_settings['ffmpeg_path'] = os.path.expandvars(ffmpeg_settings['ffmpeg_path'])
# read Gifski configuration
gifski_settings = config['gifski']
gifski_settings['gifski_path'] = os.path.expandvars(gifski_settings['gifski_path'])
# load video2x settings
image_format = config['video2x']['image_format'].lower()
preserve_frames = config['video2x']['preserve_frames']
# if preserve frames specified in command line
# overwrite config file options
if video2x_args.preserve_frames is True:
preserve_frames = True
# if cache directory not specified
# use default path: %TEMP%\video2x
if config['video2x']['video2x_cache_directory'] is None:
video2x_cache_directory = (pathlib.Path(tempfile.gettempdir()) / 'video2x')
else:
video2x_cache_directory = pathlib.Path(config['video2x']['video2x_cache_directory'])
# overwrite driver_settings with driver_args
if driver_args is not None:
driver_args_dict = vars(driver_args)
for key in driver_args_dict:
if driver_args_dict[key] is not None:
driver_settings[key] = driver_args_dict[key]
# start execution
try:
# start timer
begin_time = time.time()
# initialize upscaler object
upscaler = Upscaler(input_path=video2x_args.input,
output_path=video2x_args.output,
driver_settings=driver_settings,
ffmpeg_settings=ffmpeg_settings,
gifski_settings=gifski_settings)
# set upscaler optional options
upscaler.driver = video2x_args.driver
upscaler.scale_ratio = video2x_args.ratio
upscaler.processes = video2x_args.processes
upscaler.video2x_cache_directory = video2x_cache_directory
upscaler.image_format = image_format
upscaler.preserve_frames = preserve_frames
# run upscaler
upscaler.run()
Avalon.info(_('Program completed, taking {} seconds').format(round((time.time() - begin_time), 5)))
except Exception:
Avalon.error(_('An exception has occurred'))
traceback.print_exc()

160
src/video2x.yaml Normal file
View File

@@ -0,0 +1,160 @@
# Name: Video2X Configuration File
# Creator: K4YT3X
# Date Created: October 23, 2018
# Last Modified: May 17, 2020
# Values here are the default values. Change the value here to
# save the default value permanently.
# Items commented out are parameters irrelevant to this context
# or parameters handled by Video2X internally.
waifu2x_caffe:
path: '%LOCALAPPDATA%\video2x\waifu2x-caffe\waifu2x-caffe-cui'
tta: 0 # <0|1> 8x slower and slightly high quality
gpu: 0 # gpu device no
batch_size: 1 # input batch size
crop_h: null # input image split size(height)
crop_w: null # input image split size(width)
crop_size: 128 # input image split size
output_depth: 8 # output image chanel depth bit
output_quality: -1 # output image quality
process: gpu # <cpu|gpu|cudnn> process mode
model_dir: null # path to custom model directory (don't append last / )
scale_height: 0 # custom scale height (specifying this will overwrite scale_ratio)
scale_width: 0 # custom scale width (specifying this will overwrite scale_ratio)
#scale_ratio: null # custom scale ratio
noise_level: 3 # <0|1|2|3> noise reduction level
mode: noise_scale # <noise|scale|noise_scale|auto_scale> image processing mode
output_extention: null # extension to output image file when output_path is (auto) or input_path is folder
input_extention_list: null # extension to input image file when input_path is folder
#output_path: null # path to output image file (when input_path is folder, output_path must be folder)
#input_path: null # (required) path to input image file
waifu2x_converter_cpp:
path: '%LOCALAPPDATA%\video2x\waifu2x-converter-cpp\waifu2x-converter-cpp'
#list-supported-formats: null # dump currently supported format list
#list-opencv-formats: null # (deprecated. Use --list-supported-formats) dump opencv supported format list
#list-processor # dump processor list
output-format: null # The format used when running in recursive/folder mode
png-compression: 5 # Set PNG compression level (0-9), 9 = Max compression (slowest & smallest)
image-quality: -1 # JPEG & WebP Compression quality (-1-101, 0 being smallest size and lowest quality, -1 being default), use 101 for lossless WebP
block-size: 0 # block size
disable-gpu: false # disable GPU
force-OpenCL: false # force to use OpenCL on Intel Platform
processor: -1 # set target processor (-1 uses default device)
jobs: 0 # number of threads launching at the same time
model-dir: null # path to custom model directory (don't append last / ) default: models_rgb
#scale-ratio: 2.0 # custom scale ratio
noise-level: 1 # <0|1|2|3> noise reduction level
mode: noise-scale # <noise|scale|noise-scale> image processing mode
log-level: 1 # <0|1|2|3|4> Set log level
silent: true # Enable silent mode. (same as --log-level 1)
tta: 0 # Enable Test-Time Augmentation mode. (0 or 1)
#generate-subdir: 0 # Generate sub folder when recursive directory is enabled.
#auto-naming: 0 # Add postfix to output name when output path is not specified.
#recursive-directory: 0 # Search recursively through directories to find more images to process.
#output: null # path to output image file or directory (you should use the full path)
#input: null # (required) path to input image file or directory (you should use the full path)
waifu2x_ncnn_vulkan:
path: '%LOCALAPPDATA%\video2x\waifu2x-ncnn-vulkan\waifu2x-ncnn-vulkan'
v: null # verbose output
#i: null # input-path: input image path (jpg/png) or directory
#o: null # output-path: output image path (png) or directory
'n': 2 # noise-level: denoise level (-1/0/1/2/3, default=0)
s: 2 # scale: upscale ratio (1/2, default=2)
t: 400 # tile-size: tile size (>=32, default=400)
m: null # model-path: waifu2x model path (default=models-cunet)
g: 0 # gpu-id: gpu device to use (default=0)
j: '1:2:2' # thread count for load/proc/save (default=1:2:2)
x: false # enable tta mode
srmd_ncnn_vulkan:
path: '%LOCALAPPDATA%\video2x\srmd-ncnn-vulkan\srmd-ncnn-vulkan'
v: null # verbose output
#i: null # input-path: input image path (jpg/png) or directory
#o: null # output-path: output image path (png) or directory
'n': 3 # noise-level: denoise level (-1/0/1/2/3/4/5/6/7/8/9/10, default=3)
s: 2 # upscale ratio (2/3/4, default=2)
t: 400 # tile-size: tile size (>=32, default=400)
m: null # srmd model path (default=models-srmd)
g: 0 # gpu device to use (default=0)
j: '1:2:2' # thread count for load/proc/save (default=1:2:2)
x: false # enable tta mode
anime4kcpp:
path: '%LOCALAPPDATA%\video2x\anime4kcpp\CLI\Anime4KCPP_CLI\Anime4KCPP_CLI'
#input: null # File for loading (string [=./pic/p1.png])
#output: null # File for outputting (string [=output.png])
passes: 2 # Passes for processing (int [=2])
pushColorCount: 2 # Limit the number of color pushes (int [=2])
strengthColor: 0.3 # Strength for pushing color,range 0 to 1,higher for thinner (double [=0.3])
strengthGradient: 1.0 # Strength for pushing gradient,range 0 to 1,higher for sharper (double [=1])
zoomFactor: 2.0 # zoom factor for resizing (double [=2])
threads: 16 # Threads count for video processing (unsigned int [=16])
fastMode: false # Faster but maybe low quality
videoMode: false # Video process
preview: null # Preview image
preprocessing: False # Enable pre processing
postprocessing: False # Enable post processing
preFilters: 4 # Enhancement filter, only working when preProcessing is true,there are 5 options by binary:Median blur=0000001, Mean blur=0000010, CAS Sharpening=0000100, Gaussian blur weak=0001000, Gaussian blur=0010000, Bilateral filter=0100000, Bilateral filter faster=1000000, you can freely combine them, eg: Gaussian blur weak + Bilateral filter = 0001000 | 0100000 = 0101000 = 40(D) (unsigned int [=4])
postFilters: 40 # Enhancement filter, only working when postProcessing is true,there are 5 options by binary:Median blur=0000001, Mean blur=0000010, CAS Sharpening=0000100, Gaussian blur weak=0001000, Gaussian blur=0010000, Bilateral filter=0100000, Bilateral filter faster=1000000, you can freely combine them, eg: Gaussian blur weak + Bilateral filter = 0001000 | 0100000 = 0101000 = 40(D), so you can put 40 to enable Gaussian blur weak and Bilateral filter, which also is what I recommend for image that < 1080P, 48 for image that >= 1080P, and for performance I recommend to use 72 for video that < 1080P, 80 for video that >=1080P (unsigned int [=40])
GPUMode: False # Enable GPU acceleration
listGPUs: null # list GPUs
platformID: 0 # Specify the platform ID (unsigned int [=0])
deviceID: 0 # Specify the device ID (unsigned int [=0])
codec: mp4v # Specify the codec for encoding from mp4v(recommended in Windows), dxva(for Windows), avc1(H264, recommended in Linux), vp09(very slow), hevc(not support in Windowds), av01(not support in Windowds) (string [=mp4v])
ffmpeg:
ffmpeg_path: '%LOCALAPPDATA%\video2x\ffmpeg-latest-win64-static\bin'
intermediate_file_name: 'intermediate.mkv'
# Step 1: Frame Extraction
# extract all frames from original input into temporary directory
extract_frames:
'-hwaccel': auto # automatically select hardware acceleration method
'-y': true
input_options: {} # empty dict, expand if necessary
output_options:
'-pix_fmt': rgba64be # extracted frames pixel format
'-qscale:v': null # output image quality control for JPEG (1-31, 1 being highest)
# Step 2: Video Assembly
# assemble all frames back into a video with only a video track
assemble_video:
'-hwaccel': auto # automatically select hardware acceleration method
'-y': true
input_options:
'-f': image2 # force image2 format
output_options:
'-vcodec': libx264 # video codec
'-pix_fmt': 'yuv420p' # overwrite default pixel format
'-crf': 17 # H.264 Constant Rate Factor
'-b:v': null # target average bitrate
'-vf': 'pad=ceil(iw/2)*2:ceil(ih/2)*2' # ensure output is divisible by 2, recommended for libx264
# Step 3: Streams Migration
# migrate audio and subtitle streams from original
# video into the upscaled video
migrate_streams:
'-hwaccel': auto # automatically select hardware acceleration method
'-y': true
input_options: {} # empty dict, expand if necessary
output_options:
'-map':
- '0:v?' # copy video streams
- '1:a?' # copy audio streams
- '1:s?' # copy subtitle streams
- '1:d?' # copy data streams
- '1:t?' # copy fonts
'-c': copy # copy codec for all streams
# '-vf': 'minterpolate=''fps=60''' # minterpolate frame interpolation
'-map_metadata': 0 # copy known metadata tags
# '-movflags': 'use_metadata_tags' # copy custom/arbitrary metadata tags
'-pix_fmt': null
'-metadata': 'comment=Upscaled by Video2X'
gifski:
gifski_path: '%LOCALAPPDATA%\video2x\gifski\win\gifski'
# output: null # Destination file to write to
# fps: 20 # Animation frames per second (for PNG frames only) [default: 20]
fast: false # 3 times faster encoding, but 10% lower quality and bigger file
quality: 100 # Lower quality may give smaller file
width: null # Maximum width
height: null # Maximum height (if width is also set)
once: false # Do not loop the GIF
nosort: false # Use files exactly in the order given, rather than sorted
quiet: false # Do not show a progress bar
video2x:
video2x_cache_directory: null # default: %TEMP%\video2x
image_format: png
preserve_frames: false

1175
src/video2x_gui.py Executable file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
{
"files": ["video2x_gui.ui","video2x_gui.py"]
}

View File

@@ -0,0 +1,190 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.12.0, 2020-05-17T16:15:14. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
<value type="QByteArray">{25c1e4a4-6b4a-4828-883b-6f32c3f7eba0}</value>
</data>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
<value type="int">0</value>
</data>
<data>
<variable>ProjectExplorer.Project.EditorSettings</variable>
<valuemap type="QVariantMap">
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
<value type="QString" key="language">Cpp</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
</valuemap>
</valuemap>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
<value type="QString" key="language">QmlJS</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
</valuemap>
</valuemap>
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
<value type="int" key="EditorConfiguration.IndentSize">4</value>
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
<value type="int" key="EditorConfiguration.TabSize">8</value>
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.PluginSettings</variable>
<valuemap type="QVariantMap">
<valuelist type="QVariantList" key="ClangCodeModel.CustomCommandLineKey">
<value type="QString">-fno-delayed-template-parsing</value>
</valuelist>
<value type="bool" key="ClangCodeModel.UseGlobalConfig">true</value>
<value type="QString" key="ClangCodeModel.WarningConfigId">Builtin.Questionable</value>
<valuemap type="QVariantMap" key="ClangTools">
<value type="bool" key="ClangTools.BuildBeforeAnalysis">true</value>
<value type="QString" key="ClangTools.DiagnosticConfig">Builtin.DefaultTidyAndClazy</value>
<value type="int" key="ClangTools.ParallelJobs">8</value>
<valuelist type="QVariantList" key="ClangTools.SelectedDirs"/>
<valuelist type="QVariantList" key="ClangTools.SelectedFiles"/>
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
<value type="bool" key="ClangTools.UseGlobalSettings">true</value>
</valuemap>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.Target.0</variable>
<valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop (x86-windows-msvc2019-pe-64bit)</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop (x86-windows-msvc2019-pe-64bit)</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{5450e32e-f498-4c15-a0a5-7456f3375388}</value>
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">-1</value>
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
<value type="QString" key="Analyzer.Perf.CallgraphMode">dwarf</value>
<valuelist type="QVariantList" key="Analyzer.Perf.Events">
<value type="QString">cpu-cycles</value>
</valuelist>
<valuelist type="QVariantList" key="Analyzer.Perf.ExtraArguments"/>
<value type="int" key="Analyzer.Perf.Frequency">250</value>
<valuelist type="QVariantList" key="Analyzer.Perf.RecordArguments">
<value type="QString">-e</value>
<value type="QString">cpu-cycles</value>
<value type="QString">--call-graph</value>
<value type="QString">dwarf,4096</value>
<value type="QString">-F</value>
<value type="QString">250</value>
</valuelist>
<value type="QString" key="Analyzer.Perf.SampleMode">-F</value>
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
<value type="int" key="Analyzer.Perf.StackSize">4096</value>
<value type="bool" key="Analyzer.QmlProfiler.AggregateTraces">false</value>
<value type="bool" key="Analyzer.QmlProfiler.FlushEnabled">false</value>
<value type="uint" key="Analyzer.QmlProfiler.FlushInterval">1000</value>
<value type="QString" key="Analyzer.QmlProfiler.LastTraceFile"></value>
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
<value type="QString" key="Analyzer.Valgrind.KCachegrindExecutable">kcachegrind</value>
<value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
<value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
<value type="int">0</value>
<value type="int">1</value>
<value type="int">2</value>
<value type="int">3</value>
<value type="int">4</value>
<value type="int">5</value>
<value type="int">6</value>
<value type="int">7</value>
<value type="int">8</value>
<value type="int">9</value>
<value type="int">10</value>
<value type="int">11</value>
<value type="int">12</value>
<value type="int">13</value>
<value type="int">14</value>
</valuelist>
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">video2x_gui</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">PythonEditor.RunConfiguration.C:/Users/k4yt3x/Documents/Projects/video2x/src/video2x_gui.py</value>
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">C:/Users/k4yt3x/Documents/Projects/video2x/src/video2x_gui.py</value>
<value type="bool" key="PythonEditor.RunConfiguation.Buffered">false</value>
<value type="QString" key="PythonEditor.RunConfiguation.Interpreter">{ffc39ed5-fbe0-4af8-8b16-9a60c393bdb8}</value>
<value type="QString" key="PythonEditor.RunConfiguation.Script">C:\Users\k4yt3x\Documents\Projects\video2x\src\video2x_gui.py</value>
<value type="QString" key="RunConfiguration.Arguments"></value>
<value type="bool" key="RunConfiguration.Arguments.multi">false</value>
<value type="QString" key="RunConfiguration.OverrideDebuggerStartup"></value>
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
<value type="QString" key="RunConfiguration.WorkingDirectory"></value>
<value type="QString" key="RunConfiguration.WorkingDirectory.default"></value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.TargetCount</variable>
<value type="int">1</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
<value type="int">22</value>
</data>
<data>
<variable>Version</variable>
<value type="int">22</value>
</data>
</qtcreator>

2618
src/video2x_gui.ui Normal file

File diff suppressed because it is too large Load Diff

417
src/video2x_setup.py Executable file
View File

@@ -0,0 +1,417 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Name: Video2X Setup Script
Creator: K4YT3X
Date Created: November 28, 2018
Last Modified: May 16, 2020
Editor: BrianPetkovsek
Editor: SAT3LL
Description: This script helps installing all dependencies of video2x
and generates a configuration for it.
Installation Details:
- ffmpeg: %LOCALAPPDATA%\\video2x\\ffmpeg
- waifu2x-caffe: %LOCALAPPDATA%\\video2x\\waifu2x-caffe
- waifu2x-cpp-converter: %LOCALAPPDATA%\\video2x\\waifu2x-converter-cpp
- waifu2x_ncnn_vulkan: %LOCALAPPDATA%\\video2x\\waifu2x-ncnn-vulkan
- anime4kcpp: %LOCALAPPDATA%\\video2x\\anime4kcpp
- srmd_ncnn_vulkan: %LOCALAPPDATA%\\video2x\\srmd-ncnn-vulkan
"""
# built-in imports
from datetime import timedelta
import argparse
import contextlib
import os
import pathlib
import platform
import re
import shutil
import subprocess
import sys
import tarfile
import tempfile
import time
import traceback
import urllib
import zipfile
# Some libraries don't come with default Python installation.
# Therefore, they will be installed during the Python dependency
# installation step and imported later in the script.
SETUP_VERSION = '2.1.0'
# global static variables
LOCALAPPDATA = pathlib.Path(os.getenv('localappdata'))
VIDEO2X_CONFIG = pathlib.Path(__file__).parent.absolute() / 'video2x.yaml'
DRIVER_OPTIONS = ['all',
'ffmpeg',
'gifski',
'waifu2x_caffe',
'waifu2x_converter_cpp',
'waifu2x_ncnn_vulkan',
'anime4kcpp',
'srmd_ncnn_vulkan']
def parse_arguments():
""" parse command line arguments
"""
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('-d', '--driver', help='driver to download and configure', choices=DRIVER_OPTIONS, default='all')
parser.add_argument('-u', '--uninstall', help='uninstall Video2X dependencies from default location', action='store_true')
# parse arguments
return parser.parse_args()
class Video2xSetup:
""" install dependencies for video2x video enlarger
This library is meant to be executed as a stand-alone
script. All files will be installed under %LOCALAPPDATA%\\video2x.
"""
def __init__(self, driver, download_python_modules):
self.driver = driver
self.download_python_modules = download_python_modules
self.trash = []
def run(self):
# regardless of which driver to install
# always ensure Python modules are installed and up-to-date
if self.download_python_modules:
print('\nInstalling Python libraries')
self._install_python_requirements()
# if all drivers are to be installed
if self.driver == 'all':
DRIVER_OPTIONS.remove('all')
for driver in DRIVER_OPTIONS:
getattr(self, f'_install_{driver}')()
# install only the selected driver
else:
getattr(self, f'_install_{self.driver}')()
print('\nCleaning up temporary files')
self._cleanup()
def _install_python_requirements(self):
""" Read requirements.txt and return its content
"""
pip_install('requirements.txt')
def _cleanup(self):
""" Cleanup all the temp files downloaded
"""
for file in self.trash:
try:
if file.is_dir():
print(f'Deleting directory: {file}')
shutil.rmtree(file)
else:
print(f'Deleting file: {file}')
file.unlink()
except Exception:
print(f'Error deleting: {file}')
traceback.print_exc()
def _install_ffmpeg(self):
""" Install FFMPEG
"""
print('\nInstalling FFmpeg')
latest_release = 'https://ffmpeg.zeranoe.com/builds/win64/static/ffmpeg-latest-win64-static.zip'
ffmpeg_zip = download(latest_release, tempfile.gettempdir())
self.trash.append(ffmpeg_zip)
with zipfile.ZipFile(ffmpeg_zip) as zipf:
zipf.extractall(LOCALAPPDATA / 'video2x')
def _install_gifski(self):
print('\nInstalling Gifski')
import requests
# Get latest release of waifu2x-ncnn-vulkan via Github API
latest_release = requests.get('https://api.github.com/repos/ImageOptim/gifski/releases/latest').json()
for a in latest_release['assets']:
if re.search(r'gifski-.*\.tar\.xz', a['browser_download_url']):
gifski_tar_gz = download(a['browser_download_url'], tempfile.gettempdir())
self.trash.append(gifski_tar_gz)
# extract and rename
with tarfile.open(gifski_tar_gz) as archive:
archive.extractall(LOCALAPPDATA / 'video2x' / 'gifski')
def _install_waifu2x_caffe(self):
""" Install waifu2x_caffe
"""
print('\nInstalling waifu2x-caffe')
import requests
# Get latest release of waifu2x-caffe via GitHub API
latest_release = requests.get('https://api.github.com/repos/lltcggie/waifu2x-caffe/releases/latest').json()
for a in latest_release['assets']:
if 'waifu2x-caffe.zip' in a['browser_download_url']:
waifu2x_caffe_zip = download(a['browser_download_url'], tempfile.gettempdir())
self.trash.append(waifu2x_caffe_zip)
with zipfile.ZipFile(waifu2x_caffe_zip) as zipf:
zipf.extractall(LOCALAPPDATA / 'video2x')
def _install_waifu2x_converter_cpp(self):
""" Install waifu2x_caffe
"""
print('\nInstalling waifu2x-converter-cpp')
import requests
# Get latest release of waifu2x-caffe via GitHub API
latest_release = requests.get('https://api.github.com/repos/DeadSix27/waifu2x-converter-cpp/releases/latest').json()
for a in latest_release['assets']:
if re.search(r'waifu2x-DeadSix27-win64_v[0-9]*\.zip', a['browser_download_url']):
waifu2x_converter_cpp_zip = download(a['browser_download_url'], tempfile.gettempdir())
self.trash.append(waifu2x_converter_cpp_zip)
with zipfile.ZipFile(waifu2x_converter_cpp_zip) as zipf:
zipf.extractall(LOCALAPPDATA / 'video2x' / 'waifu2x-converter-cpp')
def _install_waifu2x_ncnn_vulkan(self):
""" Install waifu2x-ncnn-vulkan
"""
print('\nInstalling waifu2x-ncnn-vulkan')
import requests
# Get latest release of waifu2x-ncnn-vulkan via Github API
latest_release = requests.get('https://api.github.com/repos/nihui/waifu2x-ncnn-vulkan/releases/latest').json()
for a in latest_release['assets']:
if re.search(r'waifu2x-ncnn-vulkan-\d*\.zip', a['browser_download_url']):
waifu2x_ncnn_vulkan_zip = download(a['browser_download_url'], tempfile.gettempdir())
self.trash.append(waifu2x_ncnn_vulkan_zip)
# extract and rename
waifu2x_ncnn_vulkan_directory = LOCALAPPDATA / 'video2x' / 'waifu2x-ncnn-vulkan'
with zipfile.ZipFile(waifu2x_ncnn_vulkan_zip) as zipf:
zipf.extractall(LOCALAPPDATA / 'video2x')
# if directory already exists, remove it
if waifu2x_ncnn_vulkan_directory.exists():
shutil.rmtree(waifu2x_ncnn_vulkan_directory)
# rename the newly extracted directory
(LOCALAPPDATA / 'video2x' / zipf.namelist()[0]).rename(waifu2x_ncnn_vulkan_directory)
def _install_anime4kcpp(self):
""" Install Anime4KCPP
"""
print('\nInstalling Anime4KCPP')
import patoolib
import requests
# get latest release of Anime4KCPP via Github API
# at the time of writing this portion, Anime4KCPP doesn't yet have a stable release
# therefore releases/latest won't work
latest_release = requests.get('https://api.github.com/repos/TianZerL/Anime4KCPP/releases/latest').json()
for a in latest_release['assets']:
if re.search(r'Anime4KCPP_CLI-.*-Win64-msvc\.7z', a['browser_download_url']):
anime4kcpp_7z = download(a['browser_download_url'], tempfile.gettempdir())
self.trash.append(anime4kcpp_7z)
# if running in PyInstaller, add sys._MEIPASS\7z to path
# this directory contains 7za.exe and its DLL files
with contextlib.suppress(AttributeError):
os.environ['PATH'] += f';{sys._MEIPASS}\\7z'
# (LOCALAPPDATA / 'video2x' / 'anime4kcpp').mkdir(parents=True, exist_ok=True)
# pyunpack.Archive(anime4kcpp_7z).extractall(LOCALAPPDATA / 'video2x' / 'anime4kcpp')
if (LOCALAPPDATA / 'video2x' / 'anime4kcpp').exists():
shutil.rmtree(LOCALAPPDATA / 'video2x' / 'anime4kcpp')
patoolib.extract_archive(str(anime4kcpp_7z), outdir=str(LOCALAPPDATA / 'video2x' / 'anime4kcpp'))
def _install_srmd_ncnn_vulkan(self):
""" Install srmd-ncnn-vulkan
"""
print('\nInstalling srmd-ncnn-vulkan')
import requests
# Get latest release of srmd-ncnn-vulkan via Github API
latest_release = requests.get('https://api.github.com/repos/nihui/srmd-ncnn-vulkan/releases/latest').json()
for a in latest_release['assets']:
if re.search(r'srmd-ncnn-vulkan-\d*\.zip', a['browser_download_url']):
srmd_ncnn_vulkan_zip = download(a['browser_download_url'], tempfile.gettempdir())
self.trash.append(srmd_ncnn_vulkan_zip)
# extract and rename
srmd_ncnn_vulkan_directory = LOCALAPPDATA / 'video2x' / 'srmd-ncnn-vulkan'
with zipfile.ZipFile(srmd_ncnn_vulkan_zip) as zipf:
zipf.extractall(LOCALAPPDATA / 'video2x')
# if directory already exists, remove it
if srmd_ncnn_vulkan_directory.exists():
shutil.rmtree(srmd_ncnn_vulkan_directory)
# rename the newly extracted directory
(LOCALAPPDATA / 'video2x' / zipf.namelist()[0]).rename(srmd_ncnn_vulkan_directory)
def download(url, save_path, chunk_size=4096):
""" Download file to local with requests library
"""
from tqdm import tqdm
import requests
save_path = pathlib.Path(save_path)
# create target folder if it doesn't exist
save_path.mkdir(parents=True, exist_ok=True)
# create requests stream for steaming file
stream = requests.get(url, stream=True, allow_redirects=True)
# get file name
file_name = None
if 'content-disposition' in stream.headers:
disposition = stream.headers['content-disposition']
with contextlib.suppress(IndexError):
file_name = re.findall("filename=(.+)", disposition)[0].strip('"')
if file_name is None:
# output_file = f'{save_path}\\{stream.url.split("/")[-1]}'
output_file = save_path / stream.url.split('/')[-1]
else:
output_file = save_path / file_name
# decode url encoding
output_file = pathlib.Path(urllib.parse.unquote(str(output_file)))
# get total size for progress bar if provided in headers
total_size = 0
if 'content-length' in stream.headers:
total_size = int(stream.headers['content-length'])
# print download information summary
print(f'Downloading: {url}')
print(f'Total size: {total_size}')
print(f'Chunk size: {chunk_size}')
print(f'Saving to: {output_file}')
# Write content into file
with open(output_file, 'wb') as output:
with tqdm(total=total_size, ascii=True) as progress_bar:
for chunk in stream.iter_content(chunk_size=chunk_size):
if chunk:
output.write(chunk)
progress_bar.update(len(chunk))
# return the full path of saved file
return output_file
def pip_install(file):
""" Install python package via python pip module
pip.main() is not available after pip 9.0.1, thus
pip module is not used in this case.
"""
return subprocess.run([sys.executable, '-m', 'pip', 'install', '-U', '-r', file]).returncode
if __name__ != '__main__':
raise ImportError('video2x_setup cannot be imported')
try:
# set default exit code
EXIT_CODE = 0
# get start time
start_time = time.time()
# check platform
if platform.system() != 'Windows':
print('This script is currently only compatible with Windows')
EXIT_CODE = 1
sys.exit(1)
# parse command line arguments
args = parse_arguments()
print('Video2X Setup Script')
print(f'Version: {SETUP_VERSION}')
# uninstall video2x dependencies
if args.uninstall:
if input('Are you sure you want to uninstall all Video2X dependencies? [y/N]: ').lower() == 'y':
try:
print(f'Removing: {LOCALAPPDATA / "video2x"}')
shutil.rmtree(LOCALAPPDATA / 'video2x')
print('Successfully uninstalled all dependencies')
except FileNotFoundError:
print(f'Dependency folder does not exist: {LOCALAPPDATA / "video2x"}')
else:
print('Uninstallation aborted')
# run installation
else:
# do not install pip modules if script
# is packaged in exe format
download_python_modules = True
if sys.argv[0].endswith('.exe'):
print('\nScript is packaged as exe, skipping pip module download')
download_python_modules = False
# create setup install instance and run installer
setup = Video2xSetup(args.driver, download_python_modules)
setup.run()
print('\nScript finished successfully')
# let SystemExit signals pass through
except SystemExit as e:
raise e
# if PermissionError is raised
# user needs to run this with higher privilege
except PermissionError:
traceback.print_exc()
print('You might have insufficient privilege for this script to run')
print('Try running this script with Administrator privileges')
EXIT_CODE = 1
# for any exception in the script
except Exception:
traceback.print_exc()
print('An error has occurred')
print('Video2X Automatic Setup has failed')
# in case of a failure, try cleaning up temp files
try:
setup._cleanup()
except Exception:
traceback.print_exc()
print('An error occurred while trying to cleanup files')
EXIT_CODE = 1
# regardless if script finishes successfully or not
# print script execution summary
finally:
print('Script finished')
print(f'Time taken: {timedelta(seconds=round(time.time() - start_time))}')
# if the program is launched as an Windows PE file
# it might be launched from double clicking
# pause the window before it closes automatically
if sys.argv[0].endswith('.exe'):
input('Press [ENTER] to exit script')
sys.exit(EXIT_CODE)

120
src/wrappers/anime4kcpp.py Normal file
View File

@@ -0,0 +1,120 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Name: Waifu2x Caffe Driver
Author: K4YT3X
Date Created: May 3, 2020
Last Modified: May 11, 2020
Description: This class is a high-level wrapper
for waifu2x-caffe.
"""
# built-in imports
import argparse
import os
import pathlib
import platform
import shlex
import subprocess
import threading
# third-party imports
from avalon_framework import Avalon
class WrapperMain:
""" Anime4K CPP wrapper
"""
def __init__(self, driver_settings):
self.driver_settings = driver_settings
self.print_lock = threading.Lock()
@staticmethod
def zero_to_one_float(value):
value = float(value)
if value < 0.0 or value > 1.0:
raise argparse.ArgumentTypeError(f'{value} is not between 0.0 and 1.0')
return value
@staticmethod
def parse_arguments(arguments):
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter, add_help=False)
parser.error = lambda message: (_ for _ in ()).throw(AttributeError(message))
parser.add_argument('--help', action='help', help='show this help message and exit')
parser.add_argument('-i', '--input', type=str, help=argparse.SUPPRESS) # help='File for loading')
parser.add_argument('-o', '--output', type=str, help=argparse.SUPPRESS) # help='File for outputting')
parser.add_argument('-p', '--passes', type=int, help='Passes for processing')
parser.add_argument('-n', '--pushColorCount', type=int, help='Limit the number of color pushes')
parser.add_argument('-c', '--strengthColor', type=WrapperMain.zero_to_one_float, help='Strength for pushing color,range 0 to 1,higher for thinner')
parser.add_argument('-g', '--strengthGradient', type=WrapperMain.zero_to_one_float, help='Strength for pushing gradient,range 0 to 1,higher for sharper')
parser.add_argument('-z', '--zoomFactor', type=float, help='zoom factor for resizing')
parser.add_argument('-t', '--threads', type=int, help='Threads count for video processing')
parser.add_argument('-f', '--fastMode', action='store_true', help='Faster but maybe low quality')
parser.add_argument('-v', '--videoMode', action='store_true', help='Video process')
parser.add_argument('-s', '--preview', action='store_true', help='Preview image')
parser.add_argument('-b', '--preprocessing', action='store_true', help='Enable pre processing')
parser.add_argument('-a', '--postprocessing', action='store_true', help='Enable post processing')
parser.add_argument('-r', '--preFilters', type=int, help='Enhancement filter, only working when preProcessing is true,there are 5 options by binary:Median blur=0000001, Mean blur=0000010, CAS Sharpening=0000100, Gaussian blur weak=0001000, Gaussian blur=0010000, Bilateral filter=0100000, Bilateral filter faster=1000000, you can freely combine them, eg: Gaussian blur weak + Bilateral filter = 0001000 | 0100000 = 0101000 = 40(D)')
parser.add_argument('-e', '--postFilters', type=int, help='Enhancement filter, only working when postProcessing is true,there are 5 options by binary:Median blur=0000001, Mean blur=0000010, CAS Sharpening=0000100, Gaussian blur weak=0001000, Gaussian blur=0010000, Bilateral filter=0100000, Bilateral filter faster=1000000, you can freely combine them, eg: Gaussian blur weak + Bilateral filter = 0001000 | 0100000 = 0101000 = 40(D), so you can put 40 to enable Gaussian blur weak and Bilateral filter, which also is what I recommend for image that < 1080P, 48 for image that >= 1080P, and for performance I recommend to use 72 for video that < 1080P, 80 for video that >=1080P')
parser.add_argument('-q', '--GPUMode', action='store_true', help='Enable GPU acceleration')
parser.add_argument('-l', '--listGPUs', action='store_true', help='list GPUs')
parser.add_argument('-h', '--platformID', type=int, help='Specify the platform ID')
parser.add_argument('-d', '--deviceID', type=int, help='Specify the device ID')
parser.add_argument('-C', '--codec', type=str, help='Specify the codec for encoding from mp4v(recommended in Windows), dxva(for Windows), avc1(H264, recommended in Linux), vp09(very slow), hevc(not support in Windowds), av01(not support in Windowds) (string [=mp4v])')
return parser.parse_args(arguments)
def load_configurations(self, upscaler):
self.driver_settings['zoomFactor'] = upscaler.scale_ratio
self.driver_settings['threads'] = upscaler.processes
# append FFmpeg path to the end of PATH
# Anime4KCPP will then use FFmpeg to migrate audio tracks
os.environ['PATH'] += f';{upscaler.ffmpeg_settings["ffmpeg_path"]}'
def upscale(self, input_file, output_file):
"""This is the core function for WAIFU2X class
Arguments:
input_file {string} -- source directory path
output_file {string} -- output directory path
width {int} -- output video width
height {int} -- output video height
"""
# overwrite config file settings
self.driver_settings['input'] = input_file
self.driver_settings['output'] = output_file
# Anime4KCPP will look for Anime4KCPPKernel.cl under the current working directory
# change the CWD to its containing directory so it will find it
if platform.system() == 'Windows':
os.chdir(pathlib.Path(self.driver_settings['path']).parent)
# list to be executed
# initialize the list with waifu2x binary path as the first element
execute = [self.driver_settings['path']]
for key in self.driver_settings.keys():
value = self.driver_settings[key]
# null or None means that leave this option out (keep default)
if key == 'path' or value is None or value is False:
continue
else:
if len(key) == 1:
execute.append(f'-{key}')
else:
execute.append(f'--{key}')
# true means key is an option
if value is not True:
execute.append(str(value))
# return the Popen object of the new process created
self.print_lock.acquire()
Avalon.debug_info(f'[upscaler] Subprocess {os.getpid()} executing: {shlex.join(execute)}')
self.print_lock.release()
return subprocess.Popen(execute)

287
src/wrappers/ffmpeg.py Normal file
View File

@@ -0,0 +1,287 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Name: Video2X FFmpeg Controller
Author: K4YT3X
Date Created: Feb 24, 2018
Last Modified: May 14, 2020
Description: This class handles all FFmpeg related operations.
"""
# built-in imports
import json
import pathlib
import shlex
import subprocess
# third-party imports
from avalon_framework import Avalon
class Ffmpeg:
"""This class communicates with FFmpeg
This class deals with FFmpeg. It handles extracting
frames, stripping audio, converting images into videos
and inserting audio tracks to videos.
"""
def __init__(self, ffmpeg_settings, image_format='png'):
self.ffmpeg_settings = ffmpeg_settings
self.ffmpeg_path = pathlib.Path(self.ffmpeg_settings['ffmpeg_path'])
self.ffmpeg_binary = self.ffmpeg_path / 'ffmpeg'
self.ffmpeg_probe_binary = self.ffmpeg_path / 'ffprobe'
# video metadata
self.image_format = image_format
self.intermediate_file_name = pathlib.Path(self.ffmpeg_settings['intermediate_file_name'])
self.pixel_format = self.ffmpeg_settings['extract_frames']['output_options']['-pix_fmt']
def get_pixel_formats(self):
""" Get a dictionary of supported pixel formats
List all supported pixel formats and their
corresponding bit depth.
Returns:
dictionary -- JSON dict of all pixel formats to bit depth
"""
execute = [
self.ffmpeg_probe_binary,
'-v',
'quiet',
'-pix_fmts'
]
# turn elements into str
execute = [str(e) for e in execute]
Avalon.debug_info(f'Executing: {shlex.join(execute)}')
# initialize dictionary to store pixel formats
pixel_formats = {}
# record all pixel formats into dictionary
for line in subprocess.run(execute, check=True, stdout=subprocess.PIPE).stdout.decode().split('\n'):
try:
pixel_formats[' '.join(line.split()).split()[1]] = int(' '.join(line.split()).split()[3])
except (IndexError, ValueError):
pass
# print pixel formats for debugging
Avalon.debug_info(str(pixel_formats))
return pixel_formats
def probe_file_info(self, input_video):
""" Gets input video information
This method reads input video information
using ffprobe in dictionary
Arguments:
input_video {string} -- input video file path
Returns:
dictionary -- JSON text of input video information
"""
# this execution command needs to be hard-coded
# since video2x only strictly recignizes this one format
execute = [
self.ffmpeg_probe_binary,
'-v',
'quiet',
'-print_format',
'json',
'-show_format',
'-show_streams',
'-i',
input_video
]
# turn elements into str
execute = [str(e) for e in execute]
Avalon.debug_info(f'Executing: {shlex.join(execute)}')
json_str = subprocess.run(execute, check=True, stdout=subprocess.PIPE).stdout
return json.loads(json_str.decode('utf-8'))
def extract_frames(self, input_file, extracted_frames):
""" extract frames from video or GIF file
"""
execute = [
self.ffmpeg_binary
]
# load general options
execute.extend(self._read_configuration(phase='extract_frames'))
# load input_options
execute.extend(self._read_configuration(phase='extract_frames', section='input_options'))
# specify input file
execute.extend([
'-i',
input_file
])
# load output options
execute.extend(self._read_configuration(phase='extract_frames', section='output_options'))
# specify output file
execute.extend([
extracted_frames / f'extracted_%0d.{self.image_format}'
])
return(self._execute(execute))
def assemble_video(self, framerate, upscaled_frames):
"""Converts images into videos
This method converts a set of images into a video
Arguments:
framerate {float} -- target video framerate
resolution {string} -- target video resolution
upscaled_frames {string} -- source images directory
"""
execute = [
self.ffmpeg_binary,
'-r',
str(framerate)
# '-s',
# resolution
]
# read other options
execute.extend(self._read_configuration(phase='assemble_video'))
# read input options
execute.extend(self._read_configuration(phase='assemble_video', section='input_options'))
# WORKAROUND FOR WAIFU2X-NCNN-VULKAN
# Dev: SAT3LL
# rename all .png.png suffixes to .png
import re
regex = re.compile(r'\.png\.png$', re.IGNORECASE)
for frame_name in upscaled_frames.iterdir():
(upscaled_frames / frame_name).rename(upscaled_frames / regex.sub('.png', str(frame_name)))
# END WORKAROUND
# append input frames path into command
execute.extend([
'-i',
upscaled_frames / f'extracted_%d.{self.image_format}'
])
# read FFmpeg output options
execute.extend(self._read_configuration(phase='assemble_video', section='output_options'))
# specify output file location
execute.extend([
upscaled_frames / self.intermediate_file_name
])
return(self._execute(execute))
def migrate_streams(self, input_video, output_video, upscaled_frames):
""" Migrates audio tracks and subtitles from input video to output video
Arguments:
input_video {string} -- input video file path
output_video {string} -- output video file path
upscaled_frames {string} -- directory containing upscaled frames
"""
execute = [
self.ffmpeg_binary
]
# load general options
execute.extend(self._read_configuration(phase='migrate_streams'))
# load input options
execute.extend(self._read_configuration(phase='migrate_streams', section='input_options'))
# load input file names
execute.extend([
# input 1: upscaled intermediate file without sound
'-i',
upscaled_frames / self.intermediate_file_name,
# input 2: original video with streams to copy over
'-i',
input_video
])
# load output options
execute.extend(self._read_configuration(phase='migrate_streams', section='output_options'))
# load output video path
execute.extend([
output_video
])
return(self._execute(execute))
def _read_configuration(self, phase, section=None):
""" read configuration from JSON
Read the configurations (arguments) from the JSON
configuration file and append them to the end of the
FFmpeg command.
Arguments:
execute {list} -- list of arguments to be executed
phase {str} -- phase of operation
"""
configuration = []
# if section is specified, read configurations or keys
# from only that section
if section:
source = self.ffmpeg_settings[phase][section].keys()
else:
source = self.ffmpeg_settings[phase].keys()
# for each key in the section's dict
for key in source:
if section:
value = self.ffmpeg_settings[phase][section][key]
else:
value = self.ffmpeg_settings[phase][key]
# null or None means that leave this option out (keep default)
if value is None or value is False or isinstance(value, dict) or value == '':
continue
# if the value is a list, append the same argument and all values
elif isinstance(value, list):
for subvalue in value:
configuration.append(key)
if value is not True:
configuration.append(str(subvalue))
# otherwise the value is typical
else:
configuration.append(key)
# true means key is an option
if value is True:
continue
configuration.append(str(value))
return configuration
def _execute(self, execute):
# turn all list elements into string to avoid errors
execute = [str(e) for e in execute]
Avalon.debug_info(f'Executing: {shlex.join(execute)}')
return subprocess.Popen(execute)

70
src/wrappers/gifski.py Normal file
View File

@@ -0,0 +1,70 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Name: Gifski Wrapper
Creator: K4YT3X
Date Created: May 11, 2020
Last Modified: May 11, 2020
Description: High-level wrapper for Gifski.
"""
# built-in imports
import pathlib
import subprocess
# third-party imports
from avalon_framework import Avalon
class Gifski:
def __init__(self, gifski_settings):
self.gifski_settings = gifski_settings
def make_gif(self, upscaled_frames: pathlib.Path, output_path: pathlib.Path, framerate: float, image_format: str) -> subprocess.Popen:
execute = [
self.gifski_settings['gifski_path'],
'-o',
output_path,
'--fps',
int(round(framerate, 0))
]
# load configurations from config file
execute.extend(self._load_configuration())
# append frames location
execute.extend([upscaled_frames / f'extracted_*.{image_format}'])
return(self._execute(execute))
def _load_configuration(self):
configuration = []
for key in self.gifski_settings.keys():
value = self.gifski_settings[key]
# null or None means that leave this option out (keep default)
if key == 'gifski_path' or value is None or value is False:
continue
else:
if len(key) == 1:
configuration.append(f'-{key}')
else:
configuration.append(f'--{key}')
# true means key is an option
if value is not True:
configuration.append(str(value))
return configuration
def _execute(self, execute: list) -> subprocess.Popen:
# turn all list elements into string to avoid errors
execute = [str(e) for e in execute]
Avalon.debug_info(f'Executing: {execute}')
return subprocess.Popen(execute)

View File

@@ -0,0 +1,103 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Name: SRMD NCNN Vulkan Driver
Creator: K4YT3X
Date Created: April 26, 2020
Last Modified: May 11, 2020
Description: This class is a high-level wrapper
for srmd_ncnn_vulkan.
"""
# built-in imports
import argparse
import os
import pathlib
import platform
import shlex
import subprocess
import threading
# third-party imports
from avalon_framework import Avalon
class WrapperMain:
"""This class communicates with SRMD NCNN Vulkan engine
An object will be created for this class, containing information
about the binary address and the processing method. When being called
by the main program, other detailed information will be passed to
the upscale function.
"""
def __init__(self, driver_settings):
self.driver_settings = driver_settings
self.print_lock = threading.Lock()
@staticmethod
def parse_arguments(arguments):
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter, add_help=False)
parser.error = lambda message: (_ for _ in ()).throw(AttributeError(message))
parser.add_argument('--help', action='help', help='show this help message and exit')
parser.add_argument('-v', action='store_true', help='verbose output')
parser.add_argument('-i', type=str, help=argparse.SUPPRESS) # help='input image path (jpg/png) or directory')
parser.add_argument('-o', type=str, help=argparse.SUPPRESS) # help='output image path (png) or directory')
parser.add_argument('-n', type=int, choices=range(-1, 11), help='denoise level')
parser.add_argument('-s', type=int, choices=range(2, 5), help='upscale ratio')
parser.add_argument('-t', type=int, help='tile size (>=32)')
parser.add_argument('-m', type=str, help='srmd model path')
parser.add_argument('-g', type=int, help='gpu device to use')
parser.add_argument('-j', type=str, help='thread count for load/proc/save')
parser.add_argument('-x', action='store_true', help='enable tta mode')
return parser.parse_args(arguments)
def load_configurations(self, upscaler):
self.driver_settings['s'] = int(upscaler.scale_ratio)
self.driver_settings['j'] = '{}:{}:{}'.format(upscaler.processes, upscaler.processes, upscaler.processes)
def upscale(self, input_directory, output_directory):
"""This is the core function for SRMD ncnn Vulkan class
Arguments:
input_directory {string} -- source directory path
output_directory {string} -- output directory path
ratio {int} -- output video ratio
"""
# overwrite config file settings
self.driver_settings['i'] = input_directory
self.driver_settings['o'] = output_directory
# by default, srmd-ncnn-vulkan will look for the models under the current working directory
# change the working directory to its containing folder if model directory not specified
if self.driver_settings['m'] is None and platform.system() == 'Windows':
os.chdir(pathlib.Path(self.driver_settings['path']).parent)
# list to be executed
# initialize the list with the binary path as the first element
execute = [self.driver_settings['path']]
for key in self.driver_settings.keys():
value = self.driver_settings[key]
# null or None means that leave this option out (keep default)
if key == 'path' or value is None or value is False:
continue
else:
if len(key) == 1:
execute.append(f'-{key}')
else:
execute.append(f'--{key}')
# true means key is an option
if value is not True:
execute.append(str(value))
# return the Popen object of the new process created
self.print_lock.acquire()
Avalon.debug_info(f'[upscaler] Subprocess {os.getpid()} executing: {shlex.join(execute)}')
self.print_lock.release()
return subprocess.Popen(execute)

View File

@@ -0,0 +1,105 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Name: Waifu2x Caffe Driver
Author: K4YT3X
Date Created: Feb 24, 2018
Last Modified: May 11, 2020
Description: This class is a high-level wrapper
for waifu2x-caffe.
"""
# built-in imports
import argparse
import os
import shlex
import subprocess
import threading
# third-party imports
from avalon_framework import Avalon
class WrapperMain:
"""This class communicates with waifu2x cui engine
An object will be created for this class, containing information
about the binary address and the processing method. When being called
by the main program, other detailed information will be passed to
the upscale function.
"""
def __init__(self, driver_settings):
self.driver_settings = driver_settings
self.print_lock = threading.Lock()
@staticmethod
def parse_arguments(arguments):
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter, add_help=False)
parser.error = lambda message: (_ for _ in ()).throw(AttributeError(message))
parser.add_argument('--help', action='help', help='show this help message and exit')
parser.add_argument('-t', '--tta', type=int, choices=range(2), help='8x slower and slightly high quality')
parser.add_argument('--gpu', type=int, help='gpu device no')
parser.add_argument('-b', '--batch_size', type=int, help='input batch size')
parser.add_argument('--crop_h', type=int, help='input image split size(height)')
parser.add_argument('--crop_w', type=int, help='input image split size(width)')
parser.add_argument('-c', '--crop_size', type=int, help='input image split size')
parser.add_argument('-d', '--output_depth', type=int, help='output image chaneel depth bit')
parser.add_argument('-q', '--output_quality', type=int, help='output image quality')
parser.add_argument('-p', '--process', choices=['cpu', 'gpu', 'cudnn'], help='process mode')
parser.add_argument('--model_dir', type=str, help='path to custom model directory (don\'t append last / )')
parser.add_argument('-h', '--scale_height', type=int, help='custom scale height')
parser.add_argument('-w', '--scale_width', type=int, help='custom scale width')
parser.add_argument('-s', '--scale_ratio', type=float, help='custom scale ratio')
parser.add_argument('-n', '--noise_level', type=int, choices=range(4), help='noise reduction level')
parser.add_argument('-m', '--mode', choices=['noise', 'scale', 'noise_scale', 'auto_scale'], help='image processing mode')
parser.add_argument('-e', '--output_extention', type=str, help='extention to output image file when output_path is (auto) or input_path is folder')
parser.add_argument('-l', '--input_extention_list', type=str, help='extention to input image file when input_path is folder')
parser.add_argument('-o', '--output_path', type=str, help=argparse.SUPPRESS) # help='path to output image file (when input_path is folder, output_path must be folder)')
parser.add_argument('-i', '--input_path', type=str, help=argparse.SUPPRESS) # help='(required) path to input image file')
return parser.parse_args(arguments)
def load_configurations(self, upscaler):
# use scale width and scale height if specified
self.driver_settings['scale_ratio'] = upscaler.scale_ratio
self.driver_settings['output_extention'] = upscaler.image_format
# bit_depth will be 12 at this point
# it will up updated later
self.driver_settings['output_depth'] = 12
def upscale(self, input_directory, output_directory):
""" start upscaling process
"""
# overwrite config file settings
self.driver_settings['input_path'] = input_directory
self.driver_settings['output_path'] = output_directory
# list to be executed
# initialize the list with waifu2x binary path as the first element
execute = [self.driver_settings['path']]
for key in self.driver_settings.keys():
value = self.driver_settings[key]
# null or None means that leave this option out (keep default)
if key == 'path' or value is None or value is False:
continue
else:
if len(key) == 1:
execute.append(f'-{key}')
else:
execute.append(f'--{key}')
# true means key is an option
if value is not True:
execute.append(str(value))
# return the Popen object of the new process created
self.print_lock.acquire()
Avalon.debug_info(f'[upscaler] Subprocess {os.getpid()} executing: {shlex.join(execute)}')
self.print_lock.release()
return subprocess.Popen(execute)

View File

@@ -0,0 +1,119 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Name: Waifu2x Converter CPP Driver
Author: K4YT3X
Date Created: February 8, 2019
Last Modified: May 11, 2020
Description: This class is a high-level wrapper
for waifu2x-converter-cpp.
"""
# built-in imports
import argparse
import os
import pathlib
import shlex
import subprocess
import threading
# third-party imports
from avalon_framework import Avalon
class WrapperMain:
"""This class communicates with waifu2x cui engine
An object will be created for this class, containing information
about the binary address and the processing method. When being called
by the main program, other detailed information will be passed to
the upscale function.
"""
def __init__(self, driver_settings):
self.driver_settings = driver_settings
self.print_lock = threading.Lock()
@staticmethod
def parse_arguments(arguments):
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter, add_help=False)
parser.error = lambda message: (_ for _ in ()).throw(AttributeError(message))
parser.add_argument('--help', action='help', help='show this help message and exit')
parser.add_argument('--list-supported-formats', action='store_true', help='dump currently supported format list')
parser.add_argument('--list-opencv-formats', action='store_true', help='(deprecated. Use --list-supported-formats) dump opencv supported format list')
parser.add_argument('-l', '--list-processor', action='store_true', help='dump processor list')
parser.add_argument('-f', '--output-format', choices=['png', 'jpg'], help='The format used when running in recursive/folder mode\nSee --list-supported-formats for a list of supported formats/extensions.')
parser.add_argument('-c', '--png-compression', type=int, choices=range(10), help='Set PNG compression level (0-9), 9 = Max compression (slowest & smallest)')
parser.add_argument('-q', '--image-quality', type=int, choices=range(-1, 102), help='JPEG & WebP Compression quality (0-101, 0 being smallest size and lowest quality), use 101 for lossless WebP')
parser.add_argument('--block-size', type=int, help='block size')
parser.add_argument('--disable-gpu', action='store_true', help='disable GPU')
parser.add_argument('--force-OpenCL', action='store_true', help='force to use OpenCL on Intel Platform')
parser.add_argument('-p', '--processor', type=int, help='set target processor')
parser.add_argument('-j', '--jobs', type=int, help='number of threads launching at the same time')
parser.add_argument('--model-dir', type=str, help='path to custom model directory (don\'t append last / )')
parser.add_argument('--scale-ratio', type=float, help='custom scale ratio')
parser.add_argument('--noise-level', type=int, choices=range(4), help='noise reduction level')
parser.add_argument('-m', '--mode', choices=['noise', 'scale', 'noise-scale'], help='image processing mode')
parser.add_argument('-v', '--log-level', type=int, choices=range(5), help='Set log level')
parser.add_argument('-s', '--silent', action='store_true', help='Enable silent mode. (same as --log-level 1)')
parser.add_argument('-t', '--tta', type=int, choices=range(2), help='Enable Test-Time Augmentation mode.')
parser.add_argument('-g', '--generate-subdir', type=int, choices=range(2), help='Generate sub folder when recursive directory is enabled.')
parser.add_argument('-a', '--auto-naming', type=int, choices=range(2), help='Add postfix to output name when output path is not specified.\nSet 0 to disable this.')
parser.add_argument('-r', '--recursive-directory', type=int, choices=range(2), help='Search recursively through directories to find more images to process.')
parser.add_argument('-o', '--output', type=str, help=argparse.SUPPRESS) # help='path to output image file or directory (you should use the full path)')
parser.add_argument('-i', '--input', type=str, help=argparse.SUPPRESS) # help='(required) path to input image file or directory (you should use the full path)')
parser.add_argument('--version', action='store_true', help='Displays version information and exits.')
return parser.parse_args(arguments)
def load_configurations(self, upscaler):
self.driver_settings['scale-ratio'] = upscaler.scale_ratio
self.driver_settings['jobs'] = upscaler.processes
self.driver_settings['output-format'] = upscaler.image_format.lower()
def upscale(self, input_directory, output_directory):
""" Waifu2x Converter Driver Upscaler
This method executes the upscaling of extracted frames.
Arguments:
input_directory {string} -- source directory path
output_directory {string} -- output directory path
scale_ratio {int} -- frames' scale ratio
threads {int} -- number of threads
"""
# overwrite config file settings
self.driver_settings['input'] = input_directory
self.driver_settings['output'] = output_directory
# models_rgb must be specified manually for waifu2x-converter-cpp
# if it's not specified in the arguments, create automatically
if self.driver_settings['model-dir'] is None:
self.driver_settings['model-dir'] = pathlib.Path(self.driver_settings['path']).parent / 'models_rgb'
# list to be executed
# initialize the list with waifu2x binary path as the first element
execute = [self.driver_settings['path']]
for key in self.driver_settings.keys():
value = self.driver_settings[key]
# null or None means that leave this option out (keep default)
if key == 'path' or value is None or value is False:
continue
else:
if len(key) == 1:
execute.append(f'-{key}')
else:
execute.append(f'--{key}')
# true means key is an option
if value is not True:
execute.append(str(value))
# return the Popen object of the new process created
self.print_lock.acquire()
Avalon.debug_info(f'[upscaler] Subprocess {os.getpid()} executing: {shlex.join(execute)}')
self.print_lock.release()
return subprocess.Popen(execute)

View File

@@ -0,0 +1,106 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Name: Waifu2x NCNN Vulkan Driver
Creator: SAT3LL
Date Created: June 26, 2019
Last Modified: May 11, 2020
Editor: K4YT3X
Last Modified: February 22, 2020
Description: This class is a high-level wrapper
for waifu2x_ncnn_vulkan.
"""
# built-in imports
import argparse
import os
import pathlib
import platform
import shlex
import subprocess
import threading
# third-party imports
from avalon_framework import Avalon
class WrapperMain:
"""This class communicates with waifu2x ncnn vulkan engine
An object will be created for this class, containing information
about the binary address and the processing method. When being called
by the main program, other detailed information will be passed to
the upscale function.
"""
def __init__(self, driver_settings):
self.driver_settings = driver_settings
self.print_lock = threading.Lock()
@staticmethod
def parse_arguments(arguments):
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter, add_help=False)
parser.error = lambda message: (_ for _ in ()).throw(AttributeError(message))
parser.add_argument('--help', action='help', help='show this help message and exit')
parser.add_argument('-v', action='store_true', help='verbose output')
parser.add_argument('-i', type=str, help=argparse.SUPPRESS) # help='input image path (jpg/png) or directory')
parser.add_argument('-o', type=str, help=argparse.SUPPRESS) # help='output image path (png) or directory')
parser.add_argument('-n', type=int, choices=range(-1, 4), help='denoise level')
parser.add_argument('-s', type=int, choices=range(1, 3), help='upscale ratio')
parser.add_argument('-t', type=int, help='tile size (>=32)')
parser.add_argument('-m', type=str, help='waifu2x model path')
parser.add_argument('-g', type=int, help='gpu device to use')
parser.add_argument('-j', type=str, help='thread count for load/proc/save')
parser.add_argument('-x', action='store_true', help='enable tta mode')
return parser.parse_args(arguments)
def load_configurations(self, upscaler):
self.driver_settings['s'] = int(upscaler.scale_ratio)
self.driver_settings['j'] = '{}:{}:{}'.format(upscaler.processes, upscaler.processes, upscaler.processes)
def upscale(self, input_directory, output_directory):
"""This is the core function for WAIFU2X class
Arguments:
input_directory {string} -- source directory path
output_directory {string} -- output directory path
ratio {int} -- output video ratio
"""
# overwrite config file settings
self.driver_settings['i'] = input_directory
self.driver_settings['o'] = output_directory
# by default, waifu2x-ncnn-vulkan will look for the models under the current working directory
# change the working directory to its containing folder if model directory not specified
if self.driver_settings['m'] is None and platform.system() == 'Windows':
os.chdir(pathlib.Path(self.driver_settings['path']).parent)
# list to be executed
# initialize the list with waifu2x binary path as the first element
execute = [self.driver_settings['path']]
for key in self.driver_settings.keys():
value = self.driver_settings[key]
# null or None means that leave this option out (keep default)
if key == 'path' or value is None or value is False:
continue
else:
if len(key) == 1:
execute.append(f'-{key}')
else:
execute.append(f'--{key}')
# true means key is an option
if value is not True:
execute.append(str(value))
# return the Popen object of the new process created
self.print_lock.acquire()
Avalon.debug_info(f'[upscaler] Subprocess {os.getpid()} executing: {shlex.join(execute)}')
self.print_lock.release()
return subprocess.Popen(execute)