mirror of
https://github.com/k4yt3x/video2x.git
synced 2024-12-29 16:09:10 +00:00
commit
544a7081ed
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@ -1,6 +1,6 @@
|
|||||||
# These are supported funding model platforms
|
# These are supported funding model platforms
|
||||||
|
|
||||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
github: k4yt3x
|
||||||
patreon: k4yt3x
|
patreon: k4yt3x
|
||||||
open_collective: # Replace with a single Open Collective username
|
open_collective: # Replace with a single Open Collective username
|
||||||
ko_fi: # Replace with a single Ko-fi username
|
ko_fi: # Replace with a single Ko-fi username
|
||||||
|
26
.github/ISSUE_TEMPLATE/bug-report.md
vendored
26
.github/ISSUE_TEMPLATE/bug-report.md
vendored
@ -1,26 +0,0 @@
|
|||||||
---
|
|
||||||
name: Bug report
|
|
||||||
about: Use this template if you believe you've encountered a bug.
|
|
||||||
title: ''
|
|
||||||
labels: bug
|
|
||||||
assignees: K4YT3X
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Component Versions
|
|
||||||
|
|
||||||
Please at least fill in the release version and GUI or CLI version.
|
|
||||||
|
|
||||||
- **Video2X release version**:
|
|
||||||
- **Upscaler version**:
|
|
||||||
- **GUI version**:
|
|
||||||
- **CLI version**:
|
|
||||||
|
|
||||||
## Symptom
|
|
||||||
|
|
||||||
In this section, briefly describe what's going on.
|
|
||||||
|
|
||||||
## Error Log or Screenshots
|
|
||||||
|
|
||||||
Please upload or paste the error log here. You may also include screenshots.
|
|
||||||
**It is highly recommended to include your error log.**
|
|
16
.github/ISSUE_TEMPLATE/feature_request.md
vendored
16
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -1,16 +0,0 @@
|
|||||||
---
|
|
||||||
name: Feature request
|
|
||||||
about: Request a new feature to be added
|
|
||||||
title: ''
|
|
||||||
labels: enhancement
|
|
||||||
assignees: K4YT3X
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Description
|
|
||||||
|
|
||||||
Briefly describe the feature that you'd like Video2X to have.
|
|
||||||
|
|
||||||
## Sources
|
|
||||||
|
|
||||||
Paste links to descriptions of related documentations, websites and etc. here.
|
|
41
.github/workflows/ci.yml
vendored
Normal file
41
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
name: CI
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- dev/*
|
||||||
|
pull_request: {}
|
||||||
|
workflow_dispatch: {}
|
||||||
|
jobs:
|
||||||
|
ubuntu:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
DEBIAN_FRONTEND: noninteractive
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
- name: Setup Python
|
||||||
|
uses: actions/setup-python@v2
|
||||||
|
with:
|
||||||
|
python-version: 3.8
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y --no-install-recommends \
|
||||||
|
python3-opencv python3-pil python3-tqdm python3-dev \
|
||||||
|
libvulkan-dev glslang-dev glslang-tools swig
|
||||||
|
pip install wheel
|
||||||
|
- name: Build wheels
|
||||||
|
run: |
|
||||||
|
pip wheel -w /tmp/wheels \
|
||||||
|
rife-ncnn-vulkan-python@git+https://github.com/media2x/rife-ncnn-vulkan-python.git .
|
||||||
|
- name: Package artifacts
|
||||||
|
run: |
|
||||||
|
tar cJvf /tmp/video2x-nightly-wheels.txz /tmp/wheels/*
|
||||||
|
- name: Upload artifacts
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: video2x-nightly-wheels
|
||||||
|
path: /tmp/video2x-nightly-wheels.txz
|
69
.github/workflows/nightly.yml
vendored
69
.github/workflows/nightly.yml
vendored
@ -1,69 +0,0 @@
|
|||||||
# Name: Video2X Nightly Build
|
|
||||||
# Creator: K4YT3X
|
|
||||||
# Date Created: May 12, 2020
|
|
||||||
# Last Modified: May 28, 2020
|
|
||||||
|
|
||||||
name: Video2X Nightly Build
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [master]
|
|
||||||
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: src
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: windows-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Setup Python 3.8
|
|
||||||
uses: actions/setup-python@v2
|
|
||||||
with:
|
|
||||||
python-version: 3.8
|
|
||||||
- name: Install dependencies
|
|
||||||
run: |
|
|
||||||
python -m pip install -U pip
|
|
||||||
pip install -U pyinstaller pywin32
|
|
||||||
pip install -U -r requirements.txt
|
|
||||||
- name: Build Video2X CLI
|
|
||||||
run: |
|
|
||||||
pyinstaller --noconfirm --log-level=WARN `
|
|
||||||
--onefile `
|
|
||||||
--add-data="locale;locale" `
|
|
||||||
--add-data="wrappers;wrappers" `
|
|
||||||
--icon="images\video2x.ico" `
|
|
||||||
video2x.py
|
|
||||||
- name: Build Video2X GUI
|
|
||||||
run: |
|
|
||||||
pyinstaller --noconfirm --log-level=WARN `
|
|
||||||
--onefile `
|
|
||||||
--add-data="images;images" `
|
|
||||||
--add-data="locale;locale" `
|
|
||||||
--add-data="video2x_gui.ui;." `
|
|
||||||
--add-data="wrappers;wrappers" `
|
|
||||||
--icon="images\video2x.ico" `
|
|
||||||
video2x_gui.py
|
|
||||||
- name: Build Video2X setup script
|
|
||||||
run: |
|
|
||||||
pyinstaller --noconfirm --log-level=WARN `
|
|
||||||
--onefile `
|
|
||||||
--additional-hooks-dir "pyinstaller\hooks" `
|
|
||||||
--add-data="locale;locale" `
|
|
||||||
--add-data="pyinstaller\7z1900-extra;7z" `
|
|
||||||
--icon="images\video2x.ico" `
|
|
||||||
video2x_setup.py
|
|
||||||
- name: Collect artifacts into folder
|
|
||||||
run: |
|
|
||||||
New-Item "video2x-nightly-win32-light\" -ItemType Directory
|
|
||||||
Copy-Item "dist\video2x.exe" -Destination "video2x-nightly-win32-light\"
|
|
||||||
Copy-Item "dist\video2x_gui.exe" -Destination "video2x-nightly-win32-light\"
|
|
||||||
Copy-Item "dist\video2x_setup.exe" -Destination "video2x-nightly-win32-light\"
|
|
||||||
Copy-Item "video2x.yaml" -Destination "video2x-nightly-win32-light\"
|
|
||||||
- name: Upload artifacts
|
|
||||||
uses: actions/upload-artifact@v2
|
|
||||||
with:
|
|
||||||
name: video2x-nightly-win32-light
|
|
||||||
path: src/video2x-nightly-win32-light/
|
|
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
|
||||||
|
|
||||||
|
67
Dockerfile
67
Dockerfile
@ -1,34 +1,43 @@
|
|||||||
# Name: Video2X Dockerfile
|
# Name: Video2X Dockerfile (CUDA)
|
||||||
# Creator: Danielle Douglas
|
# Creator: K4YT3X
|
||||||
# Date Created: Unknown
|
# Date Created: February 3, 2022
|
||||||
# Last Modified: January 14, 2020
|
# Last Modified: February 4, 2022
|
||||||
|
|
||||||
# Editor: Lhanjian
|
# stage 1: build the python components into wheels
|
||||||
# Last Modified: May 24, 2020
|
FROM nvidia/cuda:11.6.0-runtime-ubuntu20.04 AS builder
|
||||||
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
# Editor: K4YT3X
|
COPY . /video2x
|
||||||
# Last Modified: June 13, 2020
|
WORKDIR /video2x
|
||||||
|
|
||||||
# using Ubuntu LTS 19.10
|
|
||||||
# Ubuntu 20.x is incompatible with Nvidia libraries
|
|
||||||
FROM ubuntu:19.10
|
|
||||||
|
|
||||||
# file mainainter labels
|
|
||||||
LABEL maintainer="Danielle Douglas <ddouglas87@gmail.com>"
|
|
||||||
LABEL maintainer="Lhanjian <lhjay1@foxmail.com>"
|
|
||||||
LABEL maintainer="K4YT3X <k4yt3x@k4yt3x.com>"
|
|
||||||
|
|
||||||
RUN sed -i 's/archive.ubuntu.com/old-releases.ubuntu.com/g' /etc/apt/sources.list
|
|
||||||
RUN sed -i 's/security.ubuntu.com/old-releases.ubuntu.com/g' /etc/apt/sources.list
|
|
||||||
|
|
||||||
# run installation
|
|
||||||
RUN apt-get update \
|
RUN apt-get update \
|
||||||
&& apt-get install -y git-core \
|
&& apt-get install -y --no-install-recommends \
|
||||||
&& git clone --recurse-submodules --progress https://github.com/k4yt3x/video2x.git /tmp/video2x/video2x \
|
python3-pip python3-opencv python3-pil python3-tqdm \
|
||||||
&& bash -e /tmp/video2x/video2x/src/video2x_setup_ubuntu.sh /
|
python3-dev libvulkan-dev glslang-dev glslang-tools \
|
||||||
|
build-essential swig git \
|
||||||
|
&& git config --global http.postBuffer 1048576000 \
|
||||||
|
&& git config --global https.postBuffer 1048576000 \
|
||||||
|
&& pip wheel -w /wheels \
|
||||||
|
wheel setuptools setuptools_scm \
|
||||||
|
rife-ncnn-vulkan-python@git+https://github.com/media2x/rife-ncnn-vulkan-python.git .
|
||||||
|
|
||||||
|
# stage 2: install wheels into the final image
|
||||||
|
FROM nvidia/cuda:11.6.0-runtime-ubuntu20.04
|
||||||
|
LABEL maintainer="K4YT3X <i@k4yt3x.com>" \
|
||||||
|
org.opencontainers.image.source="https://github.com/k4yt3x/video2x" \
|
||||||
|
org.opencontainers.image.description="A lossless video/GIF/image upscaler"
|
||||||
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
COPY --from=builder /var/lib/apt/lists* /var/lib/apt/lists/
|
||||||
|
COPY --from=builder /wheels /wheels
|
||||||
|
COPY . /video2x
|
||||||
|
WORKDIR /video2x
|
||||||
|
RUN apt-get install -y --no-install-recommends \
|
||||||
|
python3-pip python3-dev \
|
||||||
|
python3-opencv python3-pil python3-tqdm \
|
||||||
|
mesa-vulkan-drivers ffmpeg \
|
||||||
|
&& pip install --no-cache-dir --no-index -f /wheels . \
|
||||||
|
&& apt-get clean \
|
||||||
|
&& rm -rf /wheels /video2x /var/lib/apt/lists/*
|
||||||
|
|
||||||
WORKDIR /host
|
WORKDIR /host
|
||||||
ENTRYPOINT ["python3.8", "/video2x/src/video2x.py"]
|
ENTRYPOINT ["/usr/bin/python3", "-m", "video2x"]
|
||||||
|
|
||||||
ENV NVIDIA_DRIVER_CAPABILITIES all
|
|
||||||
ENV DEBIAN_FRONTEND teletype
|
|
||||||
|
36
Dockerfile.alpine
Normal file
36
Dockerfile.alpine
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
# Name: Video2X Dockerfile (Slim Alpine)
|
||||||
|
# Creator: K4YT3X
|
||||||
|
# Date Created: February 1, 2022
|
||||||
|
# Last Modified: February 4, 2022
|
||||||
|
|
||||||
|
# stage: build python components into heels
|
||||||
|
FROM python:3.10.2-alpine3.15 AS builder
|
||||||
|
COPY . /video2x
|
||||||
|
WORKDIR /video2x
|
||||||
|
RUN apk add --no-cache \
|
||||||
|
cmake g++ gcc git ninja swig \
|
||||||
|
ffmpeg-dev glslang-dev jpeg-dev vulkan-loader-dev zlib-dev \
|
||||||
|
linux-headers \
|
||||||
|
&& pip install -U pip \
|
||||||
|
&& CMAKE_ARGS="-DWITH_FFMPEG=YES" pip wheel -w /wheels opencv-python \
|
||||||
|
&& pip wheel -w /wheels wheel setuptools setuptools_scm \
|
||||||
|
rife-ncnn-vulkan-python@git+https://github.com/media2x/rife-ncnn-vulkan-python.git .
|
||||||
|
|
||||||
|
# stage 2: install wheels into final image
|
||||||
|
FROM python:3.10.2-alpine3.15
|
||||||
|
LABEL maintainer="K4YT3X <i@k4yt3x.com>"
|
||||||
|
org.opencontainers.image.source="https://github.com/k4yt3x/video2x" \
|
||||||
|
org.opencontainers.image.description="A lossless video/GIF/image upscaler"
|
||||||
|
|
||||||
|
COPY --from=builder /wheels /wheels
|
||||||
|
COPY . /video2x
|
||||||
|
WORKDIR /video2x
|
||||||
|
RUN apk add --no-cache --virtual .run-deps \
|
||||||
|
ffmpeg libgomp libjpeg-turbo libstdc++ \
|
||||||
|
vulkan-loader mesa-vulkan-ati \
|
||||||
|
&& pip install --no-cache-dir -U pip \
|
||||||
|
&& pip install --no-cache-dir --no-index -f /wheels . \
|
||||||
|
&& rm -rf /wheels /video2x
|
||||||
|
|
||||||
|
WORKDIR /host
|
||||||
|
ENTRYPOINT ["/usr/local/bin/python", "-m", "video2x"]
|
147
LICENSE
147
LICENSE
@ -1,23 +1,21 @@
|
|||||||
GNU GENERAL PUBLIC LICENSE
|
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
Version 3, 29 June 2007
|
Version 3, 19 November 2007
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
of this license document, but changing it is not allowed.
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
Preamble
|
Preamble
|
||||||
|
|
||||||
The GNU General Public License is a free, copyleft license for
|
The GNU Affero General Public License is a free, copyleft license for
|
||||||
software and other kinds of works.
|
software and other kinds of works, specifically designed to ensure
|
||||||
|
cooperation with the community in the case of network server software.
|
||||||
|
|
||||||
The licenses for most software and other practical works are designed
|
The licenses for most software and other practical works are designed
|
||||||
to take away your freedom to share and change the works. By contrast,
|
to take away your freedom to share and change the works. By contrast,
|
||||||
the GNU General Public License is intended to guarantee your freedom to
|
our General Public Licenses are intended to guarantee your freedom to
|
||||||
share and change all versions of a program--to make sure it remains free
|
share and change all versions of a program--to make sure it remains free
|
||||||
software for all its users. We, the Free Software Foundation, use the
|
software for all its users.
|
||||||
GNU General Public License for most of our software; it applies also to
|
|
||||||
any other work released this way by its authors. You can apply it to
|
|
||||||
your programs, too.
|
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom, not
|
When we speak of free software, we are referring to freedom, not
|
||||||
price. Our General Public Licenses are designed to make sure that you
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
@ -26,44 +24,34 @@ them if you wish), that you receive source code or can get it if you
|
|||||||
want it, that you can change the software or use pieces of it in new
|
want it, that you can change the software or use pieces of it in new
|
||||||
free programs, and that you know you can do these things.
|
free programs, and that you know you can do these things.
|
||||||
|
|
||||||
To protect your rights, we need to prevent others from denying you
|
Developers that use our General Public Licenses protect your rights
|
||||||
these rights or asking you to surrender the rights. Therefore, you have
|
with two steps: (1) assert copyright on the software, and (2) offer
|
||||||
certain responsibilities if you distribute copies of the software, or if
|
you this License which gives you legal permission to copy, distribute
|
||||||
you modify it: responsibilities to respect the freedom of others.
|
and/or modify the software.
|
||||||
|
|
||||||
For example, if you distribute copies of such a program, whether
|
A secondary benefit of defending all users' freedom is that
|
||||||
gratis or for a fee, you must pass on to the recipients the same
|
improvements made in alternate versions of the program, if they
|
||||||
freedoms that you received. You must make sure that they, too, receive
|
receive widespread use, become available for other developers to
|
||||||
or can get the source code. And you must show them these terms so they
|
incorporate. Many developers of free software are heartened and
|
||||||
know their rights.
|
encouraged by the resulting cooperation. However, in the case of
|
||||||
|
software used on network servers, this result may fail to come about.
|
||||||
|
The GNU General Public License permits making a modified version and
|
||||||
|
letting the public access it on a server without ever releasing its
|
||||||
|
source code to the public.
|
||||||
|
|
||||||
Developers that use the GNU GPL protect your rights with two steps:
|
The GNU Affero General Public License is designed specifically to
|
||||||
(1) assert copyright on the software, and (2) offer you this License
|
ensure that, in such cases, the modified source code becomes available
|
||||||
giving you legal permission to copy, distribute and/or modify it.
|
to the community. It requires the operator of a network server to
|
||||||
|
provide the source code of the modified version running there to the
|
||||||
|
users of that server. Therefore, public use of a modified version, on
|
||||||
|
a publicly accessible server, gives the public access to the source
|
||||||
|
code of the modified version.
|
||||||
|
|
||||||
For the developers' and authors' protection, the GPL clearly explains
|
An older license, called the Affero General Public License and
|
||||||
that there is no warranty for this free software. For both users' and
|
published by Affero, was designed to accomplish similar goals. This is
|
||||||
authors' sake, the GPL requires that modified versions be marked as
|
a different license, not a version of the Affero GPL, but Affero has
|
||||||
changed, so that their problems will not be attributed erroneously to
|
released a new version of the Affero GPL which permits relicensing under
|
||||||
authors of previous versions.
|
this license.
|
||||||
|
|
||||||
Some devices are designed to deny users access to install or run
|
|
||||||
modified versions of the software inside them, although the manufacturer
|
|
||||||
can do so. This is fundamentally incompatible with the aim of
|
|
||||||
protecting users' freedom to change the software. The systematic
|
|
||||||
pattern of such abuse occurs in the area of products for individuals to
|
|
||||||
use, which is precisely where it is most unacceptable. Therefore, we
|
|
||||||
have designed this version of the GPL to prohibit the practice for those
|
|
||||||
products. If such problems arise substantially in other domains, we
|
|
||||||
stand ready to extend this provision to those domains in future versions
|
|
||||||
of the GPL, as needed to protect the freedom of users.
|
|
||||||
|
|
||||||
Finally, every program is threatened constantly by software patents.
|
|
||||||
States should not allow patents to restrict development and use of
|
|
||||||
software on general-purpose computers, but in those that do, we wish to
|
|
||||||
avoid the special danger that patents applied to a free program could
|
|
||||||
make it effectively proprietary. To prevent this, the GPL assures that
|
|
||||||
patents cannot be used to render the program non-free.
|
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
The precise terms and conditions for copying, distribution and
|
||||||
modification follow.
|
modification follow.
|
||||||
@ -72,7 +60,7 @@ modification follow.
|
|||||||
|
|
||||||
0. Definitions.
|
0. Definitions.
|
||||||
|
|
||||||
"This License" refers to version 3 of the GNU General Public License.
|
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||||
|
|
||||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||||
works, such as semiconductor masks.
|
works, such as semiconductor masks.
|
||||||
@ -549,35 +537,45 @@ to collect a royalty for further conveying from those to whom you convey
|
|||||||
the Program, the only way you could satisfy both those terms and this
|
the Program, the only way you could satisfy both those terms and this
|
||||||
License would be to refrain entirely from conveying the Program.
|
License would be to refrain entirely from conveying the Program.
|
||||||
|
|
||||||
13. Use with the GNU Affero General Public License.
|
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, if you modify the
|
||||||
|
Program, your modified version must prominently offer all users
|
||||||
|
interacting with it remotely through a computer network (if your version
|
||||||
|
supports such interaction) an opportunity to receive the Corresponding
|
||||||
|
Source of your version by providing access to the Corresponding Source
|
||||||
|
from a network server at no charge, through some standard or customary
|
||||||
|
means of facilitating copying of software. This Corresponding Source
|
||||||
|
shall include the Corresponding Source for any work covered by version 3
|
||||||
|
of the GNU General Public License that is incorporated pursuant to the
|
||||||
|
following paragraph.
|
||||||
|
|
||||||
Notwithstanding any other provision of this License, you have
|
Notwithstanding any other provision of this License, you have
|
||||||
permission to link or combine any covered work with a work licensed
|
permission to link or combine any covered work with a work licensed
|
||||||
under version 3 of the GNU Affero General Public License into a single
|
under version 3 of the GNU General Public License into a single
|
||||||
combined work, and to convey the resulting work. The terms of this
|
combined work, and to convey the resulting work. The terms of this
|
||||||
License will continue to apply to the part which is the covered work,
|
License will continue to apply to the part which is the covered work,
|
||||||
but the special requirements of the GNU Affero General Public License,
|
but the work with which it is combined will remain governed by version
|
||||||
section 13, concerning interaction through a network will apply to the
|
3 of the GNU General Public License.
|
||||||
combination as such.
|
|
||||||
|
|
||||||
14. Revised Versions of this License.
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
The Free Software Foundation may publish revised and/or new versions of
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
the GNU General Public License from time to time. Such new versions will
|
the GNU Affero General Public License from time to time. Such new versions
|
||||||
be similar in spirit to the present version, but may differ in detail to
|
will be similar in spirit to the present version, but may differ in detail to
|
||||||
address new problems or concerns.
|
address new problems or concerns.
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the
|
Each version is given a distinguishing version number. If the
|
||||||
Program specifies that a certain numbered version of the GNU General
|
Program specifies that a certain numbered version of the GNU Affero General
|
||||||
Public License "or any later version" applies to it, you have the
|
Public License "or any later version" applies to it, you have the
|
||||||
option of following the terms and conditions either of that numbered
|
option of following the terms and conditions either of that numbered
|
||||||
version or of any later version published by the Free Software
|
version or of any later version published by the Free Software
|
||||||
Foundation. If the Program does not specify a version number of the
|
Foundation. If the Program does not specify a version number of the
|
||||||
GNU General Public License, you may choose any version ever published
|
GNU Affero General Public License, you may choose any version ever published
|
||||||
by the Free Software Foundation.
|
by the Free Software Foundation.
|
||||||
|
|
||||||
If the Program specifies that a proxy can decide which future
|
If the Program specifies that a proxy can decide which future
|
||||||
versions of the GNU General Public License can be used, that proxy's
|
versions of the GNU Affero General Public License can be used, that proxy's
|
||||||
public statement of acceptance of a version permanently authorizes you
|
public statement of acceptance of a version permanently authorizes you
|
||||||
to choose that version for the Program.
|
to choose that version for the Program.
|
||||||
|
|
||||||
@ -635,40 +633,29 @@ the "copyright" line and a pointer to where the full notice is found.
|
|||||||
Copyright (C) <year> <name of author>
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU Affero General Public License as published by
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
(at your option) any later version.
|
(at your option) any later version.
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
This program is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU Affero General Public License
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
If the program does terminal interaction, make it output a short
|
If your software can interact with users remotely through a computer
|
||||||
notice like this when it starts in an interactive mode:
|
network, you should also make sure that it provides a way for users to
|
||||||
|
get its source. For example, if your program is a web application, its
|
||||||
<program> Copyright (C) <year> <name of author>
|
interface could display a "Source" link that leads users to an archive
|
||||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
of the code. There are many ways you could offer source, and different
|
||||||
This is free software, and you are welcome to redistribute it
|
solutions will be better for different programs; see section 13 for the
|
||||||
under certain conditions; type `show c' for details.
|
specific requirements.
|
||||||
|
|
||||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
|
||||||
parts of the General Public License. Of course, your program's commands
|
|
||||||
might be different; for a GUI interface, you would use an "about box".
|
|
||||||
|
|
||||||
You should also get your employer (if you work as a programmer) or school,
|
You should also get your employer (if you work as a programmer) or school,
|
||||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||||
For more information on this, and how to apply and follow the GNU GPL, see
|
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||||
<http://www.gnu.org/licenses/>.
|
<https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
The GNU General Public License does not permit incorporating your program
|
|
||||||
into proprietary programs. If your program is a subroutine library, you
|
|
||||||
may consider it more useful to permit linking proprietary applications with
|
|
||||||
the library. If this is what you want to do, use the GNU Lesser General
|
|
||||||
Public License instead of this License. But first, please read
|
|
||||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
|
||||||
|
20
_config.yml
20
_config.yml
@ -1,20 +0,0 @@
|
|||||||
# site settings
|
|
||||||
locale: "en-US"
|
|
||||||
title: "Video2X"
|
|
||||||
title_separator: "-"
|
|
||||||
subtitle: "Machine learning video/GIF/image upscaling"
|
|
||||||
name: "K4YT3X"
|
|
||||||
description: "An amazing website."
|
|
||||||
url: "https://video2x.org"
|
|
||||||
repository: "k4yt3x/video2x"
|
|
||||||
|
|
||||||
# set rendering style to be GitHub flavor
|
|
||||||
kramdown:
|
|
||||||
input: GFM
|
|
||||||
|
|
||||||
# use Minimal Mistakes theme
|
|
||||||
remote_theme: mmistakes/minimal-mistakes
|
|
||||||
|
|
||||||
# plugin required for the Minimal Mistakes theme
|
|
||||||
plugins:
|
|
||||||
- jekyll-include-cache
|
|
3
pyproject.toml
Normal file
3
pyproject.toml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[build-system]
|
||||||
|
requires = ["setuptools>=44", "wheel", "setuptools_scm[toml]>=3.4.3"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
44
setup.cfg
Normal file
44
setup.cfg
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
# Name: Video2X PyPI setup file
|
||||||
|
# Creator: K4YT3X
|
||||||
|
# Date Created: June 17, 2021
|
||||||
|
# Last Modified: February 4, 2022
|
||||||
|
|
||||||
|
# build & publish commands
|
||||||
|
# pip install --user -U setuptools wheel twine build
|
||||||
|
# python -m build .
|
||||||
|
# twine upload --repository pypi dist/*
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
name = video2x
|
||||||
|
version = 5.0.0-beta1
|
||||||
|
author = K4YT3X
|
||||||
|
author_email = i@k4yt3x.com
|
||||||
|
license = GNU General Public License v3.0
|
||||||
|
description = A lossless video/GIF/image upscaler
|
||||||
|
url = https://github.com/k4yt3x/video2x
|
||||||
|
long_description = file: README.md
|
||||||
|
long_description_content_type = text/markdown
|
||||||
|
classifiers =
|
||||||
|
Topic :: Multimedia :: Video
|
||||||
|
Environment :: Console
|
||||||
|
Programming Language :: Python
|
||||||
|
Programming Language :: Python :: 3
|
||||||
|
Operating System :: OS Independent
|
||||||
|
|
||||||
|
[options]
|
||||||
|
packages = find:
|
||||||
|
install_requires =
|
||||||
|
ffmpeg-python
|
||||||
|
loguru
|
||||||
|
opencv-python
|
||||||
|
pillow
|
||||||
|
rich
|
||||||
|
tqdm
|
||||||
|
realsr-ncnn-vulkan-python
|
||||||
|
rife-ncnn-vulkan-python
|
||||||
|
srmd-ncnn-vulkan-python
|
||||||
|
waifu2x-ncnn-vulkan-python
|
||||||
|
python_requires = >=3.6
|
||||||
|
|
||||||
|
[options.entry_points]
|
||||||
|
console_scripts = video2x = video2x:main
|
@ -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
|
|
@ -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"
|
|
@ -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 |
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 +0,0 @@
|
|||||||
avalon_framework
|
|
||||||
colorama
|
|
||||||
patool
|
|
||||||
pillow
|
|
||||||
pyqt5
|
|
||||||
python-magic-bin; platform_system == "Windows"
|
|
||||||
python-magic; platform_system != "Windows"
|
|
||||||
pyyaml
|
|
||||||
requests
|
|
||||||
tqdm
|
|
1027
src/upscaler.py
1027
src/upscaler.py
File diff suppressed because it is too large
Load Diff
379
src/video2x.pot
379
src/video2x.pot
@ -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 ""
|
|
||||||
|
|
380
src/video2x.py
380
src/video2x.py
@ -1,380 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
r"""
|
|
||||||
|
|
||||||
__ __ _ _ ___ __ __
|
|
||||||
\ \ / / (_) | | |__ \ \ \ / /
|
|
||||||
\ \ / / _ __| | ___ ___ ) | \ V /
|
|
||||||
\ \/ / | | / _` | / _ \ / _ \ / / > <
|
|
||||||
\ / | | | (_| | | __/ | (_) | / /_ / . \
|
|
||||||
\/ |_| \__,_| \___| \___/ |____| /_/ \_\
|
|
||||||
|
|
||||||
|
|
||||||
Name: Video2X Controller
|
|
||||||
Creator: K4YT3X
|
|
||||||
Date Created: Feb 24, 2018
|
|
||||||
Last Modified: January 23, 2021
|
|
||||||
|
|
||||||
Editor: BrianPetkovsek
|
|
||||||
Last Modified: June 17, 2019
|
|
||||||
|
|
||||||
Editor: SAT3LL
|
|
||||||
Last Modified: June 25, 2019
|
|
||||||
|
|
||||||
Editor: 28598519a
|
|
||||||
Last Modified: March 23, 2020
|
|
||||||
|
|
||||||
Licensed under the GNU General Public License Version 3 (GNU GPL v3),
|
|
||||||
available at: https://www.gnu.org/licenses/gpl-3.0.txt
|
|
||||||
|
|
||||||
(C) 2018-2021 K4YT3X
|
|
||||||
|
|
||||||
Video2X is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
Video2X is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
Description: Video2X is an automation software based on waifu2x image
|
|
||||||
enlarging engine. It extracts frames from a video, enlarge it by a
|
|
||||||
number of times without losing any details or quality, keeping lines
|
|
||||||
smooth and edges sharp.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# local imports
|
|
||||||
from bilogger import BiLogger
|
|
||||||
from upscaler import AVAILABLE_DRIVERS
|
|
||||||
from upscaler import UPSCALER_VERSION
|
|
||||||
from upscaler import Upscaler
|
|
||||||
|
|
||||||
# built-in imports
|
|
||||||
import argparse
|
|
||||||
import gettext
|
|
||||||
import importlib
|
|
||||||
import locale
|
|
||||||
import os
|
|
||||||
import pathlib
|
|
||||||
import sys
|
|
||||||
import tempfile
|
|
||||||
import time
|
|
||||||
import traceback
|
|
||||||
import yaml
|
|
||||||
|
|
||||||
# third-party imports
|
|
||||||
from avalon_framework import Avalon
|
|
||||||
|
|
||||||
# internationalization constants
|
|
||||||
DOMAIN = "video2x"
|
|
||||||
LOCALE_DIRECTORY = pathlib.Path(__file__).parent.absolute() / "locale"
|
|
||||||
|
|
||||||
# getting default locale settings
|
|
||||||
default_locale, encoding = locale.getdefaultlocale()
|
|
||||||
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 CLI Version: {}
|
|
||||||
Upscaler Version: {}
|
|
||||||
Author: K4YT3X
|
|
||||||
License: GNU GPL v3
|
|
||||||
Github Page: https://github.com/k4yt3x/video2x
|
|
||||||
Contact: k4yt3x@k4yt3x.com"""
|
|
||||||
).format(CLI_VERSION, UPSCALER_VERSION)
|
|
||||||
|
|
||||||
LOGO = r"""
|
|
||||||
__ __ _ _ ___ __ __
|
|
||||||
\ \ / / (_) | | |__ \ \ \ / /
|
|
||||||
\ \ / / _ __| | ___ ___ ) | \ V /
|
|
||||||
\ \/ / | | / _` | / _ \ / _ \ / / > <
|
|
||||||
\ / | | | (_| | | __/ | (_) | / /_ / . \
|
|
||||||
\/ |_| \__,_| \___| \___/ |____| /_/ \_\
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def parse_arguments():
|
|
||||||
"""parse CLI arguments"""
|
|
||||||
parser = argparse.ArgumentParser(
|
|
||||||
prog="video2x",
|
|
||||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
||||||
add_help=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
# video options
|
|
||||||
video2x_options = parser.add_argument_group(_("Video2X Options"))
|
|
||||||
|
|
||||||
video2x_options.add_argument(
|
|
||||||
"--help", action="help", help=_("show this help message and exit")
|
|
||||||
)
|
|
||||||
|
|
||||||
# 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",
|
|
||||||
"--input",
|
|
||||||
type=pathlib.Path,
|
|
||||||
help=_("source video file/directory"),
|
|
||||||
required=require_input_output,
|
|
||||||
)
|
|
||||||
|
|
||||||
video2x_options.add_argument(
|
|
||||||
"-o",
|
|
||||||
"--output",
|
|
||||||
type=pathlib.Path,
|
|
||||||
help=_("output video file/directory"),
|
|
||||||
required=require_input_output,
|
|
||||||
)
|
|
||||||
|
|
||||||
video2x_options.add_argument(
|
|
||||||
"-c",
|
|
||||||
"--config",
|
|
||||||
type=pathlib.Path,
|
|
||||||
help=_("Video2X config file path"),
|
|
||||||
action="store",
|
|
||||||
default=pathlib.Path(__file__).parent.absolute() / "video2x.yaml",
|
|
||||||
)
|
|
||||||
|
|
||||||
video2x_options.add_argument("--log", type=pathlib.Path, help=_("log file path"))
|
|
||||||
|
|
||||||
video2x_options.add_argument(
|
|
||||||
"-v",
|
|
||||||
"--version",
|
|
||||||
help=_("display version, lawful information and exit"),
|
|
||||||
action="store_true",
|
|
||||||
)
|
|
||||||
|
|
||||||
# scaling options
|
|
||||||
upscaling_options = parser.add_argument_group(_("Upscaling Options"))
|
|
||||||
|
|
||||||
upscaling_options.add_argument(
|
|
||||||
"-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",
|
|
||||||
"--driver",
|
|
||||||
help=_("upscaling driver"),
|
|
||||||
choices=AVAILABLE_DRIVERS,
|
|
||||||
default="waifu2x_ncnn_vulkan",
|
|
||||||
)
|
|
||||||
|
|
||||||
upscaling_options.add_argument(
|
|
||||||
"-p",
|
|
||||||
"--processes",
|
|
||||||
help=_("number of processes to use for upscaling"),
|
|
||||||
action="store",
|
|
||||||
type=int,
|
|
||||||
default=1,
|
|
||||||
)
|
|
||||||
|
|
||||||
upscaling_options.add_argument(
|
|
||||||
"--preserve_frames",
|
|
||||||
help=_("preserve extracted and upscaled frames"),
|
|
||||||
action="store_true",
|
|
||||||
)
|
|
||||||
|
|
||||||
# if no driver arguments are specified
|
|
||||||
if "--" not in sys.argv:
|
|
||||||
video2x_args = parser.parse_args()
|
|
||||||
return video2x_args, None
|
|
||||||
|
|
||||||
# if driver arguments are specified
|
|
||||||
else:
|
|
||||||
video2x_args = parser.parse_args(sys.argv[1 : sys.argv.index("--")])
|
|
||||||
wrapper = getattr(
|
|
||||||
importlib.import_module(f"wrappers.{video2x_args.driver}"), "WrapperMain"
|
|
||||||
)
|
|
||||||
driver_args = wrapper.parse_arguments(sys.argv[sys.argv.index("--") + 1 :])
|
|
||||||
return video2x_args, driver_args
|
|
||||||
|
|
||||||
|
|
||||||
def print_logo():
|
|
||||||
"""print video2x logo"""
|
|
||||||
print(LOGO)
|
|
||||||
print(f'\n{"Video2X Video Enlarger".rjust(40, " ")}')
|
|
||||||
print(f'\n{Avalon.FM.BD}{f"Version {CLI_VERSION}".rjust(36, " ")}{Avalon.FM.RST}\n')
|
|
||||||
|
|
||||||
|
|
||||||
def read_config(config_file: pathlib.Path) -> dict:
|
|
||||||
"""read video2x configurations from config file
|
|
||||||
|
|
||||||
Arguments:
|
|
||||||
config_file {pathlib.Path} -- video2x configuration file pathlib.Path
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
dict -- dictionary of video2x configuration
|
|
||||||
"""
|
|
||||||
|
|
||||||
with open(config_file, "r") as config:
|
|
||||||
return yaml.load(config, Loader=yaml.FullLoader)
|
|
||||||
|
|
||||||
|
|
||||||
# /////////////////// Execution /////////////////// #
|
|
||||||
|
|
||||||
# this is not a library
|
|
||||||
if __name__ != "__main__":
|
|
||||||
Avalon.error(_("This file cannot be imported"))
|
|
||||||
raise ImportError(f"{__file__} cannot be imported")
|
|
||||||
|
|
||||||
# print video2x logo
|
|
||||||
print_logo()
|
|
||||||
|
|
||||||
# parse command line arguments
|
|
||||||
video2x_args, driver_args = parse_arguments()
|
|
||||||
|
|
||||||
# display version and lawful informaition
|
|
||||||
if video2x_args.version:
|
|
||||||
print(LEGAL_INFO)
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
# 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
|
|
||||||
upscaler = Upscaler(
|
|
||||||
# required parameters
|
|
||||||
input_path=video2x_args.input,
|
|
||||||
output_path=video2x_args.output,
|
|
||||||
driver_settings=driver_settings,
|
|
||||||
ffmpeg_settings=ffmpeg_settings,
|
|
||||||
gifski_settings=gifski_settings,
|
|
||||||
# optional parameters
|
|
||||||
driver=video2x_args.driver,
|
|
||||||
scale_ratio=video2x_args.ratio,
|
|
||||||
scale_width=video2x_args.width,
|
|
||||||
scale_height=video2x_args.height,
|
|
||||||
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
|
|
||||||
upscaler.run()
|
|
||||||
|
|
||||||
Avalon.info(
|
|
||||||
_("Program completed, taking {} seconds").format(
|
|
||||||
round((time.time() - begin_time), 5)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
except Exception:
|
|
||||||
|
|
||||||
Avalon.error(_("An exception has occurred"))
|
|
||||||
traceback.print_exc()
|
|
||||||
|
|
||||||
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()
|
|
185
src/video2x.yaml
185
src/video2x.yaml
@ -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
|
|
1996
src/video2x_gui.py
1996
src/video2x_gui.py
File diff suppressed because it is too large
Load Diff
@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"files": ["video2x_gui.ui","video2x_gui.py"]
|
|
||||||
}
|
|
2949
src/video2x_gui.ui
2949
src/video2x_gui.ui
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,82 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
Name: Gifski Wrapper
|
|
||||||
Creator: K4YT3X
|
|
||||||
Date Created: May 11, 2020
|
|
||||||
Last Modified: September 13, 2020
|
|
||||||
|
|
||||||
Description: High-level wrapper for Gifski.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# built-in imports
|
|
||||||
import pathlib
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
|
|
||||||
# third-party imports
|
|
||||||
from avalon_framework import Avalon
|
|
||||||
|
|
||||||
|
|
||||||
class Gifski:
|
|
||||||
def __init__(self, gifski_settings):
|
|
||||||
self.gifski_settings = gifski_settings
|
|
||||||
|
|
||||||
def make_gif(
|
|
||||||
self,
|
|
||||||
upscaled_frames: pathlib.Path,
|
|
||||||
output_path: pathlib.Path,
|
|
||||||
framerate: float,
|
|
||||||
extracted_frame_format: str,
|
|
||||||
output_width: int,
|
|
||||||
output_height: int,
|
|
||||||
) -> subprocess.Popen:
|
|
||||||
execute = [
|
|
||||||
self.gifski_settings["gifski_path"],
|
|
||||||
"-o",
|
|
||||||
output_path,
|
|
||||||
"--fps",
|
|
||||||
int(round(framerate, 0)),
|
|
||||||
"--width",
|
|
||||||
output_width,
|
|
||||||
"--height",
|
|
||||||
output_height,
|
|
||||||
]
|
|
||||||
|
|
||||||
# load configurations from config file
|
|
||||||
execute.extend(self._load_configuration())
|
|
||||||
|
|
||||||
# append frames location
|
|
||||||
execute.extend([upscaled_frames / f"extracted_*.{extracted_frame_format}"])
|
|
||||||
|
|
||||||
return self._execute(execute)
|
|
||||||
|
|
||||||
def _load_configuration(self):
|
|
||||||
|
|
||||||
configuration = []
|
|
||||||
|
|
||||||
for key in self.gifski_settings.keys():
|
|
||||||
|
|
||||||
value = self.gifski_settings[key]
|
|
||||||
|
|
||||||
# null or None means that leave this option out (keep default)
|
|
||||||
if key == "gifski_path" or value is None or value is False:
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
if len(key) == 1:
|
|
||||||
configuration.append(f"-{key}")
|
|
||||||
else:
|
|
||||||
configuration.append(f"--{key}")
|
|
||||||
|
|
||||||
# true means key is an option
|
|
||||||
if value is not True:
|
|
||||||
configuration.append(str(value))
|
|
||||||
return configuration
|
|
||||||
|
|
||||||
def _execute(self, execute: list) -> subprocess.Popen:
|
|
||||||
# turn all list elements into string to avoid errors
|
|
||||||
execute = [str(e) for e in execute]
|
|
||||||
|
|
||||||
Avalon.debug_info(f"Executing: {execute}")
|
|
||||||
|
|
||||||
return subprocess.Popen(execute, 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)
|
|
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()
|
137
video2x/decoder.py
Executable file
137
video2x/decoder.py
Executable file
@ -0,0 +1,137 @@
|
|||||||
|
#!/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
|
||||||
|
)
|
||||||
|
|
||||||
|
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
|
105
video2x/interpolator.py
Executable file
105
video2x/interpolator.py
Executable file
@ -0,0 +1,105 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Name: Interpolator
|
||||||
|
Author: K4YT3X
|
||||||
|
Date Created: May 27, 2021
|
||||||
|
Last Modified: February 2, 2022
|
||||||
|
"""
|
||||||
|
|
||||||
|
# local imports
|
||||||
|
from 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
|
||||||
|
|
||||||
|
# if image0 is None, image1 is the first frame
|
||||||
|
# skip this round
|
||||||
|
if image0 is None:
|
||||||
|
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
|
13
video2x/requirements.txt
Normal file
13
video2x/requirements.txt
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# *-ncnn-vulkan driver backends
|
||||||
|
realsr-ncnn-vulkan-python
|
||||||
|
rife-ncnn-vulkan-python
|
||||||
|
srmd-ncnn-vulkan-python
|
||||||
|
waifu2x-ncnn-vulkan-python
|
||||||
|
|
||||||
|
# regular Python packages from PyPI
|
||||||
|
ffmpeg-python
|
||||||
|
loguru
|
||||||
|
opencv-python
|
||||||
|
pillow
|
||||||
|
rich
|
||||||
|
tqdm
|
178
video2x/upscaler.py
Executable file
178
video2x/upscaler.py
Executable file
@ -0,0 +1,178 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Name: Upscaler
|
||||||
|
Author: K4YT3X
|
||||||
|
Date Created: May 27, 2021
|
||||||
|
Last Modified: August 17, 2021
|
||||||
|
"""
|
||||||
|
|
||||||
|
# local imports
|
||||||
|
from realsr_ncnn_vulkan_python.realsr_ncnn_vulkan import Realsr
|
||||||
|
from srmd_ncnn_vulkan_python.srmd_ncnn_vulkan import Srmd
|
||||||
|
from waifu2x_ncnn_vulkan_python.waifu2x_ncnn_vulkan import Waifu2x
|
||||||
|
|
||||||
|
# built-in imports
|
||||||
|
import math
|
||||||
|
import multiprocessing
|
||||||
|
import multiprocessing.managers
|
||||||
|
import multiprocessing.sharedctypes
|
||||||
|
import queue
|
||||||
|
import signal
|
||||||
|
import time
|
||||||
|
|
||||||
|
# third-party imports
|
||||||
|
from PIL import Image, ImageChops, ImageStat
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
|
# 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],
|
||||||
|
}
|
||||||
|
|
||||||
|
DRIVER_CLASSES = {"waifu2x": Waifu2x, "srmd": Srmd, "realsr": Realsr}
|
||||||
|
|
||||||
|
|
||||||
|
class Upscaler(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"Upscaler process {self.name} initiating")
|
||||||
|
driver_objects = {}
|
||||||
|
while self.running:
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
# get new job from queue
|
||||||
|
(
|
||||||
|
frame_index,
|
||||||
|
(image0, image1),
|
||||||
|
(
|
||||||
|
output_width,
|
||||||
|
output_height,
|
||||||
|
noise,
|
||||||
|
difference_threshold,
|
||||||
|
driver,
|
||||||
|
),
|
||||||
|
) = self.processing_queue.get(False)
|
||||||
|
|
||||||
|
# destructure settings
|
||||||
|
except queue.Empty:
|
||||||
|
time.sleep(0.1)
|
||||||
|
continue
|
||||||
|
|
||||||
|
difference_ratio = 0
|
||||||
|
if image0 is not None:
|
||||||
|
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
|
||||||
|
# skip this frame
|
||||||
|
if difference_ratio < difference_threshold:
|
||||||
|
|
||||||
|
# make sure the previous frame has been processed
|
||||||
|
if frame_index > 0:
|
||||||
|
while self.processed_frames[frame_index - 1] is None:
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
# make the current image the same as the previous result
|
||||||
|
self.processed_frames[frame_index] = self.processed_frames[
|
||||||
|
frame_index - 1
|
||||||
|
]
|
||||||
|
|
||||||
|
# if the difference is greater than threshold
|
||||||
|
# process this frame
|
||||||
|
else:
|
||||||
|
width, height = image1.size
|
||||||
|
|
||||||
|
# calculate required minimum scale ratio
|
||||||
|
output_scale = max(output_width / width, output_height / height)
|
||||||
|
|
||||||
|
# select the optimal driver scaling ratio to use
|
||||||
|
supported_scaling_ratios = sorted(
|
||||||
|
DRIVER_FIXED_SCALING_RATIOS[driver]
|
||||||
|
)
|
||||||
|
|
||||||
|
remaining_scaling_ratio = math.ceil(output_scale)
|
||||||
|
scaling_jobs = []
|
||||||
|
|
||||||
|
# if the scaling ratio is 1.0
|
||||||
|
# apply the smallest scaling ratio available
|
||||||
|
if remaining_scaling_ratio == 1:
|
||||||
|
scaling_jobs.append(supported_scaling_ratios[0])
|
||||||
|
else:
|
||||||
|
while remaining_scaling_ratio > 1:
|
||||||
|
for ratio in supported_scaling_ratios:
|
||||||
|
if ratio >= remaining_scaling_ratio:
|
||||||
|
scaling_jobs.append(ratio)
|
||||||
|
remaining_scaling_ratio /= ratio
|
||||||
|
break
|
||||||
|
|
||||||
|
else:
|
||||||
|
found = False
|
||||||
|
for i in supported_scaling_ratios:
|
||||||
|
for j in supported_scaling_ratios:
|
||||||
|
if i * j >= remaining_scaling_ratio:
|
||||||
|
scaling_jobs.extend([i, j])
|
||||||
|
remaining_scaling_ratio /= i * j
|
||||||
|
found = True
|
||||||
|
break
|
||||||
|
if found is True:
|
||||||
|
break
|
||||||
|
|
||||||
|
if found is False:
|
||||||
|
scaling_jobs.append(supported_scaling_ratios[-1])
|
||||||
|
remaining_scaling_ratio /= supported_scaling_ratios[
|
||||||
|
-1
|
||||||
|
]
|
||||||
|
|
||||||
|
for job in scaling_jobs:
|
||||||
|
|
||||||
|
# select a driver object with the required settings
|
||||||
|
# create a new object if none are available
|
||||||
|
driver_object = driver_objects.get((driver, job))
|
||||||
|
if driver_object is None:
|
||||||
|
driver_object = DRIVER_CLASSES[driver](
|
||||||
|
scale=job, noise=noise
|
||||||
|
)
|
||||||
|
driver_objects[(driver, job)] = driver_object
|
||||||
|
|
||||||
|
# process the image with the selected driver
|
||||||
|
image1 = driver_object.process(image1)
|
||||||
|
|
||||||
|
# downscale the image to the desired output size and save the image to disk
|
||||||
|
image1 = image1.resize((output_width, output_height), Image.LANCZOS)
|
||||||
|
self.processed_frames[frame_index] = image1
|
||||||
|
|
||||||
|
# send exceptions into the client connection pipe
|
||||||
|
except (SystemExit, KeyboardInterrupt):
|
||||||
|
break
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception(e)
|
||||||
|
break
|
||||||
|
|
||||||
|
logger.info(f"Upscaler process {self.name} terminating")
|
||||||
|
self.running = False
|
||||||
|
return super().run()
|
||||||
|
|
||||||
|
def _stop(self, _signal_number, _frame):
|
||||||
|
self.running = False
|
461
video2x/video2x.py
Executable file
461
video2x/video2x.py
Executable file
@ -0,0 +1,461 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
r"""
|
||||||
|
|
||||||
|
__ __ _ _ ___ __ __
|
||||||
|
\ \ / / (_) | | |__ \ \ \ / /
|
||||||
|
\ \ / / _ __| | ___ ___ ) | \ V /
|
||||||
|
\ \/ / | | / _` | / _ \ / _ \ / / > <
|
||||||
|
\ / | | | (_| | | __/ | (_) | / /_ / . \
|
||||||
|
\/ |_| \__,_| \___| \___/ |____| /_/ \_\
|
||||||
|
|
||||||
|
|
||||||
|
Name: Video2X
|
||||||
|
Creator: K4YT3X
|
||||||
|
Date Created: Feb 24, 2018
|
||||||
|
Last Modified: February 2, 2022
|
||||||
|
|
||||||
|
Editor: BrianPetkovsek
|
||||||
|
Last Modified: June 17, 2019
|
||||||
|
|
||||||
|
Editor: SAT3LL
|
||||||
|
Last Modified: June 25, 2019
|
||||||
|
|
||||||
|
Editor: 28598519a
|
||||||
|
Last Modified: March 23, 2020
|
||||||
|
|
||||||
|
Licensed under the GNU General Public License Version 3 (GNU GPL v3),
|
||||||
|
available at: https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
|
||||||
|
(C) 2018-2021 K4YT3X
|
||||||
|
|
||||||
|
Video2X is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Video2X is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Description: Video2X is an automation software based on waifu2x image
|
||||||
|
enlarging engine. It extracts frames from a video, enlarge it by a
|
||||||
|
number of times without losing any details or quality, keeping lines
|
||||||
|
smooth and edges sharp.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# local imports
|
||||||
|
from .decoder import VideoDecoder
|
||||||
|
from .encoder import VideoEncoder
|
||||||
|
from .interpolator import Interpolator
|
||||||
|
from .upscaler import Upscaler
|
||||||
|
|
||||||
|
# built-in imports
|
||||||
|
import argparse
|
||||||
|
import math
|
||||||
|
import multiprocessing
|
||||||
|
import os
|
||||||
|
import pathlib
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
# third-party imports
|
||||||
|
from loguru import logger
|
||||||
|
from rich import print
|
||||||
|
from tqdm import tqdm
|
||||||
|
import cv2
|
||||||
|
import ffmpeg
|
||||||
|
|
||||||
|
VERSION = "5.0.0"
|
||||||
|
|
||||||
|
LEGAL_INFO = """Video2X {}
|
||||||
|
Author: K4YT3X
|
||||||
|
License: GNU GPL v3
|
||||||
|
Github Page: https://github.com/k4yt3x/video2x
|
||||||
|
Contact: k4yt3x@k4yt3x.com""".format(
|
||||||
|
VERSION
|
||||||
|
)
|
||||||
|
|
||||||
|
UPSCALING_DRIVERS = [
|
||||||
|
"waifu2x",
|
||||||
|
"srmd",
|
||||||
|
"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],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Video2X:
|
||||||
|
"""
|
||||||
|
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
|
||||||
|
capture = cv2.VideoCapture(str(path))
|
||||||
|
|
||||||
|
# check if file is opened successfully
|
||||||
|
if not capture.isOpened():
|
||||||
|
raise RuntimeError("OpenCV has failed to open the input file")
|
||||||
|
|
||||||
|
total_frames = int(capture.get(cv2.CAP_PROP_FRAME_COUNT))
|
||||||
|
frame_rate = capture.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(
|
||||||
|
prog="video2x",
|
||||||
|
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-v", "--version", help="show version information and exit", action="store_true"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-i",
|
||||||
|
"--input",
|
||||||
|
type=pathlib.Path,
|
||||||
|
help="input file/directory path",
|
||||||
|
required=True,
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-o",
|
||||||
|
"--output",
|
||||||
|
type=pathlib.Path,
|
||||||
|
help="output file/directory path",
|
||||||
|
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",
|
||||||
|
)
|
||||||
|
|
||||||
|
# upscaler arguments
|
||||||
|
action = parser.add_subparsers(
|
||||||
|
help="action to perform", dest="action", required=True
|
||||||
|
)
|
||||||
|
|
||||||
|
upscale = action.add_parser("upscale", help="upscale a file", add_help=False)
|
||||||
|
upscale.add_argument(
|
||||||
|
"--help", action="help", help="show this help message and exit"
|
||||||
|
)
|
||||||
|
upscale.add_argument("-w", "--width", type=int, help="output width")
|
||||||
|
upscale.add_argument("-h", "--height", type=int, help="output height")
|
||||||
|
upscale.add_argument("-n", "--noise", type=int, help="denoise level", default=3)
|
||||||
|
upscale.add_argument(
|
||||||
|
"-d",
|
||||||
|
"--driver",
|
||||||
|
choices=UPSCALING_DRIVERS,
|
||||||
|
help="driver to use for upscaling",
|
||||||
|
default=UPSCALING_DRIVERS[0],
|
||||||
|
)
|
||||||
|
upscale.add_argument(
|
||||||
|
"-t",
|
||||||
|
"--threshold",
|
||||||
|
type=float,
|
||||||
|
help="skip if the % difference between two adjacent frames is below this value; set to 0 to process all frames",
|
||||||
|
default=0,
|
||||||
|
)
|
||||||
|
|
||||||
|
# interpolator arguments
|
||||||
|
interpolate = action.add_parser(
|
||||||
|
"interpolate", help="interpolate frames for file", add_help=False
|
||||||
|
)
|
||||||
|
interpolate.add_argument(
|
||||||
|
"--help", action="help", help="show this help message and exit"
|
||||||
|
)
|
||||||
|
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="skip if the % difference between two adjacent frames exceeds this value; set to 100 to interpolate all frames",
|
||||||
|
default=10,
|
||||||
|
)
|
||||||
|
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""
|
||||||
|
command line direct invocation
|
||||||
|
program entry point
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
# parse command line arguments
|
||||||
|
args = parse_arguments()
|
||||||
|
|
||||||
|
# set logger level
|
||||||
|
if os.environ.get("LOGURU_LEVEL") is None:
|
||||||
|
os.environ["LOGURU_LEVEL"] = args.loglevel.upper()
|
||||||
|
|
||||||
|
# set logger format
|
||||||
|
if os.environ.get("LOGURU_FORMAT") is None:
|
||||||
|
os.environ[
|
||||||
|
"LOGURU_FORMAT"
|
||||||
|
] = "<fg 240>{time:HH:mm:ss!UTC}</fg 240> | <level>{level: <8}</level> | <level>{message}</level>"
|
||||||
|
|
||||||
|
# display version and lawful informaition
|
||||||
|
if args.version:
|
||||||
|
print(LEGAL_INFO)
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
# initialize upscaler object
|
||||||
|
video2x = Video2X()
|
||||||
|
|
||||||
|
if args.action == "upscale":
|
||||||
|
video2x.upscale(
|
||||||
|
args.input,
|
||||||
|
args.output,
|
||||||
|
args.width,
|
||||||
|
args.height,
|
||||||
|
args.noise,
|
||||||
|
args.processes,
|
||||||
|
args.threshold,
|
||||||
|
args.driver,
|
||||||
|
)
|
||||||
|
|
||||||
|
elif args.action == "interpolate":
|
||||||
|
video2x.interpolate(
|
||||||
|
args.input,
|
||||||
|
args.output,
|
||||||
|
args.processes,
|
||||||
|
args.threshold,
|
||||||
|
args.driver,
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception(e)
|
Loading…
Reference in New Issue
Block a user