mirror of
https://github.com/k4yt3x/video2x.git
synced 2024-12-28 23:19:11 +00:00
committing changes for 5.0.0-beta
This commit is contained in:
parent
e870399af1
commit
7eabac2175
9
.gitignore
vendored
9
.gitignore
vendored
@ -1,3 +1,12 @@
|
|||||||
|
# compiled wrappers for testing purposes
|
||||||
|
video2x/wrappers
|
||||||
|
|
||||||
|
# test videos
|
||||||
|
*.mp4
|
||||||
|
|
||||||
|
# vim
|
||||||
|
Session.vim
|
||||||
|
|
||||||
# QtCreator
|
# QtCreator
|
||||||
video2x_gui.pyproject.user
|
video2x_gui.pyproject.user
|
||||||
|
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
# Directory Listing
|
|
||||||
|
|
||||||
- [**images**](images): image assets such as executable icons
|
|
||||||
- [**locale**](locale): language locale files (.po, .mo)
|
|
||||||
- [**pyinstaller**](pyinstaller): PyInstaller-specific files
|
|
||||||
- [**wrappers**](wrappers): binary Python wrappers/bindings
|
|
||||||
- [**bilogger.py**](bilogger.py): bidirectional logger
|
|
||||||
- [**build.ps1**](build.ps1): release building script
|
|
||||||
- [**exceptions.py**](exceptions.py): custom exceptions
|
|
||||||
- [**image_cleaner.py**](image_cleaner.py): upscaled images cleaner
|
|
||||||
- [**progress_monitor.py**](progress_monitor.py): upscaling progress monitor
|
|
||||||
- [**requirements.txt**](requirements.txt): Python requirements for pip
|
|
||||||
- [**upscaler.py**](upscaler.py): main upscaler class
|
|
||||||
- [**video2x.pot**](video2x.pot): project i18n POT translation file
|
|
||||||
- [**video2x.py**](video2x.py): command line interface
|
|
||||||
- [**video2x.yaml**](video2x.yaml): configuration file
|
|
||||||
- [**video2x_gui.py**](video2x_gui.py): graphical user interface
|
|
||||||
- [**video2x_gui.pyproject**](video2x_gui.pyproject): QtCreator project file
|
|
||||||
- [**video2x_gui.ui**](video2x_gui.ui): GUI UI file (defines GUI layout)
|
|
||||||
- [**video2x_setup.py**](video2x_setup.py): automatic setup script for Windows
|
|
||||||
- [**video2x_setup_ubuntu.sh**](video2x_setup_ubuntu.sh): automatic setup script for Ubuntu
|
|
11
video2x/__init__.py
Executable file
11
video2x/__init__.py
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Name: Video2X package init
|
||||||
|
Author: K4YT3X
|
||||||
|
Date Created: July 3, 2021
|
||||||
|
Last Modified: July 3, 2021
|
||||||
|
"""
|
||||||
|
from .video2x import Video2X
|
||||||
|
from .upscaler import Upscaler
|
||||||
|
from .interpolator import Interpolator
|
13
video2x/__main__.py
Executable file
13
video2x/__main__.py
Executable file
@ -0,0 +1,13 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Name: Video2X package main
|
||||||
|
Author: K4YT3X
|
||||||
|
Date Created: July 3, 2021
|
||||||
|
Last Modified: July 3, 2021
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .video2x import main
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
@ -1,45 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
Creator: Video2X Bidirectional Logger
|
|
||||||
Author: K4YT3X
|
|
||||||
Date Created: June 4, 2020
|
|
||||||
Last Modified: December 13, 2020
|
|
||||||
"""
|
|
||||||
|
|
||||||
# built-in imports
|
|
||||||
import io
|
|
||||||
|
|
||||||
|
|
||||||
class BiLogger(io.TextIOWrapper):
|
|
||||||
"""A bidirectional logger that both prints the output
|
|
||||||
and log all output to file.
|
|
||||||
|
|
||||||
Original code from: https://stackoverflow.com/a/14906787
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, terminal: io.TextIOWrapper, log_file: io.BufferedRandom):
|
|
||||||
"""initialize BiLogger
|
|
||||||
|
|
||||||
Args:
|
|
||||||
terminal (_io.TextIOWrapper): original terminal IO wrapper
|
|
||||||
logfile (_io.BufferedRandom): log file wrapper
|
|
||||||
"""
|
|
||||||
self.terminal = terminal
|
|
||||||
self.log_file = log_file
|
|
||||||
self.fileno = self.log_file.fileno
|
|
||||||
|
|
||||||
def write(self, message: str):
|
|
||||||
"""write message to original terminal output and log file
|
|
||||||
|
|
||||||
Args:
|
|
||||||
message (str): message to write
|
|
||||||
"""
|
|
||||||
self.terminal.write(message)
|
|
||||||
self.terminal.flush()
|
|
||||||
self.log_file.write(message)
|
|
||||||
self.log_file.flush()
|
|
||||||
|
|
||||||
def flush(self):
|
|
||||||
"""flush logger (for compability only)"""
|
|
||||||
pass
|
|
@ -1,96 +0,0 @@
|
|||||||
<#
|
|
||||||
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"
|
|
140
video2x/decoder.py
Executable file
140
video2x/decoder.py
Executable file
@ -0,0 +1,140 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Name: Video Decoder
|
||||||
|
Author: K4YT3X
|
||||||
|
Date Created: June 17, 2021
|
||||||
|
Last Modified: June 17, 2021
|
||||||
|
"""
|
||||||
|
|
||||||
|
# built-in imports
|
||||||
|
import os
|
||||||
|
import pathlib
|
||||||
|
import queue
|
||||||
|
import subprocess
|
||||||
|
import threading
|
||||||
|
|
||||||
|
# third-party imports
|
||||||
|
from loguru import logger
|
||||||
|
from PIL import Image
|
||||||
|
import ffmpeg
|
||||||
|
|
||||||
|
|
||||||
|
# map Loguru log levels to FFmpeg log levels
|
||||||
|
LOGURU_FFMPEG_LOGLEVELS = {
|
||||||
|
"trace": "trace",
|
||||||
|
"debug": "debug",
|
||||||
|
"info": "info",
|
||||||
|
"success": "info",
|
||||||
|
"warning": "warning",
|
||||||
|
"error": "error",
|
||||||
|
"critical": "fatal",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class VideoDecoder(threading.Thread):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
input_path: pathlib.Path,
|
||||||
|
input_width: int,
|
||||||
|
input_height: int,
|
||||||
|
frame_rate: float,
|
||||||
|
processing_queue: queue.Queue,
|
||||||
|
processing_settings: tuple,
|
||||||
|
ignore_max_image_pixels=True,
|
||||||
|
):
|
||||||
|
threading.Thread.__init__(self)
|
||||||
|
self.running = False
|
||||||
|
self.input_path = input_path
|
||||||
|
self.input_width = input_width
|
||||||
|
self.input_height = input_height
|
||||||
|
self.processing_queue = processing_queue
|
||||||
|
self.processing_settings = processing_settings
|
||||||
|
|
||||||
|
# this disables the "possible DDoS" warning
|
||||||
|
if ignore_max_image_pixels:
|
||||||
|
Image.MAX_IMAGE_PIXELS = None
|
||||||
|
|
||||||
|
self.exception = None
|
||||||
|
self.decoder = subprocess.Popen(
|
||||||
|
ffmpeg.compile(
|
||||||
|
ffmpeg.input(input_path, r=frame_rate)["v"]
|
||||||
|
.output("pipe:1", format="rawvideo", pix_fmt="rgb24", vsync="1")
|
||||||
|
.global_args("-hide_banner")
|
||||||
|
.global_args("-nostats")
|
||||||
|
.global_args(
|
||||||
|
"-loglevel",
|
||||||
|
LOGURU_FFMPEG_LOGLEVELS.get(
|
||||||
|
os.environ.get("LOGURU_LEVEL", "INFO").lower()
|
||||||
|
),
|
||||||
|
),
|
||||||
|
overwrite_output=True,
|
||||||
|
),
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
# stderr=subprocess.DEVNULL,
|
||||||
|
)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.running = True
|
||||||
|
|
||||||
|
# the index of the frame
|
||||||
|
frame_index = 0
|
||||||
|
|
||||||
|
# create placeholder for previous frame
|
||||||
|
# used in interpolate mode
|
||||||
|
previous_image = None
|
||||||
|
|
||||||
|
# continue running until an exception occurs
|
||||||
|
# or all frames have been decoded
|
||||||
|
while self.running:
|
||||||
|
try:
|
||||||
|
buffer = self.decoder.stdout.read(
|
||||||
|
3 * self.input_width * self.input_height
|
||||||
|
)
|
||||||
|
|
||||||
|
# source depleted (decoding finished)
|
||||||
|
# after the last frame has been decoded
|
||||||
|
# read will return nothing
|
||||||
|
if len(buffer) == 0:
|
||||||
|
logger.debug("Decoding queue depleted")
|
||||||
|
break
|
||||||
|
|
||||||
|
# convert raw bytes into image object
|
||||||
|
image = Image.frombytes(
|
||||||
|
"RGB", (self.input_width, self.input_height), buffer
|
||||||
|
)
|
||||||
|
|
||||||
|
# if this is the first frame
|
||||||
|
# there wouldn't be a "previous image"
|
||||||
|
if previous_image is not None:
|
||||||
|
self.processing_queue.put(
|
||||||
|
(
|
||||||
|
frame_index,
|
||||||
|
(previous_image, image),
|
||||||
|
self.processing_settings,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
previous_image = image
|
||||||
|
|
||||||
|
frame_index += 1
|
||||||
|
|
||||||
|
# most likely "not enough image data"
|
||||||
|
except ValueError as e:
|
||||||
|
logger.exception(e)
|
||||||
|
break
|
||||||
|
|
||||||
|
# send exceptions into the client connection pipe
|
||||||
|
except Exception as e:
|
||||||
|
self.exception = e
|
||||||
|
logger.exception(e)
|
||||||
|
break
|
||||||
|
|
||||||
|
# ensure the decoder has exited
|
||||||
|
self.decoder.wait()
|
||||||
|
logger.debug("Decoder thread exiting")
|
||||||
|
|
||||||
|
self.running = False
|
||||||
|
return super().run()
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self.running = False
|
150
video2x/encoder.py
Executable file
150
video2x/encoder.py
Executable file
@ -0,0 +1,150 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Name: Video Encoder
|
||||||
|
Author: K4YT3X
|
||||||
|
Date Created: June 17, 2021
|
||||||
|
Last Modified: June 30, 2021
|
||||||
|
"""
|
||||||
|
|
||||||
|
# built-in imports
|
||||||
|
import multiprocessing
|
||||||
|
import multiprocessing.managers
|
||||||
|
import multiprocessing.sharedctypes
|
||||||
|
import os
|
||||||
|
import pathlib
|
||||||
|
import signal
|
||||||
|
import subprocess
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
|
||||||
|
# third-party imports
|
||||||
|
from loguru import logger
|
||||||
|
import ffmpeg
|
||||||
|
|
||||||
|
|
||||||
|
# map Loguru log levels to FFmpeg log levels
|
||||||
|
LOGURU_FFMPEG_LOGLEVELS = {
|
||||||
|
"trace": "trace",
|
||||||
|
"debug": "debug",
|
||||||
|
"info": "info",
|
||||||
|
"success": "info",
|
||||||
|
"warning": "warning",
|
||||||
|
"error": "error",
|
||||||
|
"critical": "fatal",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class VideoEncoder(threading.Thread):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
input_path: pathlib.Path,
|
||||||
|
frame_rate: float,
|
||||||
|
output_path: pathlib.Path,
|
||||||
|
output_width: int,
|
||||||
|
output_height: int,
|
||||||
|
total_frames: int,
|
||||||
|
processed_frames: multiprocessing.managers.ListProxy,
|
||||||
|
processed: multiprocessing.sharedctypes.Synchronized,
|
||||||
|
):
|
||||||
|
threading.Thread.__init__(self)
|
||||||
|
self.running = False
|
||||||
|
self.input_path = input_path
|
||||||
|
self.output_path = output_path
|
||||||
|
self.total_frames = total_frames
|
||||||
|
self.processed_frames = processed_frames
|
||||||
|
self.processed = processed
|
||||||
|
|
||||||
|
self.original = ffmpeg.input(input_path)
|
||||||
|
|
||||||
|
# define frames as input
|
||||||
|
frames = ffmpeg.input(
|
||||||
|
"pipe:0",
|
||||||
|
format="rawvideo",
|
||||||
|
pix_fmt="rgb24",
|
||||||
|
vsync="1",
|
||||||
|
s=f"{output_width}x{output_height}",
|
||||||
|
r=frame_rate,
|
||||||
|
)
|
||||||
|
|
||||||
|
# map additional streams from original file
|
||||||
|
"""
|
||||||
|
additional_streams = [
|
||||||
|
# self.original["v?"],
|
||||||
|
self.original["a?"],
|
||||||
|
self.original["s?"],
|
||||||
|
self.original["d?"],
|
||||||
|
self.original["t?"],
|
||||||
|
]
|
||||||
|
"""
|
||||||
|
|
||||||
|
# run FFmpeg and produce final output
|
||||||
|
self.encoder = subprocess.Popen(
|
||||||
|
ffmpeg.compile(
|
||||||
|
ffmpeg.output(
|
||||||
|
frames,
|
||||||
|
str(self.output_path),
|
||||||
|
pix_fmt="yuv420p",
|
||||||
|
vcodec="libx264",
|
||||||
|
acodec="copy",
|
||||||
|
r=frame_rate,
|
||||||
|
crf=17,
|
||||||
|
vsync="1",
|
||||||
|
# map_metadata=1,
|
||||||
|
# metadata="comment=Upscaled with Video2X",
|
||||||
|
)
|
||||||
|
.global_args("-hide_banner")
|
||||||
|
.global_args("-nostats")
|
||||||
|
.global_args(
|
||||||
|
"-loglevel",
|
||||||
|
LOGURU_FFMPEG_LOGLEVELS.get(
|
||||||
|
os.environ.get("LOGURU_LEVEL", "INFO").lower()
|
||||||
|
),
|
||||||
|
),
|
||||||
|
overwrite_output=True,
|
||||||
|
),
|
||||||
|
stdin=subprocess.PIPE,
|
||||||
|
# stdout=subprocess.DEVNULL,
|
||||||
|
# stderr=subprocess.DEVNULL,
|
||||||
|
)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.running = True
|
||||||
|
frame_index = 0
|
||||||
|
while self.running and frame_index < self.total_frames:
|
||||||
|
try:
|
||||||
|
image = self.processed_frames[frame_index]
|
||||||
|
if image is None:
|
||||||
|
time.sleep(0.1)
|
||||||
|
continue
|
||||||
|
|
||||||
|
self.encoder.stdin.write(image.tobytes())
|
||||||
|
|
||||||
|
with self.processed.get_lock():
|
||||||
|
self.processed.value += 1
|
||||||
|
|
||||||
|
frame_index += 1
|
||||||
|
|
||||||
|
# send exceptions into the client connection pipe
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception(e)
|
||||||
|
break
|
||||||
|
|
||||||
|
# flush the remaining data in STDIN and close PIPE
|
||||||
|
logger.debug("Encoding queue depleted")
|
||||||
|
self.encoder.stdin.flush()
|
||||||
|
self.encoder.stdin.close()
|
||||||
|
|
||||||
|
# send SIGINT (2) to FFmpeg
|
||||||
|
# this instructs it to finalize and exit
|
||||||
|
self.encoder.send_signal(signal.SIGINT)
|
||||||
|
|
||||||
|
# wait for process to terminate
|
||||||
|
self.encoder.wait()
|
||||||
|
logger.debug("Encoder thread exiting")
|
||||||
|
|
||||||
|
self.running = False
|
||||||
|
return super().run()
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self.running = False
|
@ -1,28 +0,0 @@
|
|||||||
#!/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)
|
|
@ -1,14 +0,0 @@
|
|||||||
<#
|
|
||||||
Name: Video2X Generate POT Script
|
|
||||||
Creator: K4YT3X
|
|
||||||
Date Created: September 12, 2020
|
|
||||||
Last Modified: September 12, 2020
|
|
||||||
|
|
||||||
Description: A PowerShell script that uses Python's pygettext
|
|
||||||
script to generate the POT file for translations.
|
|
||||||
|
|
||||||
To start a PowerShell session with execution policy bypass
|
|
||||||
powershell -ExecutionPolicy Bypass
|
|
||||||
#>
|
|
||||||
|
|
||||||
python $env:LOCALAPPDATA\Programs\Python\Python38\Tools\i18n\pygettext.py -d video2x *.py wrappers\*.py
|
|
@ -1,77 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
Name: Video2X Image Cleaner
|
|
||||||
Author: BrianPetkovsek
|
|
||||||
Date Created: March 24, 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.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# built-in imports
|
|
||||||
import threading
|
|
||||||
import time
|
|
||||||
|
|
||||||
|
|
||||||
class ImageCleaner(threading.Thread):
|
|
||||||
"""Video2X Image Cleaner
|
|
||||||
|
|
||||||
This class creates an object that keeps track of extracted
|
|
||||||
frames that has already been upscaled and are not needed
|
|
||||||
anymore. It then deletes them to save disk space.
|
|
||||||
|
|
||||||
Extends:
|
|
||||||
threading.Thread
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, input_directory, output_directory, threads):
|
|
||||||
threading.Thread.__init__(self)
|
|
||||||
self.input_directory = input_directory
|
|
||||||
self.output_directory = output_directory
|
|
||||||
self.threads = threads
|
|
||||||
self.running = False
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
"""Run image cleaner"""
|
|
||||||
self.running = True
|
|
||||||
|
|
||||||
while self.running:
|
|
||||||
self.remove_upscaled_frames()
|
|
||||||
time.sleep(1)
|
|
||||||
|
|
||||||
def stop(self):
|
|
||||||
"""Stop the image cleaner"""
|
|
||||||
self.running = False
|
|
||||||
self.join()
|
|
||||||
|
|
||||||
def remove_upscaled_frames(self):
|
|
||||||
"""remove frames that have already been upscaled
|
|
||||||
|
|
||||||
This method compares the files in the extracted frames
|
|
||||||
directory with the upscaled frames directory, and removes
|
|
||||||
the frames that has already been upscaled.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# list all images in the extracted frames
|
|
||||||
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 thread_id in range(self.threads):
|
|
||||||
dir_path = self.input_directory / str(thread_id)
|
|
||||||
|
|
||||||
# for each file within all the directories
|
|
||||||
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 file.is_file() and file.name in output_frames:
|
|
||||||
file.unlink()
|
|
||||||
output_frames.remove(file.name)
|
|
Binary file not shown.
Before Width: | Height: | Size: 29 KiB |
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 23 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 133 KiB |
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 120 KiB |
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 110 KiB |
Binary file not shown.
Before Width: | Height: | Size: 39 KiB |
100
video2x/interpolator.py
Executable file
100
video2x/interpolator.py
Executable file
@ -0,0 +1,100 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Name: Interpolator
|
||||||
|
Author: K4YT3X
|
||||||
|
Date Created: May 27, 2021
|
||||||
|
Last Modified: July 3, 2021
|
||||||
|
"""
|
||||||
|
|
||||||
|
# local imports
|
||||||
|
from .wrappers.rife_ncnn_vulkan_python.rife_ncnn_vulkan import RIFE
|
||||||
|
|
||||||
|
# built-in imports
|
||||||
|
import multiprocessing
|
||||||
|
import multiprocessing.managers
|
||||||
|
import multiprocessing.sharedctypes
|
||||||
|
import queue
|
||||||
|
import signal
|
||||||
|
import time
|
||||||
|
|
||||||
|
# third-party imports
|
||||||
|
from PIL import ImageChops, ImageStat
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
|
|
||||||
|
DRIVER_CLASSES = {"rife": RIFE}
|
||||||
|
|
||||||
|
|
||||||
|
class Interpolator(multiprocessing.Process):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
processing_queue: multiprocessing.Queue,
|
||||||
|
processed_frames: multiprocessing.managers.ListProxy,
|
||||||
|
):
|
||||||
|
multiprocessing.Process.__init__(self)
|
||||||
|
self.running = False
|
||||||
|
self.processing_queue = processing_queue
|
||||||
|
self.processed_frames = processed_frames
|
||||||
|
|
||||||
|
signal.signal(signal.SIGTERM, self._stop)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.running = True
|
||||||
|
logger.info(f"Interpolator process {self.name} initiating")
|
||||||
|
driver_objects = {}
|
||||||
|
while self.running:
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
# get new job from queue
|
||||||
|
(
|
||||||
|
frame_index,
|
||||||
|
(image0, image1),
|
||||||
|
(difference_threshold, driver),
|
||||||
|
) = self.processing_queue.get(False)
|
||||||
|
except queue.Empty:
|
||||||
|
time.sleep(0.1)
|
||||||
|
continue
|
||||||
|
|
||||||
|
difference = ImageChops.difference(image0, image1)
|
||||||
|
difference_stat = ImageStat.Stat(difference)
|
||||||
|
difference_ratio = (
|
||||||
|
sum(difference_stat.mean) / (len(difference_stat.mean) * 255) * 100
|
||||||
|
)
|
||||||
|
|
||||||
|
# if the difference is lower than threshold
|
||||||
|
# process the interpolation
|
||||||
|
if difference_ratio < difference_threshold:
|
||||||
|
|
||||||
|
# select a driver object with the required settings
|
||||||
|
# create a new object if none are available
|
||||||
|
driver_object = driver_objects.get(driver)
|
||||||
|
if driver_object is None:
|
||||||
|
driver_object = DRIVER_CLASSES[driver](0)
|
||||||
|
driver_objects[driver] = driver_object
|
||||||
|
interpolated_image = driver_object.process(image0, image1)
|
||||||
|
|
||||||
|
# if the difference is greater than threshold
|
||||||
|
# there's a change in camera angle, ignore
|
||||||
|
else:
|
||||||
|
interpolated_image = image0
|
||||||
|
|
||||||
|
if frame_index == 1:
|
||||||
|
self.processed_frames[0] = image0
|
||||||
|
self.processed_frames[frame_index * 2 - 1] = interpolated_image
|
||||||
|
self.processed_frames[frame_index * 2] = image1
|
||||||
|
|
||||||
|
# send exceptions into the client connection pipe
|
||||||
|
except (SystemExit, KeyboardInterrupt):
|
||||||
|
break
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception(e)
|
||||||
|
break
|
||||||
|
|
||||||
|
logger.info(f"Interpolator process {self.name} terminating")
|
||||||
|
self.running = False
|
||||||
|
return super().run()
|
||||||
|
|
||||||
|
def _stop(self, signal_number, frame):
|
||||||
|
self.running = False
|
Binary file not shown.
Binary file not shown.
@ -1,431 +0,0 @@
|
|||||||
# SOME DESCRIPTIVE TITLE.
|
|
||||||
# Copyright (C) YEAR ORGANIZATION
|
|
||||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
|
||||||
#
|
|
||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
"Project-Id-Version: \n"
|
|
||||||
"POT-Creation-Date: 2021-01-23 16:45-0500\n"
|
|
||||||
"PO-Revision-Date: 2021-01-23 16:47-0500\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.4.1\n"
|
|
||||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
|
||||||
|
|
||||||
#: progress_monitor.py:40
|
|
||||||
msgid "Processing: {} (pass {}/{})"
|
|
||||||
msgstr "正在处理:{}(进度)"
|
|
||||||
|
|
||||||
#: upscaler.py:160
|
|
||||||
msgid "Specified or default cache directory is a file/link"
|
|
||||||
msgstr "指定或默认的缓存目录是文件/链接"
|
|
||||||
|
|
||||||
#: upscaler.py:167
|
|
||||||
msgid "Creating cache directory {}"
|
|
||||||
msgstr "创建缓存目录 {}"
|
|
||||||
|
|
||||||
#: upscaler.py:174
|
|
||||||
msgid "Unable to create {}"
|
|
||||||
msgstr "无法创建 {}"
|
|
||||||
|
|
||||||
#: upscaler.py:183
|
|
||||||
msgid "Extracted frames are being saved to: {}"
|
|
||||||
msgstr "提取的帧将被保存到:{}"
|
|
||||||
|
|
||||||
#: upscaler.py:189
|
|
||||||
msgid "Upscaled frames are being saved to: {}"
|
|
||||||
msgstr "已放大的帧将被保存到:{}"
|
|
||||||
|
|
||||||
#: upscaler.py:203
|
|
||||||
msgid "Cleaning up cache directory: {}"
|
|
||||||
msgstr "清理缓存目录:{}"
|
|
||||||
|
|
||||||
#: upscaler.py:208
|
|
||||||
msgid "Unable to delete: {}"
|
|
||||||
msgstr "无法删除:{}"
|
|
||||||
|
|
||||||
#: upscaler.py:214 upscaler.py:239 upscaler.py:250
|
|
||||||
msgid "Input and output path type mismatch"
|
|
||||||
msgstr "输入和输出路径类型不匹配"
|
|
||||||
|
|
||||||
#: upscaler.py:215
|
|
||||||
msgid "Input is multiple files but output is not directory"
|
|
||||||
msgstr "输入是多个文件,但输出不是目录"
|
|
||||||
|
|
||||||
#: upscaler.py:220
|
|
||||||
msgid "Input path {} is neither a file nor a directory"
|
|
||||||
msgstr "输入路径 {} 既不是文件也不是目录"
|
|
||||||
|
|
||||||
#: upscaler.py:230 upscaler.py:256
|
|
||||||
msgid "Input directory and output directory cannot be the same"
|
|
||||||
msgstr "输入目录和输出目录不能相同"
|
|
||||||
|
|
||||||
#: upscaler.py:240
|
|
||||||
msgid "Input is single file but output is directory"
|
|
||||||
msgstr "所选的输入路径是单个文件,但输出路径是目录"
|
|
||||||
|
|
||||||
#: upscaler.py:243
|
|
||||||
msgid "No suffix found in output file path"
|
|
||||||
msgstr "在输出文件路径中未找到后缀"
|
|
||||||
|
|
||||||
#: upscaler.py:244
|
|
||||||
msgid "Suffix must be specified"
|
|
||||||
msgstr "必须指定文件后缀"
|
|
||||||
|
|
||||||
#: upscaler.py:251
|
|
||||||
msgid "Input is directory but output is existing single file"
|
|
||||||
msgstr "输入是目录,但输出是现有的单个文件"
|
|
||||||
|
|
||||||
#: upscaler.py:264
|
|
||||||
msgid "Input path is neither a file nor a directory"
|
|
||||||
msgstr "输入路径既不是文件也不是目录"
|
|
||||||
|
|
||||||
#: upscaler.py:280
|
|
||||||
msgid "FFmpeg or FFprobe cannot be found under the specified path"
|
|
||||||
msgstr "在指定的路径下找不到 FFmpeg 或 FFprobe"
|
|
||||||
|
|
||||||
#: upscaler.py:282 upscaler.py:295
|
|
||||||
msgid "Please check the configuration file settings"
|
|
||||||
msgstr "请检查配置文件设置"
|
|
||||||
|
|
||||||
#: upscaler.py:294
|
|
||||||
msgid "Specified driver executable directory doesn't exist"
|
|
||||||
msgstr "指定驱动的可执行文件不存在"
|
|
||||||
|
|
||||||
#: upscaler.py:323
|
|
||||||
msgid "Failed to parse driver argument: {}"
|
|
||||||
msgstr "解析驱动程序参数失败:{}"
|
|
||||||
|
|
||||||
#: upscaler.py:346
|
|
||||||
msgid "Unrecognized driver: {}"
|
|
||||||
msgstr "无法识别的驱动名称:{}"
|
|
||||||
|
|
||||||
#: upscaler.py:397
|
|
||||||
msgid "Starting progress monitor"
|
|
||||||
msgstr "启动进度监视器"
|
|
||||||
|
|
||||||
#: upscaler.py:402
|
|
||||||
msgid "Starting upscaled image cleaner"
|
|
||||||
msgstr "启动已放大图像清理程序"
|
|
||||||
|
|
||||||
#: upscaler.py:413 upscaler.py:432
|
|
||||||
msgid "Killing progress monitor"
|
|
||||||
msgstr "终结进度监视器"
|
|
||||||
|
|
||||||
#: upscaler.py:416 upscaler.py:435
|
|
||||||
msgid "Killing upscaled image cleaner"
|
|
||||||
msgstr "终结已放大图像清理程序"
|
|
||||||
|
|
||||||
#: upscaler.py:439
|
|
||||||
msgid "Terminating all processes"
|
|
||||||
msgstr "正在终止所有进程"
|
|
||||||
|
|
||||||
#: upscaler.py:445
|
|
||||||
msgid "Main process waiting for subprocesses to exit"
|
|
||||||
msgstr "主进程开始等待子进程结束"
|
|
||||||
|
|
||||||
#: upscaler.py:465 upscaler.py:475
|
|
||||||
msgid "Subprocess {} exited with code {}"
|
|
||||||
msgstr "子进程 {} 结束,返回码 {}"
|
|
||||||
|
|
||||||
#: upscaler.py:484
|
|
||||||
msgid "Stop signal received"
|
|
||||||
msgstr "收到停止信号"
|
|
||||||
|
|
||||||
#: upscaler.py:489
|
|
||||||
msgid "Subprocess execution ran into an error"
|
|
||||||
msgstr "子进程执行遇到错误"
|
|
||||||
|
|
||||||
#: upscaler.py:523
|
|
||||||
msgid "Loading files into processing queue"
|
|
||||||
msgstr "正在将文件添加到处理队列中"
|
|
||||||
|
|
||||||
#: upscaler.py:524
|
|
||||||
msgid "Input path(s): {}"
|
|
||||||
msgstr "输入路径:{}"
|
|
||||||
|
|
||||||
#: upscaler.py:576
|
|
||||||
msgid "File MIME type: {}"
|
|
||||||
msgstr "文件 MIME 类型:{}"
|
|
||||||
|
|
||||||
#: upscaler.py:601
|
|
||||||
msgid "File {} ({}) neither an image nor a video"
|
|
||||||
msgstr "文件 {} ({}) 既不是图片也不是视频"
|
|
||||||
|
|
||||||
#: upscaler.py:605
|
|
||||||
msgid "Skipping this file"
|
|
||||||
msgstr "将跳过此文件"
|
|
||||||
|
|
||||||
#: upscaler.py:640
|
|
||||||
msgid "Loaded files into processing queue"
|
|
||||||
msgstr "文件已添加到处理队列"
|
|
||||||
|
|
||||||
#: upscaler.py:643
|
|
||||||
msgid "Input file: {}"
|
|
||||||
msgstr "输入文件:{}"
|
|
||||||
|
|
||||||
#: upscaler.py:661
|
|
||||||
msgid "Reading file information"
|
|
||||||
msgstr "正在读取视频信息"
|
|
||||||
|
|
||||||
#: upscaler.py:670
|
|
||||||
msgid "Starting upscaling image"
|
|
||||||
msgstr "开始放大图像"
|
|
||||||
|
|
||||||
#: upscaler.py:684
|
|
||||||
msgid "Starting upscaling video/GIF"
|
|
||||||
msgstr "开始放大视频/GIF"
|
|
||||||
|
|
||||||
#: upscaler.py:695
|
|
||||||
msgid "Aborting: No video stream found"
|
|
||||||
msgstr "程序中止:文件中未找到视频流"
|
|
||||||
|
|
||||||
#: upscaler.py:708
|
|
||||||
msgid "Getting total number of frames in the file"
|
|
||||||
msgstr "正在获取文件中的总帧数"
|
|
||||||
|
|
||||||
#: upscaler.py:723
|
|
||||||
msgid "Calculating scaling parameters"
|
|
||||||
msgstr "正在计算缩放参数"
|
|
||||||
|
|
||||||
#: upscaler.py:797
|
|
||||||
msgid "Framerate: {}"
|
|
||||||
msgstr "帧率:{}"
|
|
||||||
|
|
||||||
#: upscaler.py:798
|
|
||||||
msgid "Width: {}"
|
|
||||||
msgstr "宽:{}"
|
|
||||||
|
|
||||||
#: upscaler.py:799
|
|
||||||
msgid "Height: {}"
|
|
||||||
msgstr "高:{}"
|
|
||||||
|
|
||||||
#: upscaler.py:801
|
|
||||||
msgid "Total number of frames: {}"
|
|
||||||
msgstr "总帧数:{}"
|
|
||||||
|
|
||||||
#: upscaler.py:803
|
|
||||||
msgid "Output width: {}"
|
|
||||||
msgstr "输出宽度:{}"
|
|
||||||
|
|
||||||
#: upscaler.py:804
|
|
||||||
msgid "Output height: {}"
|
|
||||||
msgstr "输出高度:{}"
|
|
||||||
|
|
||||||
#: upscaler.py:805
|
|
||||||
msgid "Required scale ratio: {}"
|
|
||||||
msgstr "需要的缩放比例:{}"
|
|
||||||
|
|
||||||
#: upscaler.py:807
|
|
||||||
msgid "Upscaling jobs queue: {}"
|
|
||||||
msgstr "放大工作队列:{}"
|
|
||||||
|
|
||||||
#: upscaler.py:834
|
|
||||||
msgid "Unsupported pixel format: {}"
|
|
||||||
msgstr "不支持的像素格式:{}"
|
|
||||||
|
|
||||||
#: upscaler.py:843
|
|
||||||
msgid "Starting to upscale extracted frames"
|
|
||||||
msgstr "开始对提取的帧进行放大"
|
|
||||||
|
|
||||||
#: upscaler.py:860
|
|
||||||
msgid "Upscaling completed"
|
|
||||||
msgstr "放大完成"
|
|
||||||
|
|
||||||
#: upscaler.py:862
|
|
||||||
msgid "Average processing speed: {} seconds per frame"
|
|
||||||
msgstr "平均处理速度:{} 秒每帧"
|
|
||||||
|
|
||||||
#: upscaler.py:868
|
|
||||||
msgid "Lanczos downscaling frames"
|
|
||||||
msgstr "正在使用 Lanczos 算法缩放图像"
|
|
||||||
|
|
||||||
#: upscaler.py:880
|
|
||||||
msgid "Downscaling"
|
|
||||||
msgstr "正在缩放图像"
|
|
||||||
|
|
||||||
#: upscaler.py:905
|
|
||||||
msgid "Exporting image"
|
|
||||||
msgstr "正在导出图像"
|
|
||||||
|
|
||||||
#: upscaler.py:918
|
|
||||||
msgid "Converting extracted frames into GIF image"
|
|
||||||
msgstr "正在将提取的帧转换为 GIF"
|
|
||||||
|
|
||||||
#: upscaler.py:931 upscaler.py:944
|
|
||||||
msgid "Conversion completed"
|
|
||||||
msgstr "转换已完成"
|
|
||||||
|
|
||||||
#: upscaler.py:936
|
|
||||||
msgid "Converting extracted frames into video"
|
|
||||||
msgstr "正在将提取的帧转换为视频"
|
|
||||||
|
|
||||||
#: upscaler.py:949
|
|
||||||
msgid "Migrating audio, subtitles and other streams to upscaled video"
|
|
||||||
msgstr "正在将音频、字幕和其他流迁移到放大后的视频"
|
|
||||||
|
|
||||||
#: upscaler.py:966
|
|
||||||
msgid "Failed to migrate streams"
|
|
||||||
msgstr "迁移流失败"
|
|
||||||
|
|
||||||
#: upscaler.py:968
|
|
||||||
msgid "Trying to output video without additional streams"
|
|
||||||
msgstr "正在尝试输出不含其他流的视频"
|
|
||||||
|
|
||||||
#: upscaler.py:991
|
|
||||||
msgid "Output video file exists"
|
|
||||||
msgstr "输出目标文件已存在"
|
|
||||||
|
|
||||||
#: upscaler.py:1000
|
|
||||||
msgid "Created temporary directory to contain file"
|
|
||||||
msgstr "为文件创建了临时目录"
|
|
||||||
|
|
||||||
#: upscaler.py:1005
|
|
||||||
msgid "Writing intermediate file to: {}"
|
|
||||||
msgstr "正在将中间视频文件写入至:{}"
|
|
||||||
|
|
||||||
#: video2x.py:89
|
|
||||||
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:117
|
|
||||||
msgid "Video2X Options"
|
|
||||||
msgstr "Video2X 选项"
|
|
||||||
|
|
||||||
#: video2x.py:120
|
|
||||||
msgid "show this help message and exit"
|
|
||||||
msgstr "显示此帮助消息并退出"
|
|
||||||
|
|
||||||
#: video2x.py:133
|
|
||||||
msgid "source video file/directory"
|
|
||||||
msgstr "源视频文件/目录"
|
|
||||||
|
|
||||||
#: video2x.py:141
|
|
||||||
msgid "output video file/directory"
|
|
||||||
msgstr "输出视频文件/目录"
|
|
||||||
|
|
||||||
#: video2x.py:149
|
|
||||||
msgid "Video2X config file path"
|
|
||||||
msgstr "Video2X 配置文件路径"
|
|
||||||
|
|
||||||
#: video2x.py:154
|
|
||||||
msgid "log file path"
|
|
||||||
msgstr "日志文件路径"
|
|
||||||
|
|
||||||
#: video2x.py:159
|
|
||||||
msgid "display version, lawful information and exit"
|
|
||||||
msgstr "显示版本和法律信息并退出"
|
|
||||||
|
|
||||||
#: video2x.py:164
|
|
||||||
msgid "Upscaling Options"
|
|
||||||
msgstr "视频放大选项"
|
|
||||||
|
|
||||||
#: video2x.py:167
|
|
||||||
msgid "scaling ratio"
|
|
||||||
msgstr "缩放比"
|
|
||||||
|
|
||||||
#: video2x.py:171
|
|
||||||
msgid "output width"
|
|
||||||
msgstr "输出宽度"
|
|
||||||
|
|
||||||
#: video2x.py:175
|
|
||||||
msgid "output height"
|
|
||||||
msgstr "输出高度"
|
|
||||||
|
|
||||||
#: video2x.py:181
|
|
||||||
msgid "upscaling driver"
|
|
||||||
msgstr "视频放大驱动"
|
|
||||||
|
|
||||||
#: video2x.py:189
|
|
||||||
msgid "number of processes to use for upscaling"
|
|
||||||
msgstr "并发进程数"
|
|
||||||
|
|
||||||
#: video2x.py:197
|
|
||||||
msgid "preserve extracted and upscaled frames"
|
|
||||||
msgstr "保留提取的和放大的帧"
|
|
||||||
|
|
||||||
#: video2x.py:241
|
|
||||||
msgid "This file cannot be imported"
|
|
||||||
msgstr "此文件无法被当作模块导入"
|
|
||||||
|
|
||||||
#: video2x.py:259
|
|
||||||
msgid "Specify either scaling ratio or scaling resolution, not both"
|
|
||||||
msgstr "您只能指定缩放比或输出分辨率两者之一"
|
|
||||||
|
|
||||||
#: video2x.py:265
|
|
||||||
msgid "Either scaling ratio or scaling resolution needs to be specified"
|
|
||||||
msgstr "必须指定缩放比或输出分辨率"
|
|
||||||
|
|
||||||
#: video2x.py:353
|
|
||||||
msgid "Program completed, taking {} seconds"
|
|
||||||
msgstr "程序执行完毕,总计花费 {} 秒"
|
|
||||||
|
|
||||||
#: video2x.py:360
|
|
||||||
msgid "An exception has occurred"
|
|
||||||
msgstr "发生了异常"
|
|
||||||
|
|
||||||
#: video2x.py:375
|
|
||||||
msgid "The error log file can be found at: {}"
|
|
||||||
msgstr "错误日志已被保存到:{}"
|
|
||||||
|
|
||||||
#~ msgid "disable logging"
|
|
||||||
#~ msgstr "禁用日志"
|
|
||||||
|
|
||||||
#~ msgid "Only one of scaling width and scaling height is specified"
|
|
||||||
#~ msgstr "输出高度和宽度仅有其中一项被指定"
|
|
||||||
|
|
||||||
#~ msgid "Redirecting console logs to {}"
|
|
||||||
#~ msgstr "将控制台日志重定向到 {}"
|
|
||||||
|
|
||||||
#~ msgid "Upscaling Progress"
|
|
||||||
#~ msgstr "放大进度"
|
|
||||||
|
|
||||||
#~ msgid "Loading files from multiple paths"
|
|
||||||
#~ msgstr "正在从多个路径中导入文件"
|
|
||||||
|
|
||||||
#~ msgid "Loading single file"
|
|
||||||
#~ msgstr "正在导入单个文件"
|
|
||||||
|
|
||||||
#~ msgid "Loading files from directory"
|
|
||||||
#~ msgstr "正在从文件夹中导入文件"
|
|
||||||
|
|
||||||
#~ msgid "Anime4KCPP doesn't yet support GIF processing"
|
|
||||||
#~ msgstr "Anime4KCPP 尚不支持GIF处理"
|
|
||||||
|
|
||||||
#~ msgid "Starting to upscale video with Anime4KCPP"
|
|
||||||
#~ msgstr "开始用 Anime4KCPP 放大视频"
|
|
||||||
|
|
||||||
#~ 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 must specify both width and height"
|
|
||||||
#~ msgstr "您必须同时指定宽度和高度"
|
|
@ -1,73 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
Name: Video2X Upscale Progress Monitor
|
|
||||||
Author: K4YT3X
|
|
||||||
Date Created: May 7, 2020
|
|
||||||
Last Modified: September 9, 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
|
|
||||||
|
|
||||||
with tqdm(
|
|
||||||
total=self.upscaler.total_frames,
|
|
||||||
ascii=True,
|
|
||||||
desc=_("Processing: {} (pass {}/{})").format(
|
|
||||||
self.upscaler.current_input_file.name,
|
|
||||||
self.upscaler.current_pass,
|
|
||||||
len(self.upscaler.scaling_jobs),
|
|
||||||
),
|
|
||||||
) 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.extracted_frame_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.
@ -1,85 +0,0 @@
|
|||||||
.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.
|
|
@ -1,211 +0,0 @@
|
|||||||
.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.
@ -1,84 +0,0 @@
|
|||||||
.Language=Russian,Russian (<28>ãá᪨©)
|
|
||||||
.PluginContents=<3D>« £¨ 7-Zip
|
|
||||||
|
|
||||||
@Contents
|
|
||||||
$^#7-Zip Plugin 19.00#
|
|
||||||
$^#Copyright (c) 1999-2019 Igor Pavlov#
|
|
||||||
<20>â®â ¬®¤ã«ì FAR ¯®§¢®«ï¥â à ¡®â âì á # à娢 ¬¨#. „«ï ¯®«ì§®¢ ⥫ï
|
|
||||||
ä ©«ë ¢ à娢 å ¥ ®â«¨ç îâáï ®â ä ©«®¢ ¢ ¯ ¯ª å.
|
|
||||||
|
|
||||||
|
|
||||||
~<7E> ᯠª®¢ª ä ©«®¢ ¨§ à娢 ~@Extract@
|
|
||||||
|
|
||||||
~„®¡ ¢«¥¨¥ ä ©«®¢ ª à娢ã~@Update@
|
|
||||||
|
|
||||||
~<7E> à ¬¥âàë à ¡®âë á à娢 ¬¨~@Config@
|
|
||||||
|
|
||||||
|
|
||||||
Web site: #www.7-zip.org#
|
|
||||||
|
|
||||||
@Extract
|
|
||||||
$ #<23> ᯠª®¢ª ä ©«®¢ ¨§ à娢 #
|
|
||||||
‚ í⮬ ¤¨ «®£¥ ¢ë ¬®¦¥â¥ ¢¢¥á⨠¯ãâì ¤«ï à ᯠª®¢ª¨ ä ©«®¢ ¨ § ¤ âì
|
|
||||||
०¨¬ à ᯠª®¢ª¨.
|
|
||||||
|
|
||||||
<20>ãâ¨
|
|
||||||
|
|
||||||
#<23>®«ë¥ ¯ãâ¨# <20> ᯠª®¢ âì ä ©«ë á ¯®«ë¬¨ ¯ãâﬨ.
|
|
||||||
|
|
||||||
#Žâ®á¨â¥«ìë¥ ¯ãâ¨# <20> ᯠª®¢ âì á ®â®á¨â¥«ì묨 ¯ãâﬨ.
|
|
||||||
|
|
||||||
#<23>¥§ ¯ã⥩# <20> ᯠª®¢ âì ¡¥§ ¯ã⥩.
|
|
||||||
|
|
||||||
|
|
||||||
<20>¥à¥§ ¯¨áì
|
|
||||||
|
|
||||||
#‘¯à 訢 âì ¯®¤â¢¥à¦¤¥¨¥# ‘¯à 訢 âì ¯®¤â¢¥à¦¤¥¨¥
|
|
||||||
¯¥à¥§ ¯¨áì áãé¥áâ¢ãî饣® ä ©« .
|
|
||||||
|
|
||||||
#<23>¥§ ¯®¤â¢¥à¦¤¥¨ï# ‡ ¬¥é âì áãé¥áâ¢ãî騩 ä ©«
|
|
||||||
¡¥§ ¯®¤â¢¥à¦¤¥¨ï.
|
|
||||||
|
|
||||||
#<23>யã᪠âì# <20>யã᪠âì áãé¥áâ¢ãî騥 ä ©«ë.
|
|
||||||
|
|
||||||
|
|
||||||
<20> ᯠª®¢ âì
|
|
||||||
|
|
||||||
#‚ë¡à ë¥ ä ©«ë# <20> ᯠª®¢ âì ⮫쪮 ¢ë¤¥«¥ë¥ ä ©«ë ¨§ à娢 .
|
|
||||||
|
|
||||||
#‚á¥ ä ©«ë# <20> ᯠª®¢ âì ¢á¥ ä ©«ë ¨§ à娢 .
|
|
||||||
|
|
||||||
@Update
|
|
||||||
$ #„®¡ ¢«¥¨¥ ä ©«®¢ ª à娢ã#
|
|
||||||
|
|
||||||
‚ í⮬ ¤¨ «®£¥ ¢ë ¬®¦¥â¥ § ¤ âì ०¨¬ 㯠ª®¢ª¨.
|
|
||||||
|
|
||||||
|
|
||||||
Œ¥â®¤ ᦠâ¨ï:
|
|
||||||
|
|
||||||
#<23>¥§ ᦠâ¨ï# ” ©«ë ¡ã¤ãâ ᪮¯¨à®¢ ë ¡¥§ ᦠâ¨ï.
|
|
||||||
|
|
||||||
#<23>®à¬ «ì®¥ ᦠ⨥# ” ©«ë ¡ã¤ãâ ᦠâë.
|
|
||||||
|
|
||||||
#Œ ªá¨¬ «ì®¥ ᦠ⨥# ” ©«ë ¡ã¤ãâ ᦠâë á ¬ ªá¨¬ «ì®©
|
|
||||||
á⥯¥ìî ᦠâ¨ï.
|
|
||||||
|
|
||||||
|
|
||||||
<20>¥¦¨¬ ¨§¬¥¥¨ï:
|
|
||||||
|
|
||||||
#„®¡ ¢¨âì ¨ § ¬¥¨âì# „®¡ ¢¨âì ¢á¥ ¢ë¡à ë¥ ä ©«ë ¢ à娢.
|
|
||||||
|
|
||||||
#Ž¡®¢¨âì ¨ ¤®¡ ¢¨âì# Ž¡®¢¨âì ãáâ ॢ訥 ä ©«ë ¢ à娢¥ ¨
|
|
||||||
¤®¡ ¢¨âì ä ©«ë, ª®â®àëå ¥â ¢ à娢¥.
|
|
||||||
|
|
||||||
#Ž¡®¢¨âì# Ž¡®¢¨âì ãáâ ॢ訥 ä ©«ë ¢ à娢¥.
|
|
||||||
|
|
||||||
#‘¨åந§¨à®¢ âì# ‘¨åந§¨à®¢ âì ᮤ¥à¦¨¬®¥ à娢
|
|
||||||
á ¢ë¡à 묨 ä ©« ¬¨.
|
|
||||||
|
|
||||||
|
|
||||||
@Config
|
|
||||||
$ #<23> à ¬¥âàë à ¡®âë á ¯« £¨®¬ 7-Zip#
|
|
||||||
‚ í⮬ ¤¨ «®£¥ ¢ë ¬®¦¥â¥ ¨§¬¥¨âì á«¥¤ãî騥 ¯ à ¬¥âàë:
|
|
||||||
|
|
||||||
#<23>« £¨ ¨á¯®«ì§ã¥âáï ¯® 㬮«ç ¨î# <20>« £¨ ¨á¯®«ì§ã¥âáï ¯® 㬮«ç ¨î
|
|
@ -1,211 +0,0 @@
|
|||||||
.Language=Russian,Russian (<28>ãá᪨©)
|
|
||||||
|
|
||||||
"<22>த®«¦¨âì"
|
|
||||||
"&Žâ¬¥¨âì"
|
|
||||||
|
|
||||||
"<22>।ã¯à¥¦¤¥¨¥"
|
|
||||||
"Žè¨¡ª "
|
|
||||||
|
|
||||||
"”®à¬ â"
|
|
||||||
|
|
||||||
"‘¢®©á⢠"
|
|
||||||
|
|
||||||
"„ "
|
|
||||||
"<22>¥â"
|
|
||||||
|
|
||||||
"‚¢®¤ ¯ ஫ï"
|
|
||||||
"‚¢¥¤¨â¥ ¯ ஫ì"
|
|
||||||
|
|
||||||
"<22> ᯠª®¢ª "
|
|
||||||
"&<26> ᯠª®¢ âì ¢"
|
|
||||||
|
|
||||||
"<22>ãâ¨"
|
|
||||||
"<22>®&«ë¥ ¯ãâ¨"
|
|
||||||
"Ž&â®á¨â¥«ìë¥ ¯ãâ¨"
|
|
||||||
"&<26>¥§ ¯ã⥩"
|
|
||||||
|
|
||||||
"<22>¥à¥§ ¯¨áì"
|
|
||||||
"&‘¯à 訢 âì ¯®¤â¢¥à¦¤¥¨¥"
|
|
||||||
"<22>&¥§ ¯®¤â¢¥à¦¤¥¨ï"
|
|
||||||
"<22>ய&ã᪠âì"
|
|
||||||
"<22>¥à¥¨¬¥®¢ âì ¢â®¬."
|
|
||||||
"<22>¥à¥¨¬. ¢â®¬. áãé¥áâ¢."
|
|
||||||
|
|
||||||
"<22> ᯠª®¢ âì"
|
|
||||||
"‚&ë¡à ë¥ ä ©«ë"
|
|
||||||
"‚ᥠ&ä ©«ë"
|
|
||||||
|
|
||||||
"&<26> ஫ì"
|
|
||||||
|
|
||||||
"<22>& ᯠª®¢ âì"
|
|
||||||
"&Žâ¬¥¨âì"
|
|
||||||
|
|
||||||
"<22>¥¢®§¬®¦® ®âªàëâì ä ©« '%s'."
|
|
||||||
|
|
||||||
"<22>¥¯®¤¤¥à¦¨¢ ¥¬ë© ¬¥â®¤ ᦠâ¨ï ¤«ï ä ©« '%s'."
|
|
||||||
"Žè¨¡ª CRC ¢ '%s'."
|
|
||||||
"Žè¨¡ª ¢ ¤ ëå ¢ '%s'."
|
|
||||||
"Žè¨¡ª CRC ¤«ï § è¨ä஢ ®£® ä ©« '%s'. <20>¥¢¥àë© ¯ ஫ì?"
|
|
||||||
"Žè¨¡ª ¢ ¤ ëå § è¨ä஢ ®£® ä ©« '%s'. <20>¥¢¥àë© ¯ ஫ì?"
|
|
||||||
|
|
||||||
"<22>®¤â¢¥à¤¨â¥ § ¬¥ã ä ©« "
|
|
||||||
"<22> ¯ª 㦥 ᮤ¥à¦¨â ®¡à ¡ âë¢ ¥¬ë© ä ©«."
|
|
||||||
"‡ ¬¥¨âì áãé¥áâ¢ãî騩 ä ©«"
|
|
||||||
"á«¥¤ãî騬 ä ©«®¬"
|
|
||||||
|
|
||||||
"¡ ©â"
|
|
||||||
"¨§¬¥¥"
|
|
||||||
|
|
||||||
|
|
||||||
"&„ "
|
|
||||||
"„ ¤«ï &¢á¥å"
|
|
||||||
"&<26>¥â"
|
|
||||||
"<22>¥â ¤«ï ¢&á¥å"
|
|
||||||
"<22>¥à¥¨¬¥®¢ âì ¢â®¬ â¨ç¥áª¨"
|
|
||||||
"&Žâ¬¥¨âì"
|
|
||||||
|
|
||||||
|
|
||||||
"„«ï í⮣® à娢 ®¯¥à 樨 ¨§¬¥¥¨ï ¥ ¯®¤¤¥à¦¨¢ îâáï."
|
|
||||||
|
|
||||||
|
|
||||||
"“¤ «¥¨¥ ¨§ à娢 "
|
|
||||||
"“¤ «¨âì \"%.40s\" ¨§ à娢 "
|
|
||||||
"“¤ «¨âì ¢ë¡à ë¥ ä ©«ë ¨§ à娢 "
|
|
||||||
"“¤ «¨âì %d ä ©«®¢ ¨§ à娢 "
|
|
||||||
"“¤ «¥¨¥"
|
|
||||||
"Žâ¬¥ "
|
|
||||||
|
|
||||||
"„®¡ ¢¨âì ä ©«ë ª à娢ã"
|
|
||||||
|
|
||||||
"„®¡ ¢¨âì ª %s & à娢ã"
|
|
||||||
|
|
||||||
"Œ¥â®¤ ᦠâ¨ï"
|
|
||||||
"<22>¥§ ᦠâ¨ï"
|
|
||||||
"‘ª®à®á⮩"
|
|
||||||
"<22>ëáâàë©"
|
|
||||||
"<22>®à¬ «ìë©"
|
|
||||||
"Œ ªá¨¬ «ìë©"
|
|
||||||
"“«ìâà "
|
|
||||||
|
|
||||||
"<22>¥¦¨¬ ¨§¬¥¥¨ï"
|
|
||||||
"„®¡ ¢¨âì ¨ § ¬¥¨âì"
|
|
||||||
"Ž¡®¢¨âì ¨ ¤®¡ ¢¨âì"
|
|
||||||
"Ž¡®¢¨âì"
|
|
||||||
"‘¨åந§¨à®¢ âì"
|
|
||||||
|
|
||||||
"&„®¡ ¢¨âì"
|
|
||||||
"€&à娢 â®à"
|
|
||||||
|
|
||||||
"‚ë¡®à à娢®£® ä®à¬ â "
|
|
||||||
|
|
||||||
"<22>®¤®¦¤¨â¥"
|
|
||||||
"—⥨¥ à娢 "
|
|
||||||
"<22> ᯠª®¢ª "
|
|
||||||
"“¤ «¥¨¥"
|
|
||||||
"ˆ§¬¥¥¨¥"
|
|
||||||
|
|
||||||
"<22>¥à¥¬¥é¥¨¥ ä ©«®¢ ¥ ¯®¤¤¥à¦¨¢ ¥âáï"
|
|
||||||
|
|
||||||
"7-Zip"
|
|
||||||
"7-Zip (¤®¡ ¢¨âì ¢ à娢)"
|
|
||||||
|
|
||||||
"7-Zip configuration"
|
|
||||||
|
|
||||||
"<22>« £¨ ¨á¯®«ì§ã¥âáï ¯® 㬮«ç ¨î"
|
|
||||||
|
|
||||||
"0"
|
|
||||||
"1"
|
|
||||||
"2"
|
|
||||||
"<22>ãâì"
|
|
||||||
"ˆ¬ï"
|
|
||||||
"<22> áè¨à¥¨¥"
|
|
||||||
"<22> ¯ª "
|
|
||||||
"<22> §¬¥à"
|
|
||||||
"‘¦ âë©"
|
|
||||||
"€âਡãâë"
|
|
||||||
"‘®§¤ "
|
|
||||||
"Žâªàëâ"
|
|
||||||
"ˆ§¬¥¥"
|
|
||||||
"<22>¥¯à¥àë¢ë©"
|
|
||||||
"Š®¬¬¥â ਩"
|
|
||||||
"‡ è¨ä஢ "
|
|
||||||
"<22> §¡¨â „®"
|
|
||||||
"<22> §¡¨â <20>®á«¥"
|
|
||||||
"‘«®¢ àì"
|
|
||||||
"CRC"
|
|
||||||
"’¨¯"
|
|
||||||
"€â¨"
|
|
||||||
"Œ¥â®¤"
|
|
||||||
"‘¨á⥬ "
|
|
||||||
"” ©«®¢ ï ‘¨á⥬ "
|
|
||||||
"<22>®«ì§®¢ ⥫ì"
|
|
||||||
"ƒà㯯 "
|
|
||||||
"<22>«®ª"
|
|
||||||
"Š®¬¬¥â ਩"
|
|
||||||
"<22>®§¨æ¨ï"
|
|
||||||
"<22>ãâì"
|
|
||||||
"<22> ¯®ª"
|
|
||||||
"” ©«®¢"
|
|
||||||
"‚¥àá¨ï"
|
|
||||||
"’®¬"
|
|
||||||
"Œ®£®â®¬ë©"
|
|
||||||
"‘¬¥é¥¨¥"
|
|
||||||
"‘áë«®ª"
|
|
||||||
"<22>«®ª®¢"
|
|
||||||
"’®¬®¢"
|
|
||||||
"Time Type"
|
|
||||||
"64-bit"
|
|
||||||
"Big-endian"
|
|
||||||
"<22>à®æ¥áá®à"
|
|
||||||
"”¨§¨ç¥áª¨© <20> §¬¥à"
|
|
||||||
"<22> §¬¥à ‡ £®«®¢ª®¢"
|
|
||||||
"Š®âà. ‘㬬 "
|
|
||||||
"• à ªâ¥à¨á⨪¨"
|
|
||||||
"‚¨àâã «ìë© €¤à¥á"
|
|
||||||
"ID"
|
|
||||||
"Š®à®âª®¥ ¨¬ï"
|
|
||||||
"<22>à®£à ¬¬ "
|
|
||||||
"<22> §¬¥à ᥪâ®à "
|
|
||||||
"<22>¥¦¨¬"
|
|
||||||
"‘¨¬¢®«ì ï ‘á뫪 "
|
|
||||||
"Žè¨¡ª "
|
|
||||||
"…¬ª®áâì"
|
|
||||||
"‘¢®¡®¤®"
|
|
||||||
"<22> §¬¥à ª« áâ¥à "
|
|
||||||
"Œ¥âª "
|
|
||||||
"‹®ª «ì®¥ ¨¬ï"
|
|
||||||
"<22>஢ ©¤¥à"
|
|
||||||
"NT <20>¥§®¯ á®áâì"
|
|
||||||
"€«ìâ¥à â¨¢ë© <20>®â®ª"
|
|
||||||
"Aux"
|
|
||||||
"“¤ «¥ë©"
|
|
||||||
"„¥à¥¢®"
|
|
||||||
"SHA-1"
|
|
||||||
"SHA-256"
|
|
||||||
"’¨¯ Žè¨¡ª¨"
|
|
||||||
"Žè¨¡ª¨"
|
|
||||||
"Žè¨¡ª¨"
|
|
||||||
"<22>।ã¯à¥¦¤¥¨ï"
|
|
||||||
"<22>।ã¯à¥¦¤¥¨¥"
|
|
||||||
"<22>®â®ª¨"
|
|
||||||
"€«ìâ¥à â¨¢ë¥ <20>®â®ª¨"
|
|
||||||
"<22> §¬¥à €«ìâ¥à ⨢ëå ¯®â®ª®¢"
|
|
||||||
"‚¨àâã «ìë© <20> §¬¥à"
|
|
||||||
"<22> ᯠª®¢ ë© <20> §¬¥à"
|
|
||||||
"Ž¡é¨© ”¨§¨ç¥áª¨© <20> §¬¥à"
|
|
||||||
"<22>®¬¥à ’®¬ "
|
|
||||||
"<22>®¤â¨¯"
|
|
||||||
"Š®à®âª¨© Š®¬¬¥â ਩"
|
|
||||||
"Š®¤®¢ ï ‘âà ¨æ "
|
|
||||||
"Is not archive type"
|
|
||||||
"Physical Size can't be detected"
|
|
||||||
"Zeros Tail Is Allowed"
|
|
||||||
"<22> §¬¥à Žáâ ⪠"
|
|
||||||
"<22> §¬¥à ‚áâ஥®£® <20>«®ª "
|
|
||||||
"‘á뫪 "
|
|
||||||
"†¥áâª ï ‘á뫪 "
|
|
||||||
"iNode"
|
|
||||||
"ID <20>®â®ª "
|
|
||||||
"’®«ìª® ¤«ï ç⥨ï"
|
|
||||||
"Out Name"
|
|
||||||
"Copy Link"
|
|
@ -1,67 +0,0 @@
|
|||||||
; 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="*"
|
|
||||||
|
|
@ -1,67 +0,0 @@
|
|||||||
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"="*"
|
|
@ -1,67 +0,0 @@
|
|||||||
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.
|
|
@ -1,31 +0,0 @@
|
|||||||
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/
|
|
||||||
|
|
@ -1,111 +0,0 @@
|
|||||||
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
|
|
@ -1,124 +0,0 @@
|
|||||||
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.
@ -1,80 +0,0 @@
|
|||||||
# -----------------------------------------------------------------------------
|
|
||||||
# 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",
|
|
||||||
]
|
|
@ -1,10 +1,6 @@
|
|||||||
avalon_framework
|
ffmpeg-python
|
||||||
colorama
|
loguru
|
||||||
patool
|
opencv-python
|
||||||
pillow
|
pillow
|
||||||
pyqt5
|
rich
|
||||||
python-magic-bin; platform_system == "Windows"
|
|
||||||
python-magic; platform_system != "Windows"
|
|
||||||
pyyaml
|
|
||||||
requests
|
|
||||||
tqdm
|
tqdm
|
1031
video2x/upscaler.py
1031
video2x/upscaler.py
File diff suppressed because it is too large
Load Diff
@ -1,379 +0,0 @@
|
|||||||
# SOME DESCRIPTIVE TITLE.
|
|
||||||
# Copyright (C) YEAR ORGANIZATION
|
|
||||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
|
||||||
#
|
|
||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
|
||||||
"POT-Creation-Date: 2021-01-23 16:45-0500\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:40
|
|
||||||
msgid "Processing: {} (pass {}/{})"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:160
|
|
||||||
msgid "Specified or default cache directory is a file/link"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:167
|
|
||||||
msgid "Creating cache directory {}"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:174
|
|
||||||
msgid "Unable to create {}"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:183
|
|
||||||
msgid "Extracted frames are being saved to: {}"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:189
|
|
||||||
msgid "Upscaled frames are being saved to: {}"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:203
|
|
||||||
msgid "Cleaning up cache directory: {}"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:208
|
|
||||||
msgid "Unable to delete: {}"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:214 upscaler.py:239 upscaler.py:250
|
|
||||||
msgid "Input and output path type mismatch"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:215
|
|
||||||
msgid "Input is multiple files but output is not directory"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:220
|
|
||||||
msgid "Input path {} is neither a file nor a directory"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:230 upscaler.py:256
|
|
||||||
msgid "Input directory and output directory cannot be the same"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:240
|
|
||||||
msgid "Input is single file but output is directory"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:243
|
|
||||||
msgid "No suffix found in output file path"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:244
|
|
||||||
msgid "Suffix must be specified"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:251
|
|
||||||
msgid "Input is directory but output is existing single file"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:264
|
|
||||||
msgid "Input path is neither a file nor a directory"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:280
|
|
||||||
msgid "FFmpeg or FFprobe cannot be found under the specified path"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:282 upscaler.py:295
|
|
||||||
msgid "Please check the configuration file settings"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:294
|
|
||||||
msgid "Specified driver executable directory doesn't exist"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:323
|
|
||||||
msgid "Failed to parse driver argument: {}"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:346
|
|
||||||
msgid "Unrecognized driver: {}"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:397
|
|
||||||
msgid "Starting progress monitor"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:402
|
|
||||||
msgid "Starting upscaled image cleaner"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:413 upscaler.py:432
|
|
||||||
msgid "Killing progress monitor"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:416 upscaler.py:435
|
|
||||||
msgid "Killing upscaled image cleaner"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:439
|
|
||||||
msgid "Terminating all processes"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:445
|
|
||||||
msgid "Main process waiting for subprocesses to exit"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:465 upscaler.py:475
|
|
||||||
msgid "Subprocess {} exited with code {}"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:484
|
|
||||||
msgid "Stop signal received"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:489
|
|
||||||
msgid "Subprocess execution ran into an error"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:523
|
|
||||||
msgid "Loading files into processing queue"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:524
|
|
||||||
msgid "Input path(s): {}"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:576
|
|
||||||
msgid "File MIME type: {}"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:601
|
|
||||||
msgid "File {} ({}) neither an image nor a video"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:605
|
|
||||||
msgid "Skipping this file"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:640
|
|
||||||
msgid "Loaded files into processing queue"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:643
|
|
||||||
msgid "Input file: {}"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:661
|
|
||||||
msgid "Reading file information"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:670
|
|
||||||
msgid "Starting upscaling image"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:684
|
|
||||||
msgid "Starting upscaling video/GIF"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:695
|
|
||||||
msgid "Aborting: No video stream found"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:708
|
|
||||||
msgid "Getting total number of frames in the file"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:723
|
|
||||||
msgid "Calculating scaling parameters"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:797
|
|
||||||
msgid "Framerate: {}"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:798
|
|
||||||
msgid "Width: {}"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:799
|
|
||||||
msgid "Height: {}"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:801
|
|
||||||
msgid "Total number of frames: {}"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:803
|
|
||||||
msgid "Output width: {}"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:804
|
|
||||||
msgid "Output height: {}"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:805
|
|
||||||
msgid "Required scale ratio: {}"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:807
|
|
||||||
msgid "Upscaling jobs queue: {}"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:834
|
|
||||||
msgid "Unsupported pixel format: {}"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:843
|
|
||||||
msgid "Starting to upscale extracted frames"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:860
|
|
||||||
msgid "Upscaling completed"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:862
|
|
||||||
msgid "Average processing speed: {} seconds per frame"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:868
|
|
||||||
msgid "Lanczos downscaling frames"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:880
|
|
||||||
msgid "Downscaling"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:905
|
|
||||||
msgid "Exporting image"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:918
|
|
||||||
msgid "Converting extracted frames into GIF image"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:931 upscaler.py:944
|
|
||||||
msgid "Conversion completed"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:936
|
|
||||||
msgid "Converting extracted frames into video"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:949
|
|
||||||
msgid "Migrating audio, subtitles and other streams to upscaled video"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:966
|
|
||||||
msgid "Failed to migrate streams"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:968
|
|
||||||
msgid "Trying to output video without additional streams"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:991
|
|
||||||
msgid "Output video file exists"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:1000
|
|
||||||
msgid "Created temporary directory to contain file"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: upscaler.py:1005
|
|
||||||
msgid "Writing intermediate file to: {}"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: video2x.py:89
|
|
||||||
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:117
|
|
||||||
msgid "Video2X Options"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: video2x.py:120
|
|
||||||
msgid "show this help message and exit"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: video2x.py:133
|
|
||||||
msgid "source video file/directory"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: video2x.py:141
|
|
||||||
msgid "output video file/directory"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: video2x.py:149
|
|
||||||
msgid "Video2X config file path"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: video2x.py:154
|
|
||||||
msgid "log file path"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: video2x.py:159
|
|
||||||
msgid "display version, lawful information and exit"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: video2x.py:164
|
|
||||||
msgid "Upscaling Options"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: video2x.py:167
|
|
||||||
msgid "scaling ratio"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: video2x.py:171
|
|
||||||
msgid "output width"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: video2x.py:175
|
|
||||||
msgid "output height"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: video2x.py:181
|
|
||||||
msgid "upscaling driver"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: video2x.py:189
|
|
||||||
msgid "number of processes to use for upscaling"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: video2x.py:197
|
|
||||||
msgid "preserve extracted and upscaled frames"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: video2x.py:241
|
|
||||||
msgid "This file cannot be imported"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: video2x.py:259
|
|
||||||
msgid "Specify either scaling ratio or scaling resolution, not both"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: video2x.py:265
|
|
||||||
msgid "Either scaling ratio or scaling resolution needs to be specified"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: video2x.py:353
|
|
||||||
msgid "Program completed, taking {} seconds"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: video2x.py:360
|
|
||||||
msgid "An exception has occurred"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: video2x.py:375
|
|
||||||
msgid "The error log file can be found at: {}"
|
|
||||||
msgstr ""
|
|
||||||
|
|
@ -10,10 +10,10 @@ __ __ _ _ ___ __ __
|
|||||||
\/ |_| \__,_| \___| \___/ |____| /_/ \_\
|
\/ |_| \__,_| \___| \___/ |____| /_/ \_\
|
||||||
|
|
||||||
|
|
||||||
Name: Video2X Controller
|
Name: Video2X
|
||||||
Creator: K4YT3X
|
Creator: K4YT3X
|
||||||
Date Created: Feb 24, 2018
|
Date Created: Feb 24, 2018
|
||||||
Last Modified: January 23, 2021
|
Last Modified: July 3, 2021
|
||||||
|
|
||||||
Editor: BrianPetkovsek
|
Editor: BrianPetkovsek
|
||||||
Last Modified: June 17, 2019
|
Last Modified: June 17, 2019
|
||||||
@ -49,332 +49,412 @@ smooth and edges sharp.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# local imports
|
# local imports
|
||||||
from bilogger import BiLogger
|
from .decoder import VideoDecoder
|
||||||
from upscaler import AVAILABLE_DRIVERS
|
from .encoder import VideoEncoder
|
||||||
from upscaler import UPSCALER_VERSION
|
from .interpolator import Interpolator
|
||||||
from upscaler import Upscaler
|
from .upscaler import Upscaler
|
||||||
|
|
||||||
# built-in imports
|
# built-in imports
|
||||||
import argparse
|
import argparse
|
||||||
import gettext
|
import math
|
||||||
import importlib
|
import multiprocessing
|
||||||
import locale
|
|
||||||
import os
|
import os
|
||||||
import pathlib
|
import pathlib
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
|
||||||
import time
|
import time
|
||||||
import traceback
|
|
||||||
import yaml
|
|
||||||
|
|
||||||
# third-party imports
|
# third-party imports
|
||||||
from avalon_framework import Avalon
|
from loguru import logger
|
||||||
|
from rich import print
|
||||||
|
from tqdm import tqdm
|
||||||
|
import cv2
|
||||||
|
import ffmpeg
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
# internationalization constants
|
|
||||||
DOMAIN = "video2x"
|
|
||||||
LOCALE_DIRECTORY = pathlib.Path(__file__).parent.absolute() / "locale"
|
|
||||||
|
|
||||||
# getting default locale settings
|
VERSION = "5.0.0"
|
||||||
default_locale, encoding = locale.getdefaultlocale()
|
|
||||||
if default_locale is None:
|
|
||||||
default_locale = "en_US"
|
|
||||||
language = gettext.translation(
|
|
||||||
DOMAIN, LOCALE_DIRECTORY, [default_locale], fallback=True
|
|
||||||
)
|
|
||||||
language.install()
|
|
||||||
_ = language.gettext
|
|
||||||
|
|
||||||
CLI_VERSION = "4.3.3"
|
LEGAL_INFO = """Video2X {}
|
||||||
|
|
||||||
LEGAL_INFO = _(
|
|
||||||
"""Video2X CLI Version: {}
|
|
||||||
Upscaler Version: {}
|
|
||||||
Author: K4YT3X
|
Author: K4YT3X
|
||||||
License: GNU GPL v3
|
License: GNU GPL v3
|
||||||
Github Page: https://github.com/k4yt3x/video2x
|
Github Page: https://github.com/k4yt3x/video2x
|
||||||
Contact: k4yt3x@k4yt3x.com"""
|
Contact: k4yt3x@k4yt3x.com""".format(
|
||||||
).format(CLI_VERSION, UPSCALER_VERSION)
|
VERSION
|
||||||
|
)
|
||||||
|
|
||||||
LOGO = r"""
|
UPSCALING_DRIVERS = [
|
||||||
__ __ _ _ ___ __ __
|
"waifu2x",
|
||||||
\ \ / / (_) | | |__ \ \ \ / /
|
"srmd",
|
||||||
\ \ / / _ __| | ___ ___ ) | \ V /
|
"realsr",
|
||||||
\ \/ / | | / _` | / _ \ / _ \ / / > <
|
]
|
||||||
\ / | | | (_| | | __/ | (_) | / /_ / . \
|
|
||||||
\/ |_| \__,_| \___| \___/ |____| /_/ \_\
|
INTERPOLATION_DRIVERS = ["rife"]
|
||||||
"""
|
|
||||||
|
# fixed scaling ratios supported by the drivers
|
||||||
|
# that only support certain fixed scale ratios
|
||||||
|
DRIVER_FIXED_SCALING_RATIOS = {
|
||||||
|
"waifu2x": [1, 2],
|
||||||
|
"srmd": [2, 3, 4],
|
||||||
|
"realsr": [4],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def parse_arguments():
|
class Video2X:
|
||||||
"""parse CLI arguments"""
|
"""
|
||||||
|
Video2X class
|
||||||
|
|
||||||
|
provides two vital functions:
|
||||||
|
- upscale: perform upscaling on a file
|
||||||
|
- interpolate: perform motion interpolation on a file
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.version = "5.0.0"
|
||||||
|
|
||||||
|
def _get_video_info(self, path: pathlib.Path):
|
||||||
|
"""
|
||||||
|
get video file information with FFmpeg
|
||||||
|
|
||||||
|
:param path pathlib.Path: video file path
|
||||||
|
:raises RuntimeError: raised when video stream isn't found
|
||||||
|
"""
|
||||||
|
# probe video file info
|
||||||
|
logger.info("Reading input video information")
|
||||||
|
for stream in ffmpeg.probe(path)["streams"]:
|
||||||
|
if stream["codec_type"] == "video":
|
||||||
|
video_info = stream
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
raise RuntimeError("unable to find video stream")
|
||||||
|
|
||||||
|
# get total number of frames to be processed
|
||||||
|
total_frames = int(cv2.VideoCapture(str(path)).get(cv2.CAP_PROP_FRAME_COUNT))
|
||||||
|
frame_rate = cv2.VideoCapture(str(path)).get(cv2.CAP_PROP_FPS)
|
||||||
|
|
||||||
|
return video_info["width"], video_info["height"], total_frames, frame_rate
|
||||||
|
|
||||||
|
def _run(
|
||||||
|
self,
|
||||||
|
input_path: pathlib.Path,
|
||||||
|
width: int,
|
||||||
|
height: int,
|
||||||
|
total_frames: int,
|
||||||
|
frame_rate: float,
|
||||||
|
output_path: pathlib.Path,
|
||||||
|
output_width: int,
|
||||||
|
output_height: int,
|
||||||
|
Processor: object,
|
||||||
|
mode: str,
|
||||||
|
processes: int,
|
||||||
|
processing_settings: tuple,
|
||||||
|
):
|
||||||
|
# initialize values
|
||||||
|
self.processor_processes = []
|
||||||
|
self.processing_queue = multiprocessing.Queue()
|
||||||
|
processed_frames = multiprocessing.Manager().list([None] * total_frames)
|
||||||
|
self.processed = multiprocessing.Value("I", 0)
|
||||||
|
|
||||||
|
# set up and start decoder thread
|
||||||
|
logger.info("Starting video decoder")
|
||||||
|
self.decoder = VideoDecoder(
|
||||||
|
input_path,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
frame_rate,
|
||||||
|
self.processing_queue,
|
||||||
|
processing_settings,
|
||||||
|
)
|
||||||
|
self.decoder.start()
|
||||||
|
|
||||||
|
# in interpolate mode, the frame rate is doubled
|
||||||
|
if mode == "upscale":
|
||||||
|
progress = tqdm(total=total_frames, desc=f"UPSC {input_path.name}")
|
||||||
|
# elif mode == "interpolate":
|
||||||
|
else:
|
||||||
|
frame_rate *= 2
|
||||||
|
progress = tqdm(total=total_frames, desc=f"INTERP {input_path.name}")
|
||||||
|
|
||||||
|
# set up and start encoder thread
|
||||||
|
logger.info("Starting video encoder")
|
||||||
|
self.encoder = VideoEncoder(
|
||||||
|
input_path,
|
||||||
|
frame_rate,
|
||||||
|
output_path,
|
||||||
|
output_width,
|
||||||
|
output_height,
|
||||||
|
total_frames,
|
||||||
|
processed_frames,
|
||||||
|
self.processed,
|
||||||
|
)
|
||||||
|
self.encoder.start()
|
||||||
|
|
||||||
|
# create upscaler processes
|
||||||
|
for process_name in range(processes):
|
||||||
|
process = Processor(self.processing_queue, processed_frames)
|
||||||
|
process.name = str(process_name)
|
||||||
|
process.daemon = True
|
||||||
|
process.start()
|
||||||
|
self.processor_processes.append(process)
|
||||||
|
|
||||||
|
# create progress bar
|
||||||
|
|
||||||
|
try:
|
||||||
|
# wait for jobs in queue to deplete
|
||||||
|
while self.encoder.is_alive() is True:
|
||||||
|
for process in self.processor_processes:
|
||||||
|
if not process.is_alive():
|
||||||
|
raise Exception("process died unexpectedly")
|
||||||
|
progress.n = self.processed.value
|
||||||
|
progress.refresh()
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
logger.info("Encoding has completed")
|
||||||
|
progress.n = self.processed.value
|
||||||
|
progress.refresh()
|
||||||
|
|
||||||
|
# if SIGTERM is received or ^C is pressed
|
||||||
|
# TODO: pause and continue here
|
||||||
|
except (SystemExit, KeyboardInterrupt):
|
||||||
|
logger.warning("Exit signal received, terminating")
|
||||||
|
|
||||||
|
finally:
|
||||||
|
# mark processing queue as closed
|
||||||
|
self.processing_queue.close()
|
||||||
|
|
||||||
|
# stop upscaler processes
|
||||||
|
logger.info("Stopping upscaler processes")
|
||||||
|
for process in self.processor_processes:
|
||||||
|
process.terminate()
|
||||||
|
|
||||||
|
# wait for processes to finish
|
||||||
|
for process in self.processor_processes:
|
||||||
|
process.join()
|
||||||
|
|
||||||
|
# ensure both the decoder and the encoder have exited
|
||||||
|
self.decoder.stop()
|
||||||
|
self.encoder.stop()
|
||||||
|
self.decoder.join()
|
||||||
|
self.encoder.join()
|
||||||
|
|
||||||
|
def upscale(
|
||||||
|
self,
|
||||||
|
input_path: pathlib.Path,
|
||||||
|
output_path: pathlib.Path,
|
||||||
|
output_width: int,
|
||||||
|
output_height: int,
|
||||||
|
noise: int,
|
||||||
|
processes: int,
|
||||||
|
threshold: float,
|
||||||
|
driver: str,
|
||||||
|
) -> None:
|
||||||
|
|
||||||
|
# get basic video information
|
||||||
|
width, height, total_frames, frame_rate = self._get_video_info(input_path)
|
||||||
|
|
||||||
|
# automatically calculate output width and height if only one is given
|
||||||
|
if output_width == 0 or output_width is None:
|
||||||
|
output_width = output_height / height * width
|
||||||
|
|
||||||
|
elif output_height == 0 or output_height is None:
|
||||||
|
output_height = output_width / width * height
|
||||||
|
|
||||||
|
# sanitize output width and height to be divisible by 2
|
||||||
|
output_width = int(math.ceil(output_width / 2.0) * 2)
|
||||||
|
output_height = int(math.ceil(output_height / 2.0) * 2)
|
||||||
|
|
||||||
|
# start processing
|
||||||
|
self._run(
|
||||||
|
input_path,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
total_frames,
|
||||||
|
frame_rate,
|
||||||
|
output_path,
|
||||||
|
output_width,
|
||||||
|
output_height,
|
||||||
|
Upscaler,
|
||||||
|
"upscale",
|
||||||
|
processes,
|
||||||
|
(
|
||||||
|
output_width,
|
||||||
|
output_height,
|
||||||
|
noise,
|
||||||
|
threshold,
|
||||||
|
driver,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
def interpolate(
|
||||||
|
self,
|
||||||
|
input_path: pathlib.Path,
|
||||||
|
output_path: pathlib.Path,
|
||||||
|
processes: int,
|
||||||
|
threshold: float,
|
||||||
|
driver: str,
|
||||||
|
) -> None:
|
||||||
|
|
||||||
|
# get video basic information
|
||||||
|
width, height, original_frames, frame_rate = self._get_video_info(input_path)
|
||||||
|
|
||||||
|
# calculate the number of total output frames
|
||||||
|
total_frames = original_frames * 2 - 1
|
||||||
|
|
||||||
|
# start processing
|
||||||
|
self._run(
|
||||||
|
input_path,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
total_frames,
|
||||||
|
frame_rate,
|
||||||
|
output_path,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
Interpolator,
|
||||||
|
"interpolate",
|
||||||
|
processes,
|
||||||
|
(threshold, driver),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_arguments() -> argparse.Namespace:
|
||||||
|
"""
|
||||||
|
parse command line arguments
|
||||||
|
|
||||||
|
:rtype argparse.Namespace: command parsing results
|
||||||
|
"""
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
prog="video2x",
|
prog="video2x",
|
||||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||||
add_help=False,
|
add_help=False,
|
||||||
)
|
)
|
||||||
|
parser.add_argument("--help", action="help", help="show this help message and exit")
|
||||||
# video options
|
parser.add_argument(
|
||||||
video2x_options = parser.add_argument_group(_("Video2X Options"))
|
"-v", "--version", help="show version information and exit", action="store_true"
|
||||||
|
|
||||||
video2x_options.add_argument(
|
|
||||||
"--help", action="help", help=_("show this help message and exit")
|
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
# if help is in arguments list
|
|
||||||
# do not require input and output path to be specified
|
|
||||||
require_input_output = True
|
|
||||||
if "-h" in sys.argv or "--help" in sys.argv:
|
|
||||||
require_input_output = False
|
|
||||||
|
|
||||||
video2x_options.add_argument(
|
|
||||||
"-i",
|
"-i",
|
||||||
"--input",
|
"--input",
|
||||||
type=pathlib.Path,
|
type=pathlib.Path,
|
||||||
help=_("source video file/directory"),
|
help="input file/directory path",
|
||||||
required=require_input_output,
|
required=True,
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
video2x_options.add_argument(
|
|
||||||
"-o",
|
"-o",
|
||||||
"--output",
|
"--output",
|
||||||
type=pathlib.Path,
|
type=pathlib.Path,
|
||||||
help=_("output video file/directory"),
|
help="output file/directory path",
|
||||||
required=require_input_output,
|
required=True,
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-p", "--processes", type=int, help="number of processes to launch", default=1
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-l",
|
||||||
|
"--loglevel",
|
||||||
|
choices=["trace", "debug", "info", "success", "warning", "error", "critical"],
|
||||||
|
default="info",
|
||||||
)
|
)
|
||||||
|
|
||||||
video2x_options.add_argument(
|
# upscaler arguments
|
||||||
"-c",
|
action = parser.add_subparsers(
|
||||||
"--config",
|
help="action to perform", dest="action", required=True
|
||||||
type=pathlib.Path,
|
|
||||||
help=_("Video2X config file path"),
|
|
||||||
action="store",
|
|
||||||
default=pathlib.Path(__file__).parent.absolute() / "video2x.yaml",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
video2x_options.add_argument("--log", type=pathlib.Path, help=_("log file path"))
|
upscale = action.add_parser("upscale", help="upscale a file", add_help=False)
|
||||||
|
upscale.add_argument(
|
||||||
video2x_options.add_argument(
|
"--help", action="help", help="show this help message and exit"
|
||||||
"-v",
|
|
||||||
"--version",
|
|
||||||
help=_("display version, lawful information and exit"),
|
|
||||||
action="store_true",
|
|
||||||
)
|
)
|
||||||
|
upscale.add_argument("-w", "--width", type=int, help="output width")
|
||||||
# scaling options
|
upscale.add_argument("-h", "--height", type=int, help="output height")
|
||||||
upscaling_options = parser.add_argument_group(_("Upscaling Options"))
|
upscale.add_argument("-n", "--noise", type=int, help="denoise level", default=3)
|
||||||
|
upscale.add_argument(
|
||||||
upscaling_options.add_argument(
|
|
||||||
"-r", "--ratio", help=_("scaling ratio"), action="store", type=float
|
|
||||||
)
|
|
||||||
|
|
||||||
upscaling_options.add_argument(
|
|
||||||
"-w", "--width", help=_("output width"), action="store", type=float
|
|
||||||
)
|
|
||||||
|
|
||||||
upscaling_options.add_argument(
|
|
||||||
"-h", "--height", help=_("output height"), action="store", type=float
|
|
||||||
)
|
|
||||||
|
|
||||||
upscaling_options.add_argument(
|
|
||||||
"-d",
|
"-d",
|
||||||
"--driver",
|
"--driver",
|
||||||
help=_("upscaling driver"),
|
choices=UPSCALING_DRIVERS,
|
||||||
choices=AVAILABLE_DRIVERS,
|
help="driver to use for upscaling",
|
||||||
default="waifu2x_ncnn_vulkan",
|
default=UPSCALING_DRIVERS[0],
|
||||||
|
)
|
||||||
|
upscale.add_argument(
|
||||||
|
"-t",
|
||||||
|
"--threshold",
|
||||||
|
type=float,
|
||||||
|
help="if the % difference between two adjacent frames exceeds this value, two images are deemed the same",
|
||||||
|
default=0.1,
|
||||||
)
|
)
|
||||||
|
|
||||||
upscaling_options.add_argument(
|
# interpolator arguments
|
||||||
"-p",
|
interpolate = action.add_parser(
|
||||||
"--processes",
|
"interpolate", help="interpolate frames for file", add_help=False
|
||||||
help=_("number of processes to use for upscaling"),
|
)
|
||||||
action="store",
|
interpolate.add_argument(
|
||||||
type=int,
|
"--help", action="help", help="show this help message and exit"
|
||||||
default=1,
|
)
|
||||||
|
interpolate.add_argument(
|
||||||
|
"-d",
|
||||||
|
"--driver",
|
||||||
|
choices=UPSCALING_DRIVERS,
|
||||||
|
help="driver to use for upscaling",
|
||||||
|
default=INTERPOLATION_DRIVERS[0],
|
||||||
|
)
|
||||||
|
interpolate.add_argument(
|
||||||
|
"-t",
|
||||||
|
"--threshold",
|
||||||
|
type=float,
|
||||||
|
help="if the % difference between two adjacent frames exceeds this value, no interpolation will be performed",
|
||||||
|
default=10,
|
||||||
)
|
)
|
||||||
|
|
||||||
upscaling_options.add_argument(
|
return parser.parse_args()
|
||||||
"--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():
|
def main():
|
||||||
"""print video2x logo"""
|
"""
|
||||||
print(LOGO)
|
command line direct invocation
|
||||||
print(f'\n{"Video2X Video Enlarger".rjust(40, " ")}')
|
program entry point
|
||||||
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:
|
try:
|
||||||
return yaml.load(config, Loader=yaml.FullLoader)
|
|
||||||
|
|
||||||
|
# parse command line arguments
|
||||||
|
args = parse_arguments()
|
||||||
|
|
||||||
# /////////////////// Execution /////////////////// #
|
# set logger level
|
||||||
|
if os.environ.get("LOGURU_LEVEL") is None:
|
||||||
|
os.environ["LOGURU_LEVEL"] = args.loglevel.upper()
|
||||||
|
|
||||||
# this is not a library
|
# set logger format
|
||||||
if __name__ != "__main__":
|
if os.environ.get("LOGURU_FORMAT") is None:
|
||||||
Avalon.error(_("This file cannot be imported"))
|
os.environ[
|
||||||
raise ImportError(f"{__file__} cannot be imported")
|
"LOGURU_FORMAT"
|
||||||
|
] = "<fg 240>{time:HH:mm:ss!UTC}</fg 240> | <level>{level: <8}</level> | <level>{message}</level>"
|
||||||
|
|
||||||
# print video2x logo
|
# display version and lawful informaition
|
||||||
print_logo()
|
if args.version:
|
||||||
|
|
||||||
# parse command line arguments
|
|
||||||
video2x_args, driver_args = parse_arguments()
|
|
||||||
|
|
||||||
# display version and lawful informaition
|
|
||||||
if video2x_args.version:
|
|
||||||
print(LEGAL_INFO)
|
print(LEGAL_INFO)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
# additional checks on upscaling arguments
|
|
||||||
if video2x_args.ratio is not None and (
|
|
||||||
video2x_args.width is not None or video2x_args.height is not None
|
|
||||||
):
|
|
||||||
Avalon.error(_("Specify either scaling ratio or scaling resolution, not both"))
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
elif video2x_args.ratio is None and (
|
|
||||||
video2x_args.width is None or video2x_args.height is None
|
|
||||||
):
|
|
||||||
Avalon.error(_("Either scaling ratio or scaling resolution needs to be specified"))
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# redirect output to both terminal and log file
|
|
||||||
if video2x_args.log is not None:
|
|
||||||
log_file = video2x_args.log.open(mode="a+", encoding="utf-8")
|
|
||||||
else:
|
|
||||||
log_file = tempfile.TemporaryFile(
|
|
||||||
mode="a+", suffix=".log", prefix="video2x_", encoding="utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
original_stdout = sys.stdout
|
|
||||||
original_stderr = sys.stderr
|
|
||||||
sys.stdout = BiLogger(sys.stdout, log_file)
|
|
||||||
sys.stderr = BiLogger(sys.stderr, log_file)
|
|
||||||
|
|
||||||
# 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
|
|
||||||
extracted_frame_format = config["video2x"]["extracted_frame_format"].lower()
|
|
||||||
output_file_name_format_string = config["video2x"]["output_file_name_format_string"]
|
|
||||||
image_output_extension = config["video2x"]["image_output_extension"]
|
|
||||||
video_output_extension = config["video2x"]["video_output_extension"]
|
|
||||||
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
|
# initialize upscaler object
|
||||||
upscaler = Upscaler(
|
video2x = Video2X()
|
||||||
# required parameters
|
|
||||||
input_path=video2x_args.input,
|
if args.action == "upscale":
|
||||||
output_path=video2x_args.output,
|
video2x.upscale(
|
||||||
driver_settings=driver_settings,
|
args.input,
|
||||||
ffmpeg_settings=ffmpeg_settings,
|
args.output,
|
||||||
gifski_settings=gifski_settings,
|
args.width,
|
||||||
# optional parameters
|
args.height,
|
||||||
driver=video2x_args.driver,
|
args.noise,
|
||||||
scale_ratio=video2x_args.ratio,
|
args.processes,
|
||||||
scale_width=video2x_args.width,
|
args.threshold,
|
||||||
scale_height=video2x_args.height,
|
args.driver,
|
||||||
processes=video2x_args.processes,
|
|
||||||
video2x_cache_directory=video2x_cache_directory,
|
|
||||||
extracted_frame_format=extracted_frame_format,
|
|
||||||
output_file_name_format_string=output_file_name_format_string,
|
|
||||||
image_output_extension=image_output_extension,
|
|
||||||
video_output_extension=video_output_extension,
|
|
||||||
preserve_frames=preserve_frames,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# run upscaler
|
elif args.action == "interpolate":
|
||||||
upscaler.run()
|
video2x.interpolate(
|
||||||
|
args.input,
|
||||||
Avalon.info(
|
args.output,
|
||||||
_("Program completed, taking {} seconds").format(
|
args.processes,
|
||||||
round((time.time() - begin_time), 5)
|
args.threshold,
|
||||||
|
args.driver,
|
||||||
)
|
)
|
||||||
)
|
except Exception as e:
|
||||||
|
logger.exception(e)
|
||||||
except Exception:
|
|
||||||
|
|
||||||
Avalon.error(_("An exception has occurred"))
|
|
||||||
traceback.print_exc()
|
|
||||||
|
|
||||||
if video2x_args.log is not None:
|
|
||||||
log_file_path = video2x_args.log.absolute()
|
|
||||||
|
|
||||||
# if log file path is not specified, create temporary file as permanent log file
|
|
||||||
# tempfile.TempFile does not have a name attribute and is not guaranteed to have
|
|
||||||
# a visible name on the file system
|
|
||||||
else:
|
|
||||||
log_file_path = tempfile.mkstemp(suffix=".log", prefix="video2x_")[1]
|
|
||||||
with open(log_file_path, "w", encoding="utf-8") as permanent_log_file:
|
|
||||||
log_file.seek(0)
|
|
||||||
permanent_log_file.write(log_file.read())
|
|
||||||
|
|
||||||
Avalon.error(_("The error log file can be found at: {}").format(log_file_path))
|
|
||||||
|
|
||||||
finally:
|
|
||||||
sys.stdout = original_stdout
|
|
||||||
sys.stderr = original_stderr
|
|
||||||
log_file.close()
|
|
||||||
|
@ -1,185 +0,0 @@
|
|||||||
# Name: Video2X Configuration File
|
|
||||||
# Creator: K4YT3X
|
|
||||||
# Date Created: October 23, 2018
|
|
||||||
# Last Modified: September 28, 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/webp) or directory
|
|
||||||
#o: null # output-path: output image path (jpg/png/webp) 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) can be 1:2,2,2:2 for multi-gpu
|
|
||||||
x: false # enable tta mode
|
|
||||||
#f: png # output image format (jpg/png/webp, default=ext/png)
|
|
||||||
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
|
|
||||||
#f: png # output image format (jpg/png/webp, default=ext/png)
|
|
||||||
realsr_ncnn_vulkan:
|
|
||||||
path: '%LOCALAPPDATA%\video2x\realsr-ncnn-vulkan\realsr-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
|
|
||||||
s: 4 # upscale ratio (4, default=4)
|
|
||||||
t: 0 # tile size (>=32/0=auto, default=0)
|
|
||||||
m: null # realsr model path (default=models-DF2K)
|
|
||||||
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
|
|
||||||
#f: png # output image format (jpg/png/webp, default=ext/png)
|
|
||||||
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
|
|
||||||
CNNMode: false # Enable ACNet
|
|
||||||
HDN: false # Enable HDN mode for ACNet
|
|
||||||
HDNLevel: 1 # Set HDN level (int [=1])
|
|
||||||
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])
|
|
||||||
forceFps: 0 # Set output video fps to the specifying number, 0 to disable (float [=0])
|
|
||||||
disableProgress: false # disable progress display
|
|
||||||
webVideo: null # process the video from URL
|
|
||||||
alpha: false # preserve the Alpha channel for transparent image
|
|
||||||
ffmpeg:
|
|
||||||
ffmpeg_path: '%LOCALAPPDATA%\video2x\ffmpeg\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': rgb24 # 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
|
|
||||||
'-tune': 'animation' # encoding tuning film/animation/grain/stillimage/fastdecode/zerolatency/psnr/ssim
|
|
||||||
# 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, directory where cache files are stored, will be deleted if preserve_frames is not set to true
|
|
||||||
extracted_frame_format: png # png/jpg intermediate file format used for extracted frames during video processing
|
|
||||||
output_file_name_format_string: "{original_file_name}_output{extension}" # format string to use for generating output file names
|
|
||||||
image_output_extension: .png # image output extension during batch processing
|
|
||||||
video_output_extension: .mp4 # video output extension during batch processing
|
|
||||||
preserve_frames: false # if set to true, the cache directory won't be cleaned upon task completion
|
|
File diff suppressed because it is too large
Load Diff
@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"files": ["video2x_gui.ui","video2x_gui.py"]
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -1,518 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
Name: Video2X Setup Script
|
|
||||||
Creator: K4YT3X
|
|
||||||
Date Created: November 28, 2018
|
|
||||||
Last Modified: December 13, 2020
|
|
||||||
|
|
||||||
Editor: BrianPetkovsek
|
|
||||||
Editor: SAT3LL
|
|
||||||
Editor: konqiDAM
|
|
||||||
|
|
||||||
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
|
|
||||||
- srmd_ncnn_vulkan: %LOCALAPPDATA%\\video2x\\srmd-ncnn-vulkan
|
|
||||||
- realsr_ncnn_vulkan: %LOCALAPPDATA%\\video2x\\realsr-ncnn-vulkan
|
|
||||||
- anime4kcpp: %LOCALAPPDATA%\\video2x\\anime4kcpp
|
|
||||||
"""
|
|
||||||
|
|
||||||
# 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.4.1"
|
|
||||||
|
|
||||||
# global static variables
|
|
||||||
LOCALAPPDATA = pathlib.Path(os.getenv("localappdata"))
|
|
||||||
DRIVER_OPTIONS = [
|
|
||||||
"all",
|
|
||||||
"ffmpeg",
|
|
||||||
"gifski",
|
|
||||||
"waifu2x_caffe",
|
|
||||||
"waifu2x_converter_cpp",
|
|
||||||
"waifu2x_ncnn_vulkan",
|
|
||||||
"srmd_ncnn_vulkan",
|
|
||||||
"realsr_ncnn_vulkan",
|
|
||||||
"anime4kcpp",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
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}")()
|
|
||||||
|
|
||||||
# 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"""
|
|
||||||
print("\nCleaning up temporary files")
|
|
||||||
|
|
||||||
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")
|
|
||||||
|
|
||||||
import patoolib
|
|
||||||
|
|
||||||
latest_release = "https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-full.7z"
|
|
||||||
|
|
||||||
ffmpeg_7z = download(latest_release, tempfile.gettempdir())
|
|
||||||
self.trash.append(ffmpeg_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"
|
|
||||||
|
|
||||||
ffmpeg_directory = LOCALAPPDATA / "video2x" / "ffmpeg"
|
|
||||||
|
|
||||||
# (ffmpeg_directory).mkdir(parents=True, exist_ok=True)
|
|
||||||
# pyunpack.Archive(ffmpeg_7z).extractall(ffmpeg_directory)
|
|
||||||
if (ffmpeg_directory).exists():
|
|
||||||
shutil.rmtree(ffmpeg_directory)
|
|
||||||
patoolib.extract_archive(str(ffmpeg_7z), outdir=str(LOCALAPPDATA / "video2x"))
|
|
||||||
(LOCALAPPDATA / "video2x" / ffmpeg_7z.stem).rename(ffmpeg_directory)
|
|
||||||
|
|
||||||
def _install_gifski(self):
|
|
||||||
print("\nInstalling Gifski")
|
|
||||||
import requests
|
|
||||||
|
|
||||||
# Get latest release of Gifski via Github API
|
|
||||||
releases = requests.get(
|
|
||||||
"https://api.github.com/repos/ImageOptim/gifski/releases"
|
|
||||||
).json()
|
|
||||||
for release in releases:
|
|
||||||
for asset in release["assets"]:
|
|
||||||
if re.search(r"gifski-.*\.tar\.xz", asset["browser_download_url"]):
|
|
||||||
gifski_tar_xz = download(
|
|
||||||
asset["browser_download_url"], tempfile.gettempdir()
|
|
||||||
)
|
|
||||||
self.trash.append(gifski_tar_xz)
|
|
||||||
|
|
||||||
# extract and rename
|
|
||||||
with tarfile.open(gifski_tar_xz) as archive:
|
|
||||||
archive.extractall(LOCALAPPDATA / "video2x" / "gifski")
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
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*-windows\.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_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*-windows\.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 _install_realsr_ncnn_vulkan(self):
|
|
||||||
"""Install realsr-ncnn-vulkan"""
|
|
||||||
print("\nInstalling realsr-ncnn-vulkan")
|
|
||||||
import requests
|
|
||||||
|
|
||||||
# Get latest release of realsr-ncnn-vulkan via Github API
|
|
||||||
latest_release = requests.get(
|
|
||||||
"https://api.github.com/repos/nihui/realsr-ncnn-vulkan/releases/latest"
|
|
||||||
).json()
|
|
||||||
|
|
||||||
for a in latest_release["assets"]:
|
|
||||||
if re.search(
|
|
||||||
r"realsr-ncnn-vulkan-\d*-windows\.zip", a["browser_download_url"]
|
|
||||||
):
|
|
||||||
realsr_ncnn_vulkan_zip = download(
|
|
||||||
a["browser_download_url"], tempfile.gettempdir()
|
|
||||||
)
|
|
||||||
self.trash.append(realsr_ncnn_vulkan_zip)
|
|
||||||
|
|
||||||
# extract and rename
|
|
||||||
realsr_ncnn_vulkan_directory = LOCALAPPDATA / "video2x" / "realsr-ncnn-vulkan"
|
|
||||||
with zipfile.ZipFile(realsr_ncnn_vulkan_zip) as zipf:
|
|
||||||
zipf.extractall(LOCALAPPDATA / "video2x")
|
|
||||||
|
|
||||||
# if directory already exists, remove it
|
|
||||||
if realsr_ncnn_vulkan_directory.exists():
|
|
||||||
shutil.rmtree(realsr_ncnn_vulkan_directory)
|
|
||||||
|
|
||||||
# rename the newly extracted directory
|
|
||||||
(LOCALAPPDATA / "video2x" / zipf.namelist()[0]).rename(
|
|
||||||
realsr_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 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")
|
|
||||||
|
|
||||||
EXIT_CODE = 1
|
|
||||||
|
|
||||||
# regardless if script finishes successfully or not
|
|
||||||
# print script execution summary
|
|
||||||
finally:
|
|
||||||
# always try cleaning up trash
|
|
||||||
try:
|
|
||||||
setup._cleanup()
|
|
||||||
except Exception:
|
|
||||||
traceback.print_exc()
|
|
||||||
print("An error occurred while trying to cleanup files")
|
|
||||||
|
|
||||||
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)
|
|
@ -1,246 +0,0 @@
|
|||||||
#!/usr/bin/bash -e
|
|
||||||
# Name: Video2X Setup Script (Ubuntu)
|
|
||||||
# Creator: K4YT3X
|
|
||||||
# Date Created: June 5, 2020
|
|
||||||
# Last Modified: September 4, 2020
|
|
||||||
|
|
||||||
# help message if input is incorrect of if -h/--help is specified
|
|
||||||
if [ "$1" == "-h" ] || [ "$1" == "--help" ] || [ "$#" -gt 2 ]; then
|
|
||||||
echo "usage: $0 INSTALLATION_PATH TEMP"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# set intallation path if specified
|
|
||||||
if [ ! -z "$1" ]; then
|
|
||||||
export INSTALLATION_PATH=$1
|
|
||||||
else
|
|
||||||
export INSTALLATION_PATH="$HOME/.local/share"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# set temp directory location if specified
|
|
||||||
if [ ! -z "$2" ]; then
|
|
||||||
export TEMP=$2
|
|
||||||
else
|
|
||||||
export TEMP="/tmp/video2x"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# environment variables
|
|
||||||
export DEBIAN_FRONTEND="noninteractive"
|
|
||||||
|
|
||||||
# install basic utilities and add PPAs
|
|
||||||
apt-get update
|
|
||||||
apt-get install -y --no-install-recommends apt-utils software-properties-common
|
|
||||||
|
|
||||||
# add PPAs and sources
|
|
||||||
add-apt-repository -y ppa:apt-fast/stable
|
|
||||||
add-apt-repository -y ppa:graphics-drivers/ppa
|
|
||||||
apt-get install -y --no-install-recommends apt-fast aria2
|
|
||||||
apt-fast update
|
|
||||||
|
|
||||||
# install runtime packages
|
|
||||||
apt-fast install -y --no-install-recommends ffmpeg libmagic1 nvidia-cuda-toolkit nvidia-driver-440 python3.8
|
|
||||||
|
|
||||||
# install compilation packages
|
|
||||||
apt-fast install -y --no-install-recommends git-core curl wget ca-certificates gnupg2 python3-dev python3-pip python3-setuptools python3-wheel
|
|
||||||
|
|
||||||
# add Nvidia sources
|
|
||||||
curl -fsSL https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/7fa2af80.pub | apt-key add -
|
|
||||||
echo "deb https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64 /" >/etc/apt/sources.list.d/nvidia-ml.list
|
|
||||||
apt-fast update
|
|
||||||
|
|
||||||
# install python3 packages
|
|
||||||
git clone --recurse-submodules --progress https://github.com/k4yt3x/video2x.git --depth=1 $INSTALLATION_PATH/video2x
|
|
||||||
python3.8 -m pip install -U pip
|
|
||||||
python3.8 -m pip install -U -r $INSTALLATION_PATH/video2x/src/requirements.txt
|
|
||||||
mkdir -v -p $INSTALLATION_PATH/video2x/src/dependencies
|
|
||||||
|
|
||||||
# install gifski
|
|
||||||
# cargo from APT might be outdate and will result in gifski components not being built successfully
|
|
||||||
# apt-fast install -y --no-install-recommends cargo
|
|
||||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | bash -s -- -y
|
|
||||||
source $HOME/.cargo/env
|
|
||||||
cargo install gifski
|
|
||||||
|
|
||||||
# install waifu2x-caffe
|
|
||||||
apt-fast install -y --no-install-recommends autoconf build-essential cmake gcc-8 libatlas-base-dev libboost-atomic-dev libboost-chrono-dev libboost-date-time-dev libboost-filesystem-dev libboost-iostreams-dev libboost-python-dev libboost-system-dev libboost-thread-dev libcudnn7 libcudnn7-dev libgflags-dev libgoogle-glog-dev libhdf5-dev libleveldb-dev liblmdb-dev libopencv-dev libprotobuf-dev libsnappy-dev protobuf-compiler python-dev python-numpy texinfo yasm zlib1g-dev
|
|
||||||
|
|
||||||
git clone --recurse-submodules --depth=1 --progress --recurse-submodules https://github.com/nagadomi/waifu2x-caffe-ubuntu.git $TEMP/waifu2x-caffe-ubuntu
|
|
||||||
git clone --recurse-submodules --progress --depth=1 https://github.com/nagadomi/caffe.git $TEMP/waifu2x-caffe-ubuntu/caffe
|
|
||||||
|
|
||||||
export CC=/usr/bin/gcc-8
|
|
||||||
export CXX=/usr/bin/g++-8
|
|
||||||
mkdir -v -p $TEMP/waifu2x-caffe-ubuntu/build
|
|
||||||
cd $TEMP/waifu2x-caffe-ubuntu/build
|
|
||||||
cmake .. -DCMAKE_INSTALL_PREFIX=/usr
|
|
||||||
make -j$(nproc) install
|
|
||||||
|
|
||||||
mv -v /tmp/video2x/waifu2x-caffe-ubuntu/bin $INSTALLATION_PATH/video2x/src/dependencies/waifu2x-caffe
|
|
||||||
mv -v /tmp/video2x/waifu2x-caffe-ubuntu/build/waifu2x-caffe $INSTALLATION_PATH/video2x/src/dependencies/waifu2x-caffe/waifu2x-caffe
|
|
||||||
|
|
||||||
# install waifu2x-converter-cpp
|
|
||||||
apt-fast install -y --no-install-recommends build-essential cmake libopencv-dev beignet-opencl-icd mesa-opencl-icd nvidia-cuda-toolkit ocl-icd-opencl-dev opencl-headers
|
|
||||||
git clone --recurse-submodules --depth=1 --progress https://github.com/DeadSix27/waifu2x-converter-cpp $TEMP/waifu2x-converter-cpp
|
|
||||||
mkdir -v $TEMP/waifu2x-converter-cpp/build
|
|
||||||
cd $TEMP/waifu2x-converter-cpp/build
|
|
||||||
cmake ..
|
|
||||||
make -j$(nproc)
|
|
||||||
ldconfig
|
|
||||||
mv -v $TEMP/waifu2x-converter-cpp/build $INSTALLATION_PATH/video2x/src/dependencies/waifu2x-converter-cpp
|
|
||||||
mv -v $TEMP/waifu2x-converter-cpp/models_rgb $INSTALLATION_PATH/video2x/src/dependencies/waifu2x-converter-cpp/models_rgb
|
|
||||||
|
|
||||||
# install waifu2x-ncnn-vulkan
|
|
||||||
# download libvulkan1
|
|
||||||
apt-fast install -y --no-install-recommends libvulkan1 unzip jq
|
|
||||||
|
|
||||||
# get latest release JSON as a string
|
|
||||||
echo "Fetching latest waifu2x-ncnn-vulkan release information using GitHub API"
|
|
||||||
waifu2x_ncnn_vulkan_latest_release=$(curl -s https://api.github.com/repos/nihui/waifu2x-ncnn-vulkan/releases/latest)
|
|
||||||
|
|
||||||
# count the number of assets in this release
|
|
||||||
assets=$(echo "$waifu2x_ncnn_vulkan_latest_release" | jq -r '.assets | length')
|
|
||||||
|
|
||||||
# iterate through each of the assets and see if the name of the asset matches what we're looking for
|
|
||||||
for i in $(seq $assets $END); do
|
|
||||||
if echo "$waifu2x_ncnn_vulkan_latest_release" | jq -r ".assets["$(($i - 1))"].name" | egrep "^waifu2x-ncnn-vulkan-[0-9]*-linux\.zip$"; then
|
|
||||||
download_link=$(echo "$waifu2x_ncnn_vulkan_latest_release" | jq -r ".assets["$(($i - 1))"].browser_download_url")
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# check if download_link variable is set
|
|
||||||
if [ -z "$download_link" ]; then
|
|
||||||
echo "$waifu2x_ncnn_vulkan_latest_release"
|
|
||||||
echo "Error: unable to find waifu2x-ncnn-vulkan download link or GitHub API rate limit exceeded"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
waifu2x_ncnn_vulkan_zip="$TEMP/waifu2x-ncnn-vulkan-linux.zip"
|
|
||||||
echo "Downloading $download_link to $waifu2x_ncnn_vulkan_zip"
|
|
||||||
aria2c "$download_link" --dir / -o "$waifu2x_ncnn_vulkan_zip"
|
|
||||||
unzip "$waifu2x_ncnn_vulkan_zip" -d $TEMP/waifu2x-ncnn-vulkan
|
|
||||||
mv -v $TEMP/waifu2x-ncnn-vulkan/waifu2x-ncnn-vulkan-*-linux $INSTALLATION_PATH/video2x/src/dependencies/waifu2x-ncnn-vulkan
|
|
||||||
|
|
||||||
# install srmd-ncnn-vulkan
|
|
||||||
# download libvulkan1
|
|
||||||
apt-fast install -y --no-install-recommends libvulkan1 unzip jq
|
|
||||||
|
|
||||||
# get latest release JSON as a string
|
|
||||||
echo "Fetching latest srmd-ncnn-vulkan release information using GitHub API"
|
|
||||||
srmd_ncnn_vulkan_latest_release=$(curl -s https://api.github.com/repos/nihui/srmd-ncnn-vulkan/releases/latest)
|
|
||||||
|
|
||||||
# count the number of assets in this release
|
|
||||||
assets=$(echo "$srmd_ncnn_vulkan_latest_release" | jq -r '.assets | length')
|
|
||||||
|
|
||||||
# iterate through each of the assets and see if the name of the asset matches what we're looking for
|
|
||||||
for i in $(seq $assets $END); do
|
|
||||||
if echo "$srmd_ncnn_vulkan_latest_release" | jq -r ".assets["$(($i - 1))"].name" | egrep "^srmd-ncnn-vulkan-[0-9]*-linux\.zip$"; then
|
|
||||||
download_link=$(echo "$srmd_ncnn_vulkan_latest_release" | jq -r ".assets["$(($i - 1))"].browser_download_url")
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# check if download_link variable is set
|
|
||||||
if [ -z "$download_link" ]; then
|
|
||||||
echo "$srmd_ncnn_vulkan_latest_release"
|
|
||||||
echo "Error: unable to find srmd-ncnn-vulkan download link or GitHub API rate limit exceeded"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
srmd_ncnn_vulkan_zip="$TEMP/srmd-ncnn-vulkan-linux.zip"
|
|
||||||
echo "Downloading $download_link to $srmd_ncnn_vulkan_zip"
|
|
||||||
aria2c "$download_link" --dir / -o "$srmd_ncnn_vulkan_zip"
|
|
||||||
unzip "$srmd_ncnn_vulkan_zip" -d $TEMP/srmd-ncnn-vulkan
|
|
||||||
mv -v $TEMP/srmd-ncnn-vulkan/srmd-ncnn-vulkan-*-linux $INSTALLATION_PATH/video2x/src/dependencies/srmd-ncnn-vulkan
|
|
||||||
|
|
||||||
# install realsr-ncnn-vulkan
|
|
||||||
# download libvulkan1
|
|
||||||
apt-fast install -y --no-install-recommends libvulkan1 unzip jq
|
|
||||||
|
|
||||||
# get latest release JSON as a string
|
|
||||||
echo "Fetching latest realsr-ncnn-vulkan release information using GitHub API"
|
|
||||||
realsr_ncnn_vulkan_latest_release=$(curl -s https://api.github.com/repos/nihui/realsr-ncnn-vulkan/releases/latest)
|
|
||||||
|
|
||||||
# count the number of assets in this release
|
|
||||||
assets=$(echo "$realsr_ncnn_vulkan_latest_release" | jq -r '.assets | length')
|
|
||||||
|
|
||||||
# iterate through each of the assets and see if the name of the asset matches what we're looking for
|
|
||||||
for i in $(seq $assets $END); do
|
|
||||||
if echo "$realsr_ncnn_vulkan_latest_release" | jq -r ".assets["$(($i - 1))"].name" | egrep "^realsr-ncnn-vulkan-[0-9]*-linux\.zip$"; then
|
|
||||||
download_link=$(echo "$realsr_ncnn_vulkan_latest_release" | jq -r ".assets["$(($i - 1))"].browser_download_url")
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# check if download_link variable is set
|
|
||||||
if [ -z "$download_link" ]; then
|
|
||||||
echo "$realsr_ncnn_vulkan_latest_release"
|
|
||||||
echo "Error: unable to find realsr-ncnn-vulkan download link or GitHub API rate limit exceeded"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
realsr_ncnn_vulkan_zip="$TEMP/realsr-ncnn-vulkan-linux.zip"
|
|
||||||
echo "Downloading $download_link to $realsr_ncnn_vulkan_zip"
|
|
||||||
aria2c "$download_link" --dir / -o "$realsr_ncnn_vulkan_zip"
|
|
||||||
unzip "$realsr_ncnn_vulkan_zip" -d $TEMP/realsr-ncnn-vulkan
|
|
||||||
mv -v $TEMP/realsr-ncnn-vulkan/realsr-ncnn-vulkan-*-linux $INSTALLATION_PATH/video2x/src/dependencies/realsr-ncnn-vulkan
|
|
||||||
|
|
||||||
# install Anime4KCPP
|
|
||||||
# install the latest cmake for compiling Anime4KCPP
|
|
||||||
aria2c https://github.com/Kitware/CMake/releases/download/v3.18.2/cmake-3.18.2-Linux-x86_64.sh --dir / -o "$TEMP/cmake.sh"
|
|
||||||
mkdir $TEMP/cmake
|
|
||||||
bash "$TEMP/cmake.sh" --prefix=$TEMP/cmake --skip-license
|
|
||||||
|
|
||||||
# build and install Anime4KCPP
|
|
||||||
apt-fast install -y --no-install-recommends libopencv-dev opencl-dev
|
|
||||||
git clone --recurse-submodules --depth=1 --progress https://github.com/TianZerL/Anime4KCPP.git $TEMP/anime4kcpp
|
|
||||||
mkdir -v $TEMP/anime4kcpp/build
|
|
||||||
cd $TEMP/anime4kcpp/build
|
|
||||||
$TEMP/cmake/bin/cmake -DBuild_GUI=OFF ..
|
|
||||||
make -j$(nproc)
|
|
||||||
mv -v $TEMP/anime4kcpp/build $INSTALLATION_PATH/video2x/src/dependencies/anime4kcpp
|
|
||||||
ln -s $INSTALLATION_PATH/video2x/src/dependencies/anime4kcpp/bin/libAnime4KCPPCore.so /usr/lib
|
|
||||||
|
|
||||||
# rewrite config file values
|
|
||||||
python3.8 - <<EOF
|
|
||||||
import yaml
|
|
||||||
import os
|
|
||||||
|
|
||||||
|
|
||||||
INSTALLATION_PATH = os.environ['INSTALLATION_PATH']
|
|
||||||
|
|
||||||
with open('{}/video2x/src/video2x.yaml'.format(INSTALLATION_PATH), 'r') as template:
|
|
||||||
template_dict = yaml.load(template, Loader=yaml.FullLoader)
|
|
||||||
template.close()
|
|
||||||
|
|
||||||
template_dict['ffmpeg']['ffmpeg_path'] = '/usr/bin'
|
|
||||||
template_dict['gifski']['gifski_path'] = '/root/.cargo/bin/gifski'
|
|
||||||
template_dict['waifu2x_caffe']['path'] = '{}/video2x/src/dependencies/waifu2x-caffe/waifu2x-caffe'.format(INSTALLATION_PATH)
|
|
||||||
template_dict['waifu2x_converter_cpp']['path'] = '{}/video2x/src/dependencies/waifu2x-converter-cpp/waifu2x-converter-cpp'.format(INSTALLATION_PATH)
|
|
||||||
template_dict['waifu2x_ncnn_vulkan']['path'] = '{}/video2x/src/dependencies/waifu2x-ncnn-vulkan/waifu2x-ncnn-vulkan'.format(INSTALLATION_PATH)
|
|
||||||
template_dict['srmd_ncnn_vulkan']['path'] = '{}/video2x/src/dependencies/srmd-ncnn-vulkan/srmd-ncnn-vulkan'.format(INSTALLATION_PATH)
|
|
||||||
template_dict['realsr_ncnn_vulkan']['path'] = '{}/video2x/src/dependencies/realsr-ncnn-vulkan/realsr-ncnn-vulkan'.format(INSTALLATION_PATH)
|
|
||||||
template_dict['anime4kcpp']['path'] = '{}/video2x/src/dependencies/anime4kcpp/bin/Anime4KCPP_CLI'.format(INSTALLATION_PATH)
|
|
||||||
|
|
||||||
# write configuration into file
|
|
||||||
with open('{}/video2x/src/video2x.yaml'.format(INSTALLATION_PATH), 'w') as config:
|
|
||||||
yaml.dump(template_dict, config)
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# clean up temp directory
|
|
||||||
# purge default utilities
|
|
||||||
# apt-get purge -y git-core curl wget ca-certificates gnupg2 python3-dev python3-pip python3-setuptools
|
|
||||||
|
|
||||||
# purge waifu2x-caffe build dependencies
|
|
||||||
# apt-get purge -y autoconf build-essential cmake gcc-8 libatlas-base-dev libboost-atomic-dev libboost-chrono-dev libboost-date-time-dev libboost-filesystem-dev libboost-iostreams-dev libboost-python-dev libboost-system-dev libboost-thread-dev libcudnn7 libcudnn7-dev libgflags-dev libgoogle-glog-dev libhdf5-dev libleveldb-dev liblmdb-dev libopencv-dev libprotobuf-dev libsnappy-dev protobuf-compiler python-numpy texinfo yasm zlib1g-dev
|
|
||||||
|
|
||||||
# purge waifu2x-converter-cpp build dependencies
|
|
||||||
# apt-get purge -y libopencv-dev ocl-icd-opencl-dev
|
|
||||||
|
|
||||||
# purge waifu2x/srmd/realsr-ncnn-vulkan build dependencies
|
|
||||||
# apt-get purge -y unzip jq
|
|
||||||
|
|
||||||
# run autoremove and purge all unused packages
|
|
||||||
# apt-get autoremove --purge -y
|
|
||||||
|
|
||||||
# remove temp directory
|
|
||||||
rm -rf $TEMP
|
|
@ -1,140 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
Name: Anime4KCPP Driver
|
|
||||||
Author: K4YT3X
|
|
||||||
Date Created: May 3, 2020
|
|
||||||
Last Modified: December 15, 2020
|
|
||||||
|
|
||||||
Editor: fire0shadow
|
|
||||||
Last Modified: December 15, 2020
|
|
||||||
|
|
||||||
Description: This class is a high-level wrapper
|
|
||||||
for Anime4KCPP.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# built-in imports
|
|
||||||
import argparse
|
|
||||||
import os
|
|
||||||
import pathlib
|
|
||||||
import platform
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
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):
|
|
||||||
# fmt: off
|
|
||||||
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("-w", "--CNNMode", action="store_true", help="Enable ACNet")
|
|
||||||
parser.add_argument("-H", "--HDN", action="store_true", help="Enable HDN mode for ACNet")
|
|
||||||
parser.add_argument("-L", "--HDNLevel", type=int, help="Set HDN level")
|
|
||||||
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])")
|
|
||||||
parser.add_argument("-F", "--forceFps", type=float, help="Set output video fps to the specifying number, 0 to disable")
|
|
||||||
parser.add_argument("-D", "--disableProgress", action="store_true", help="disable progress display")
|
|
||||||
parser.add_argument("-W", "--webVideo", type=str, help="process the video from URL")
|
|
||||||
parser.add_argument("-A", "--alpha", action="store_true", help="preserve the Alpha channel for transparent image")
|
|
||||||
return parser.parse_args(arguments)
|
|
||||||
# fmt: on
|
|
||||||
|
|
||||||
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 set_scale_ratio(self, scale_ratio: float):
|
|
||||||
self.driver_settings["zoomFactor"] = scale_ratio
|
|
||||||
|
|
||||||
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
|
|
||||||
"""
|
|
||||||
|
|
||||||
# change the working directory to the binary's parent directory
|
|
||||||
# so the binary can find shared object files and other files
|
|
||||||
os.chdir(pathlib.Path(self.driver_settings["path"]).parent)
|
|
||||||
|
|
||||||
# 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: {" ".join(execute)}'
|
|
||||||
)
|
|
||||||
self.print_lock.release()
|
|
||||||
return subprocess.Popen(execute, stdout=sys.stdout, stderr=sys.stderr)
|
|
@ -1,344 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
Name: Video2X FFmpeg Controller
|
|
||||||
Author: K4YT3X
|
|
||||||
Date Created: Feb 24, 2018
|
|
||||||
Last Modified: January 23, 2021
|
|
||||||
|
|
||||||
Description: This class handles all FFmpeg related operations.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# built-in imports
|
|
||||||
import json
|
|
||||||
import pathlib
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
|
|
||||||
# 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, extracted_frame_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.extracted_frame_format = extracted_frame_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: {" ".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 get_number_of_frames(self, input_file: str) -> int:
|
|
||||||
"""Count the number of frames in a video
|
|
||||||
|
|
||||||
Args:
|
|
||||||
input_file (str): input file path
|
|
||||||
video_stream_index (int): index number of the video stream
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
int: number of frames in the video
|
|
||||||
"""
|
|
||||||
|
|
||||||
execute = [
|
|
||||||
self.ffmpeg_probe_binary,
|
|
||||||
"-v",
|
|
||||||
"quiet",
|
|
||||||
"-count_frames",
|
|
||||||
"-select_streams",
|
|
||||||
"v",
|
|
||||||
"-show_entries",
|
|
||||||
"stream=nb_read_frames",
|
|
||||||
"-of",
|
|
||||||
"default=nokey=1:noprint_wrappers=1",
|
|
||||||
input_file,
|
|
||||||
]
|
|
||||||
|
|
||||||
# turn elements into str
|
|
||||||
execute = [str(e) for e in execute]
|
|
||||||
|
|
||||||
Avalon.debug_info(f'Executing: {" ".join(execute)}')
|
|
||||||
return int(
|
|
||||||
subprocess.run(execute, check=True, stdout=subprocess.PIPE)
|
|
||||||
.stdout.decode()
|
|
||||||
.strip()
|
|
||||||
.split("\n")[0]
|
|
||||||
.split("\r")[0]
|
|
||||||
)
|
|
||||||
|
|
||||||
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: {" ".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.extracted_frame_format}"
|
|
||||||
# extracted_frames / f'frame_%06d.{self.extracted_frame_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.extracted_frame_format}"
|
|
||||||
# upscaled_frames / f'%06d.{self.extracted_frame_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: {" ".join(execute)}')
|
|
||||||
return subprocess.Popen(execute, stdout=sys.stdout, stderr=sys.stderr)
|
|
@ -1,117 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
Name: RealSR ncnn Vulkan Driver
|
|
||||||
Creator: K4YT3X
|
|
||||||
Date Created: May 26, 2020
|
|
||||||
Last Modified: September 21, 2020
|
|
||||||
|
|
||||||
Description: This class is a high-level wrapper
|
|
||||||
for realsr_ncnn_vulkan.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# built-in imports
|
|
||||||
import argparse
|
|
||||||
import os
|
|
||||||
import pathlib
|
|
||||||
import platform
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
import threading
|
|
||||||
|
|
||||||
# third-party imports
|
|
||||||
from avalon_framework import Avalon
|
|
||||||
|
|
||||||
|
|
||||||
class WrapperMain:
|
|
||||||
"""This class communicates with RealSR 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):
|
|
||||||
# fmt: off
|
|
||||||
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("-s", type=int, help="upscale ratio")
|
|
||||||
parser.add_argument("-t", type=int, help="tile size (>=32/0=auto)")
|
|
||||||
parser.add_argument("-m", type=str, help="realsr 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")
|
|
||||||
parser.add_argument("-f", type=str, help=argparse.SUPPRESS) # help="output image format (jpg/png/webp, default=ext/png)")
|
|
||||||
return parser.parse_args(arguments)
|
|
||||||
# fmt: on
|
|
||||||
|
|
||||||
def load_configurations(self, upscaler):
|
|
||||||
# self.driver_settings['s'] = int(upscaler.scale_ratio)
|
|
||||||
self.driver_settings["j"] = "{}:{}:{}".format(
|
|
||||||
upscaler.processes, upscaler.processes, upscaler.processes
|
|
||||||
)
|
|
||||||
self.driver_settings["f"] = upscaler.extracted_frame_format.lower()
|
|
||||||
|
|
||||||
def set_scale_ratio(self, scale_ratio: int):
|
|
||||||
self.driver_settings["s"] = int(scale_ratio)
|
|
||||||
|
|
||||||
def upscale(self, input_directory, output_directory):
|
|
||||||
"""This is the core function for RealSR ncnn Vulkan class
|
|
||||||
|
|
||||||
Arguments:
|
|
||||||
input_directory {string} -- source directory path
|
|
||||||
output_directory {string} -- output directory path
|
|
||||||
ratio {int} -- output video ratio
|
|
||||||
"""
|
|
||||||
|
|
||||||
# change the working directory to the binary's parent directory
|
|
||||||
# so the binary can find shared object files and other files
|
|
||||||
os.chdir(pathlib.Path(self.driver_settings["path"]).parent)
|
|
||||||
|
|
||||||
# overwrite config file settings
|
|
||||||
self.driver_settings["i"] = input_directory
|
|
||||||
self.driver_settings["o"] = output_directory
|
|
||||||
|
|
||||||
# by default, realsr-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: {" ".join(execute)}'
|
|
||||||
)
|
|
||||||
self.print_lock.release()
|
|
||||||
return subprocess.Popen(execute, stdout=sys.stdout, stderr=sys.stderr)
|
|
@ -1,118 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
Name: SRMD ncnn Vulkan Driver
|
|
||||||
Creator: K4YT3X
|
|
||||||
Date Created: April 26, 2020
|
|
||||||
Last Modified: September 21, 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 subprocess
|
|
||||||
import sys
|
|
||||||
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):
|
|
||||||
# fmt: off
|
|
||||||
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, 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")
|
|
||||||
parser.add_argument("-f", type=str, help=argparse.SUPPRESS) # help="output image format (jpg/png/webp, default=ext/png)")
|
|
||||||
return parser.parse_args(arguments)
|
|
||||||
# fmt: on
|
|
||||||
|
|
||||||
def load_configurations(self, upscaler):
|
|
||||||
# self.driver_settings['s'] = int(upscaler.scale_ratio)
|
|
||||||
self.driver_settings["j"] = "{}:{}:{}".format(
|
|
||||||
upscaler.processes, upscaler.processes, upscaler.processes
|
|
||||||
)
|
|
||||||
self.driver_settings["f"] = upscaler.extracted_frame_format.lower()
|
|
||||||
|
|
||||||
def set_scale_ratio(self, scale_ratio: int):
|
|
||||||
self.driver_settings["s"] = int(scale_ratio)
|
|
||||||
|
|
||||||
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
|
|
||||||
"""
|
|
||||||
|
|
||||||
# change the working directory to the binary's parent directory
|
|
||||||
# so the binary can find shared object files and other files
|
|
||||||
os.chdir(pathlib.Path(self.driver_settings["path"]).parent)
|
|
||||||
|
|
||||||
# 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: {" ".join(execute)}'
|
|
||||||
)
|
|
||||||
self.print_lock.release()
|
|
||||||
return subprocess.Popen(execute, stdout=sys.stdout, stderr=sys.stderr)
|
|
@ -1,123 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
Name: Waifu2x Caffe Driver
|
|
||||||
Author: K4YT3X
|
|
||||||
Date Created: Feb 24, 2018
|
|
||||||
Last Modified: September 12, 2020
|
|
||||||
|
|
||||||
Description: This class is a high-level wrapper
|
|
||||||
for waifu2x-caffe.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# built-in imports
|
|
||||||
import argparse
|
|
||||||
import os
|
|
||||||
import pathlib
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
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):
|
|
||||||
# fmt: off
|
|
||||||
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)
|
|
||||||
# fmt: on
|
|
||||||
|
|
||||||
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.extracted_frame_format
|
|
||||||
|
|
||||||
# bit_depth will be 12 at this point
|
|
||||||
# it will up updated later
|
|
||||||
self.driver_settings["output_depth"] = 12
|
|
||||||
|
|
||||||
def set_scale_resolution(self, width: int, height: int):
|
|
||||||
self.driver_settings["scale_width"] = width
|
|
||||||
self.driver_settings["scale_height"] = height
|
|
||||||
self.driver_settings["scale_ratio"] = None
|
|
||||||
|
|
||||||
def set_scale_ratio(self, scale_ratio: float):
|
|
||||||
self.driver_settings["scale_width"] = None
|
|
||||||
self.driver_settings["scale_height"] = None
|
|
||||||
self.driver_settings["scale_ratio"] = scale_ratio
|
|
||||||
|
|
||||||
def upscale(self, input_directory, output_directory):
|
|
||||||
"""start upscaling process"""
|
|
||||||
|
|
||||||
# change the working directory to the binary's parent directory
|
|
||||||
# so the binary can find shared object files and other files
|
|
||||||
os.chdir(pathlib.Path(self.driver_settings["path"]).parent)
|
|
||||||
|
|
||||||
# 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: {" ".join(execute)}'
|
|
||||||
)
|
|
||||||
self.print_lock.release()
|
|
||||||
return subprocess.Popen(execute, stdout=sys.stdout, stderr=sys.stderr)
|
|
@ -1,132 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
Name: Waifu2x Converter CPP Driver
|
|
||||||
Author: K4YT3X
|
|
||||||
Date Created: February 8, 2019
|
|
||||||
Last Modified: September 9, 2020
|
|
||||||
|
|
||||||
Description: This class is a high-level wrapper
|
|
||||||
for waifu2x-converter-cpp.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# built-in imports
|
|
||||||
import argparse
|
|
||||||
import os
|
|
||||||
import pathlib
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
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):
|
|
||||||
# fmt: off
|
|
||||||
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)
|
|
||||||
# fmt: on
|
|
||||||
|
|
||||||
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.extracted_frame_format.lower()
|
|
||||||
|
|
||||||
def set_scale_ratio(self, scale_ratio: float):
|
|
||||||
self.driver_settings["scale-ratio"] = scale_ratio
|
|
||||||
|
|
||||||
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
|
|
||||||
"""
|
|
||||||
|
|
||||||
# change the working directory to the binary's parent directory
|
|
||||||
# so the binary can find shared object files and other files
|
|
||||||
os.chdir(pathlib.Path(self.driver_settings["path"]).parent)
|
|
||||||
|
|
||||||
# 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: {" ".join(execute)}'
|
|
||||||
)
|
|
||||||
self.print_lock.release()
|
|
||||||
return subprocess.Popen(execute, stdout=sys.stdout, stderr=sys.stderr)
|
|
@ -1,121 +0,0 @@
|
|||||||
#!/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: September 21, 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 subprocess
|
|
||||||
import sys
|
|
||||||
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):
|
|
||||||
# fmt: off
|
|
||||||
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/webp) or directory")
|
|
||||||
parser.add_argument("-o", type=str, help=argparse.SUPPRESS) # help="output image path (jpg/png/webp) or directory")
|
|
||||||
parser.add_argument("-n", type=int, choices=range(-1, 4), help="denoise level")
|
|
||||||
parser.add_argument("-s", type=int, 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")
|
|
||||||
parser.add_argument("-f", type=str, help=argparse.SUPPRESS) # help="output image format (jpg/png/webp, default=ext/png)")
|
|
||||||
return parser.parse_args(arguments)
|
|
||||||
# fmt: on
|
|
||||||
|
|
||||||
def load_configurations(self, upscaler):
|
|
||||||
# self.driver_settings['s'] = int(upscaler.scale_ratio)
|
|
||||||
self.driver_settings["j"] = "{}:{}:{}".format(
|
|
||||||
upscaler.processes, upscaler.processes, upscaler.processes
|
|
||||||
)
|
|
||||||
self.driver_settings["f"] = upscaler.extracted_frame_format.lower()
|
|
||||||
|
|
||||||
def set_scale_ratio(self, scale_ratio: int):
|
|
||||||
self.driver_settings["s"] = int(scale_ratio)
|
|
||||||
|
|
||||||
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
|
|
||||||
"""
|
|
||||||
|
|
||||||
# change the working directory to the binary's parent directory
|
|
||||||
# so the binary can find shared object files and other files
|
|
||||||
os.chdir(pathlib.Path(self.driver_settings["path"]).parent)
|
|
||||||
|
|
||||||
# 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: {" ".join(execute)}'
|
|
||||||
)
|
|
||||||
self.print_lock.release()
|
|
||||||
return subprocess.Popen(execute, stdout=sys.stdout, stderr=sys.stderr)
|
|
Loading…
Reference in New Issue
Block a user