35 Commits
4.1.0 ... 4.4.0

Author SHA1 Message Date
k4yt3x
d3db4e8cf1 updated build script requirements file name 2020-05-29 16:24:22 -04:00
k4yt3x
f887dfe3a7 fixed a dash with the wrong encoding 2020-05-29 16:20:11 -04:00
k4yt3x
a41df138bf updated setup script for RealSR NCNN Vulkan and changed requirement files 2020-05-29 16:02:06 -04:00
k4yt3x
41833f4068 fixed Anime4KCPP multi-processing mishandling issue 2020-05-29 15:30:16 -04:00
K4YT3X
c0955ae7e4 updated file modes for Linux 2020-05-28 10:52:38 -04:00
K4YT3X
682aeb82ff updated GitHub Actions config for requirements file changes 2020-05-28 10:24:24 -04:00
K4YT3X
21407c831c separated Linux requirements from Windows requirements 2020-05-28 10:23:54 -04:00
k4yt3x
7e34bf7516 updated Patreon badge 2020-05-27 19:17:05 -04:00
k4yt3x
4c5ca73e38 added RealSR NCNN Vulkan support 2020-05-26 06:35:53 -04:00
k4yt3x
387a233daf added Docker cloud build status badge 2020-05-25 05:29:28 -04:00
k4yt3x
781eb6686f added Docker usage section, added @lhanjian to special thanks for writing the Dockerfile 2020-05-24 23:36:10 -04:00
k4yt3x
c73edd9001 fixed docker submodule issues, formatted Dockerfile 2020-05-24 23:09:22 -04:00
k4yt3x
deb742ee8d added a short description for each of the drivers 2020-05-24 14:26:32 -04:00
k4yt3x
5ef6eb7e8e added Dockerfile written by @lhanjian 2020-05-24 13:24:28 -04:00
k4yt3x
6c5e079a1c added a list of supported drivers into README since it is useful info 2020-05-23 10:19:18 -04:00
k4yt3x
1e384596ee Updated special thanks section 2020-05-23 09:40:17 -04:00
k4yt3x
4680647f1f removed the insignificant master version number badge 2020-05-23 09:05:31 -04:00
k4yt3x
4015db5bcf CLI 4.0.1: require input and output to be specified if help is not specified 2020-05-23 08:59:57 -04:00
k4yt3x
082c6d44fa GUI 2.4.0: added H264/265 tune option 2020-05-23 08:59:39 -04:00
k4yt3x
de841a4636 removed bold exception string to avoid formatting bugs 2020-05-23 07:41:01 -04:00
k4yt3x
40711a2711 updated translations for upscaler 4.1.1 2020-05-22 17:56:31 -04:00
k4yt3x
0c63768165 Upscaler 4.1.1: fixed python-magic detection issues, added more debug output 2020-05-22 17:56:22 -04:00
k4yt3x
ac2d447391 GUI 2.3.1: added shortcut keys 2020-05-22 17:55:55 -04:00
k4yt3x
b03747dbde updated translations after fixing typo 2020-05-22 16:30:02 -04:00
k4yt3x
89740f01dc using mimetypes as a backup mime detection method, fixed typo 2020-05-22 16:29:51 -04:00
k4yt3x
676e70f088 updated drivers tooltips 2020-05-17 16:15:38 -04:00
k4yt3x
f57b5e9d04 bumped GUI version number 2020-05-17 16:15:26 -04:00
k4yt3x
f48e23a890 ignore FileNotFoundError while clearing cache 2020-05-17 15:50:05 -04:00
k4yt3x
826b4e9829 renamed stream copy checkbox 2020-05-17 15:48:21 -04:00
k4yt3x
c56be51e21 updated output path generation logic, organized lines 2020-05-17 15:48:06 -04:00
k4yt3x
d2b3175ccd changed default output codec to yuv420p for wider compatibility, added frame interpolation comment 2020-05-17 15:47:33 -04:00
k4yt3x
a98d1c7277 added stopping confirmation 2020-05-17 10:51:17 -04:00
k4yt3x
e107ddc96e updated translations 2020-05-17 10:13:43 -04:00
k4yt3x
289f5441eb added FFmpeg frame interpolation option 2020-05-17 09:57:07 -04:00
k4yt3x
179bd6afc8 updated GUI 2.1.0 screenshot 2020-05-16 08:01:11 -04:00
26 changed files with 1152 additions and 318 deletions

View File

@@ -1,7 +1,7 @@
# Name: Video2X Nightly Build # Name: Video2X Nightly Build
# Creator: K4YT3X # Creator: K4YT3X
# Date Created: May 12, 2020 # Date Created: May 12, 2020
# Last Modified: May 13, 2020 # Last Modified: May 28, 2020
name: Video2X Nightly Build name: Video2X Nightly Build
@@ -27,7 +27,7 @@ jobs:
run: | run: |
python -m pip install -U pip python -m pip install -U pip
pip install -U pyinstaller pywin32 pip install -U pyinstaller pywin32
pip install -U -r requirements.txt pip install -U -r requirements-windows.txt
- name: Build Video2X CLI - name: Build Video2X CLI
run: | run: |
pyinstaller --noconfirm --log-level=WARN ` pyinstaller --noconfirm --log-level=WARN `

186
Dockerfile Normal file
View File

@@ -0,0 +1,186 @@
FROM ubuntu:19.10
#FROM nvidia/cuda:10.1-cudnn7-devel-ubuntu18.04
MAINTAINER Danielle Douglas <ddouglas87@gmail.com>
MAINTAINER Lhanjian <lhjay1@foxmail.com>
MAINTAINER K4YT3X <k4yt3x@k4yt3x.com>
# Don't ask questions during image setup.
ENV DEBIAN_FRONTEND noninteractive
ENV NASM_VERSION 2.14
ENV NVCODEC_VERSION 8.2.15.6
ENV PKG_CONFIG_PATH /usr/local/lib/pkgconfig
ENV FFMPEG_VERSION 4.1.2
# Install apt-fast, because we got gigs to download.
RUN apt-get update && apt-get install -y apt-utils &&\
apt-get install -y --no-install-recommends software-properties-common &&\
add-apt-repository ppa:apt-fast/stable &&\
add-apt-repository -y ppa:graphics-drivers/ppa &&\
apt-get install -y --no-install-recommends apt-fast && apt-fast update
## Install Video2X ##
# Dependencies
RUN apt-fast install -y --no-install-recommends git-core python3-pip python3-setuptools python3-wheel python3-psutil ffmpeg gcc g++ \
libc6-dev python3-dev libmagic-dev libmagic1 python3.8 nvidia-driver-440 nvidia-cuda-toolkit gnupg2 curl ca-certificates pkg-config \
autoconf libx264-dev libx265-dev libnuma-dev libvpx-dev libfdk-aac-dev libmp3lame-dev libopus-dev libass-dev libfreetype6-dev libgnutls28-dev \
libsdl2-dev libtool libva-dev libvdpau-dev libvorbis-dev libxcb1-dev libxcb-shm0-dev libxcb-xfixes0-dev texinfo wget yasm zlib1g-dev \
libass-dev libfreetype6-dev libsdl2-dev p11-kit libva-dev libvdpau-dev libvorbis-dev libxcb1-dev libxcb-shm0-dev libxcb-xfixes0-dev \
pkg-config texinfo wget zlib1g-dev libchromaprint-dev frei0r-plugins-dev gnutls-dev ladspa-sdk libcaca-dev libcdio-paranoia-dev libcodec2-dev \
libfontconfig1-dev libfreetype6-dev libfribidi-dev libgme-dev libgsm1-dev libjack-dev libmodplug-dev libmp3lame-dev libopencore-amrnb-dev \
libopencore-amrwb-dev libopenjp2-7-dev libopenmpt-dev libopus-dev libpulse-dev librsvg2-dev librubberband-dev librtmp-dev libshine-dev \
libsmbclient-dev libsnappy-dev libsoxr-dev libspeex-dev libssh-dev libtesseract-dev libtheora-dev libtwolame-dev libv4l-dev libvo-amrwbenc-dev \
libvorbis-dev libvpx-dev libwavpack-dev libwebp-dev libx264-dev libx265-dev libxvidcore-dev libxml2-dev libzmq3-dev libzvbi-dev liblilv-dev \
libopenal-dev opencl-dev libjack-dev libbluray-dev libfdk-aac-dev libmysofa-dev
RUN curl -vfsSLO https://www.nasm.us/pub/nasm/releasebuilds/$NASM_VERSION/nasm-$NASM_VERSION.tar.bz2 \
&& tar -xjf nasm-$NASM_VERSION.tar.bz2 \
&& cd nasm-$NASM_VERSION \
&& ./autogen.sh \
&& ./configure \
&& make -j$(nproc) \
&& make install
RUN git clone --recurse-submodules -b n$NVCODEC_VERSION --depth 1 https://git.videolan.org/git/ffmpeg/nv-codec-headers \
&& cd nv-codec-headers \
&& make install
RUN curl -vfsSLO https://ffmpeg.org/releases/ffmpeg-$FFMPEG_VERSION.tar.bz2 \
&& tar -xjf ffmpeg-$FFMPEG_VERSION.tar.bz2 \
&& cd ffmpeg-$FFMPEG_VERSION \
&& ./configure --enable-cuda-sdk --enable-cuvid --enable-nonfree --enable-libnpp --enable-nvenc \
--enable-gpl --enable-version3 \
--enable-small --enable-avisynth --enable-chromaprint \
--enable-frei0r --enable-gmp --enable-gnutls --enable-ladspa \
--enable-libass --enable-libcaca --enable-libcdio \
--enable-libcodec2 --enable-libfontconfig --enable-libfreetype \
--enable-libfribidi --enable-libgme --enable-libgsm --enable-libjack \
--enable-libmodplug --enable-libmp3lame --enable-libopencore-amrnb \
--enable-libopencore-amrwb --enable-libopencore-amrwb \
--enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse \
--enable-librsvg --enable-librubberband --enable-librtmp --enable-libshine \
--enable-libsnappy --enable-libsoxr --enable-libspeex \
--enable-libssh --enable-libtesseract --enable-libtheora \
--enable-libtwolame --enable-libv4l2 --enable-libvo-amrwbenc \
--enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp \
--enable-libx264 --enable-libx265 --enable-libxvid --enable-libxml2 \
--enable-libzmq --enable-libzvbi --enable-lv2 \
--enable-libmysofa \
--enable-openal --enable-opencl --enable-opengl --enable-libdrm \
--enable-libfdk-aac --enable-libbluray \
&& make -j$(nproc) \
&& make install
# Install Nvidia Driver
RUN curl -fsSL https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/7fa2af80.pub | apt-key add -
RUN echo "deb https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64 /" > /etc/apt/sources.list.d/nvidia-ml.list
# Install Video2X
RUN update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.7 1 && update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.8 2
RUN cd / && python3.8 -m pip install --upgrade pip &&\
git clone --recurse-submodules --progress https://github.com/k4yt3x/video2x.git --depth=1 &&\
python3.8 -m pip install avalon_framework colorama python-magic patool psutil pyqt5 pyunpack pyyaml requests tqdm
# eg: docker build -t video2x . --build-arg driver=waifu2x_ncnn_vulkan
ARG driver=all
# Check if driver exists.
SHELL ["/bin/bash", "-c"]
RUN drivers=(all waifu2x_caffe waifu2x_converter waifu2x_ncnn_vulkan) &&\
case ${drivers[@]} in (*${driver,,}*) true ;; (*)\
echo "ERROR: Unrecognized driver." >&2 &&\
printf "%s " "Choices are: ${drivers[@]}" >&2 | printf "\n" >&2 &&\
exit 1 ;;\
esac
RUN if [ "$driver" = "all" ] || [ "$driver" = "waifu2x_caffe" ] ; then \
# nagadomi/caffe prerequisites
apt-fast update &&\
apt-fast install -y --no-install-recommends build-essential cmake libboost-system-dev libboost-thread-dev libboost-filesystem-dev libboost-chrono-dev libboost-date-time-dev libboost-atomic-dev libboost-python-dev libprotobuf-dev protobuf-compiler libhdf5-dev liblmdb-dev libleveldb-dev libsnappy-dev libopencv-dev libatlas-base-dev python-numpy libgflags-dev libgoogle-glog-dev &&\
# nagadomi/waifu2x-caffee-ubuntu prerequisites
apt-fast install -y --no-install-recommends libboost-iostreams-dev;\
fi
# build waifu2x-caffe && install caffe
RUN if [ "$driver" = "all" ] || [ "$driver" = "waifu2x_caffe" ] ; then \
git clone --recurse-submodules --depth=1 --progress --recurse-submodules https://github.com/nagadomi/waifu2x-caffe-ubuntu.git &&\
cd waifu2x-caffe-ubuntu &&\
git clone --recurse-submodules --progress --depth=1 https://github.com/nagadomi/caffe.git;\
fi
RUN if [ "$driver" = "all" ] || [ "$driver" = "waifu2x_caffe" ] ; then \
apt-fast install --no-install-recommends -y gcc-8 libcudnn7 libcudnn7-dev &&\
apt-get remove -y gcc g++ &&\
ln -s /usr/bin/gcc-8 /usr/bin/gcc && ln -s /usr/bin/g++-8 /usr/bin/g++ &&\
cd /waifu2x-caffe-ubuntu &&\
mkdir build &&\
cd build &&\
cmake .. -DCMAKE_INSTALL_PREFIX=/usr &&\
make -j$(nproc) install;\
fi
RUN if [ "$driver" = "all" ] || [ "$driver" = "waifu2x_caffe" ] ; then \
# install waifu2x-caffe
cd /waifu2x-caffe-ubuntu/build &&\
cp waifu2x-caffe ../bin/ &&\
mv ../bin tempname &&\
mv tempname /video2x/ &&\
mv /video2x/tempname /video2x/waifu2x-caffe &&\
rm -rf ../waifu2x-caffe-ubuntu ;\
fi
RUN if [ "$driver" = "all" ] || [ "$driver" = "waifu2x_ncnn_vulkan" ] ; then \
apt-fast install -y --no-install-recommends software-properties-common build-essential cmake libvulkan-dev glslang-tools libprotobuf-dev protobuf-compiler &&\
git clone --recurse-submodules --depth=1 --progress https://github.com/Tencent/ncnn.git &&\
cd ncnn &&\
mkdir -p build &&\
cd build &&\
cmake -DCMAKE_INSTALL_PREFIX=/usr -DNCNN_VULKAN=ON .. &&\
make -j$(nproc) install &&\
rm -rf ../../ncnn &&\
cd / &&\
# Compile waifu2x-ncnn-vulkan
git clone --recurse-submodules --depth=1 --progress https://github.com/nihui/waifu2x-ncnn-vulkan.git &&\
cd waifu2x-ncnn-vulkan &&\
mkdir -p build &&\
cd build &&\
cmake ../src &&\
make -j$(nproc) &&\
# Incall waifu2x-ncnn-vulkan
cd /waifu2x-ncnn-vulkan &&\
mkdir waifu2x-ncnn-vulkan &&\
mv models/models-cunet waifu2x-ncnn-vulkan/ &&\
mv build/waifu2x-ncnn-vulkan waifu2x-ncnn-vulkan/ &&\
mv waifu2x-ncnn-vulkan /video2x/ &&\
rm -rf ../waifu2x-ncnn-vulkan ;\
fi
RUN if [ "$driver" = "all" ] || [ "$driver" = "waifu2x_converter" ] ;\
then \
# Prerequisits for waifu2x-converter-cpp
apt-fast install -y --no-install-recommends build-essential cmake libopencv-dev ocl-icd-opencl-dev &&\
# Compile & Install
git clone --recurse-submodules --depth=1 --progress https://github.com/DeadSix27/waifu2x-converter-cpp &&\
cd waifu2x-converter-cpp &&\
mkdir build &&\
cd build &&\
cmake .. &&\
make -j$(nproc) &&\
#ldconfig &&\
cp -r ../models_rgb ./&&\
cd / ;\
fi
# Go!
#COPY entrypoint.sh /
#ENTRYPOINT ["/entrypoint.sh"]
WORKDIR /host
ENTRYPOINT ["/bin/bash"]
ENV NVIDIA_DRIVER_CAPABILITIES all
# Docker image can ask questions now, if needed.
ENV DEBIAN_FRONTEND teletype

View File

@@ -2,13 +2,13 @@
<img src="https://user-images.githubusercontent.com/21986859/81626588-ae5ab800-93eb-11ea-918f-ebe98c2de40a.png"/> <img src="https://user-images.githubusercontent.com/21986859/81626588-ae5ab800-93eb-11ea-918f-ebe98c2de40a.png"/>
</p> </p>
![Master Branch Version](https://img.shields.io/badge/master-v4.0.0-9cf?style=flat-square)
![GitHub release (latest by date)](https://img.shields.io/github/v/release/k4yt3x/video2x?style=flat-square) ![GitHub release (latest by date)](https://img.shields.io/github/v/release/k4yt3x/video2x?style=flat-square)
![GitHub Workflow Status](https://img.shields.io/github/workflow/status/k4yt3x/video2x/Video2X%20Nightly%20Build?label=Nightly&style=flat-square) ![GitHub Workflow Status](https://img.shields.io/github/workflow/status/k4yt3x/video2x/Video2X%20Nightly%20Build?label=Nightly&style=flat-square)
![Docker Cloud Build Status](https://img.shields.io/docker/cloud/build/k4yt3x/video2x?style=flat-square)
![GitHub All Releases](https://img.shields.io/github/downloads/k4yt3x/video2x/total?style=flat-square) ![GitHub All Releases](https://img.shields.io/github/downloads/k4yt3x/video2x/total?style=flat-square)
![GitHub](https://img.shields.io/github/license/k4yt3x/video2x?style=flat-square) ![GitHub](https://img.shields.io/github/license/k4yt3x/video2x?style=flat-square)
![Platforms](https://img.shields.io/badge/Platforms-Windows%20%7C%20Linux%20%7C%20macOS-blue?style=flat-square) ![Platforms](https://img.shields.io/badge/Platforms-Windows%20%7C%20Linux%20%7C%20macOS-blue?style=flat-square)
<img alt="Become a Patron!" src="https://c5.patreon.com/external/logo/become_a_patron_button@2x.png" href="https://www.patreon.com/bePatron?u=34970782" height=20> ![Become A Patron!](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fshieldsio-patreon.herokuapp.com%2Fk4yt3x&style=flat-square)
<!--# Video2X Lossless Video Enlarger--> <!--# Video2X Lossless Video Enlarger-->
@@ -35,6 +35,14 @@ To download the latest nightly build, go to the [GitHub Actions](https://github.
Video2X is a video/GIF/image upscaling software based on Waifu2X, Anime4K and SRMD written in Python 3. It upscales videos, GIFs and images, restoring details from low-resolution inputs. Video2X also accepts GIF input to video output and video input to GIF output. Video2X is a video/GIF/image upscaling software based on Waifu2X, Anime4K and SRMD written in Python 3. It upscales videos, GIFs and images, restoring details from low-resolution inputs. Video2X also accepts GIF input to video output and video input to GIF output.
Currently, Video2X supports the following drivers (implementations of algorithms).
- **Waifu2X Caffe**: Caffe implementation of waifu2x
- **Waifu2X Converter CPP**: CPP implementation of waifu2x based on OpenCL and OpenCV
- **Waifu2X NCNN Vulkan**: NCNN implementation of waifu2x based on Vulkan API
- **SRMD NCNN Vulkan**: NCNN implementation of SRMD based on Vulkan API
- **Anime4KCPP**: CPP implementation of Anime4K
### Video Upscaling ### Video Upscaling
![Spirited Away Demo](https://user-images.githubusercontent.com/21986859/49412428-65083280-f73a-11e8-8237-bb34158a545e.png)\ ![Spirited Away Demo](https://user-images.githubusercontent.com/21986859/49412428-65083280-f73a-11e8-8237-bb34158a545e.png)\
@@ -86,7 +94,7 @@ The list is sorted from new to old.
### Video2X GUI ### Video2X GUI
![GUI Preview](https://user-images.githubusercontent.com/21986859/81662226-cacb1480-942c-11ea-831f-2f0827f9cd11.png)\ ![GUI Preview](https://user-images.githubusercontent.com/21986859/82119295-bc526500-976c-11ea-9ea8-53264689023e.png)\
*Video2X GUI Screenshot* *Video2X GUI Screenshot*
### Video2X CLI ### Video2X CLI
@@ -171,6 +179,14 @@ To see a help page for driver-specific settings, use `-d` to select the driver a
python video2x.py -d waifu2x_caffe -- --help python video2x.py -d waifu2x_caffe -- --help
``` ```
### Running Video2X (Docker)
Video2X can be deployed via Docker.
```shell
docker pull k4yt3x/video2x
```
--- ---
## Documentations ## Documentations
@@ -268,10 +284,12 @@ This project relies on the following software and projects.
## Special Thanks ## Special Thanks
Appreciations given to the following code contributors: Appreciations given to the following personnel who have contributed significantly to the project (specifically the technical perspective).
- @BrianPetkovsek - @BrianPetkovsek
- @SAT3LL - @SAT3LL
- @ddouglas87
- @lhanjian
## Related Projects ## Related Projects

View File

@@ -9,7 +9,7 @@ executable (PE) releases automatically using PyInstaller.
This script is currently only tuned for K4YT3X's environment. This script is currently only tuned for K4YT3X's environment.
To start a PowerShell session with execution policy bypass To start a PowerShell session with execution policy bypass
powershell ExecutionPolicy Bypass powershell -ExecutionPolicy Bypass
#> #>
if ($args.count -ne 1){ if ($args.count -ne 1){
@@ -82,7 +82,7 @@ Copy-Item "dist\video2x.exe" -Destination "$($VIDEO2X_VERSION)\video2x-$($VIDEO2
Copy-Item "dist\video2x_gui.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 "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 "video2x.yaml" -Destination "$($VIDEO2X_VERSION)\video2x-$($VIDEO2X_VERSION)-win32-light\"
Copy-Item "requirements.txt" -Destination "$($VIDEO2X_VERSION)\video2x-$($VIDEO2X_VERSION)-win32-light\" Copy-Item "requirements-windows.txt" -Destination "$($VIDEO2X_VERSION)\video2x-$($VIDEO2X_VERSION)-win32-light\"
# clean up temporary files # clean up temporary files
Write-Host -ForegroundColor White "`nDeleting temporary files" Write-Host -ForegroundColor White "`nDeleting temporary files"

View File

@@ -5,8 +5,8 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: \n"
"POT-Creation-Date: 2020-05-12 04:27-0400\n" "POT-Creation-Date: 2020-05-22 17:51-0400\n"
"PO-Revision-Date: 2020-05-12 04:29-0400\n" "PO-Revision-Date: 2020-05-22 17:54-0400\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: \n" "Language-Team: \n"
"Language: zh_CN\n" "Language: zh_CN\n"
@@ -21,276 +21,304 @@ msgstr ""
msgid "Upscaling Progress" msgid "Upscaling Progress"
msgstr "放大进度" msgstr "放大进度"
#: upscaler.py:106 #: upscaler.py:110
msgid "Specified or default cache directory is a file/link" msgid "Specified or default cache directory is a file/link"
msgstr "指定或默认的缓存目录是文件/链接" msgstr "指定或默认的缓存目录是文件/链接"
#: upscaler.py:112 #: upscaler.py:116
msgid "Creating cache directory {}" msgid "Creating cache directory {}"
msgstr "创建缓存目录 {}" msgstr "创建缓存目录 {}"
#: upscaler.py:115 #: upscaler.py:119
msgid "Unable to create {}" msgid "Unable to create {}"
msgstr "无法创建 {}" msgstr "无法创建 {}"
#: upscaler.py:120 #: upscaler.py:124
msgid "Extracted frames are being saved to: {}" msgid "Extracted frames are being saved to: {}"
msgstr "提取的帧将被保存到:{}" msgstr "提取的帧将被保存到:{}"
#: upscaler.py:122 #: upscaler.py:126
msgid "Upscaled frames are being saved to: {}" msgid "Upscaled frames are being saved to: {}"
msgstr "已放大的帧将被保存到:{}" msgstr "已放大的帧将被保存到:{}"
#: upscaler.py:132 #: upscaler.py:136
msgid "Cleaning up cache directory: {}" msgid "Cleaning up cache directory: {}"
msgstr "清理缓存目录:{}" msgstr "清理缓存目录:{}"
#: upscaler.py:135 #: upscaler.py:141
msgid "Unable to delete: {}" msgid "Unable to delete: {}"
msgstr "无法删除:{}" msgstr "无法删除:{}"
#: upscaler.py:141 upscaler.py:156 upscaler.py:167 #: upscaler.py:147 upscaler.py:162 upscaler.py:173
msgid "Input and output path type mismatch" msgid "Input and output path type mismatch"
msgstr "输入和输出路径类型不匹配" msgstr "输入和输出路径类型不匹配"
#: upscaler.py:142 #: upscaler.py:148
msgid "Input is multiple files but output is not directory" msgid "Input is multiple files but output is not directory"
msgstr "输入是多个文件,但输出不是目录" msgstr "输入是多个文件,但输出不是目录"
#: upscaler.py:146 #: upscaler.py:152
msgid "Input path {} is neither a file nor a directory" msgid "Input path {} is neither a file nor a directory"
msgstr "输入路径 {} 既不是文件也不是目录" msgstr "输入路径 {} 既不是文件也不是目录"
#: upscaler.py:150 upscaler.py:172 #: upscaler.py:156 upscaler.py:178
msgid "Input directory and output directory cannot be the same" msgid "Input directory and output directory cannot be the same"
msgstr "输入目录和输出目录不能相同" msgstr "输入目录和输出目录不能相同"
#: upscaler.py:157 #: upscaler.py:163
msgid "Input is single file but output is directory" msgid "Input is single file but output is directory"
msgstr "所选的输入路径是单个文件,但输出路径是目录" msgstr "所选的输入路径是单个文件,但输出路径是目录"
#: upscaler.py:160 #: upscaler.py:166
msgid "No suffix found in output file path" msgid "No suffix found in output file path"
msgstr "在输出文件路径中未找到后缀" msgstr "在输出文件路径中未找到后缀"
#: upscaler.py:161 #: upscaler.py:167
msgid "Suffix must be specified" msgid "Suffix must be specified"
msgstr "必须指定文件后缀" msgstr "必须指定文件后缀"
#: upscaler.py:168 #: upscaler.py:174
msgid "Input is directory but output is existing single file" msgid "Input is directory but output is existing single file"
msgstr "输入是目录,但输出是现有的单个文件" msgstr "输入是目录,但输出是现有的单个文件"
#: upscaler.py:177 #: upscaler.py:183
msgid "Input path is neither a file nor a directory" msgid "Input path is neither a file nor a directory"
msgstr "输入路径既不是文件也不是目录" msgstr "输入路径既不是文件也不是目录"
#: upscaler.py:186 #: upscaler.py:192
msgid "FFmpeg or FFprobe cannot be found under the specified path" msgid "FFmpeg or FFprobe cannot be found under the specified path"
msgstr "在指定的路径下找不到 FFmpeg 或 FFprobe" msgstr "在指定的路径下找不到 FFmpeg 或 FFprobe"
#: upscaler.py:187 upscaler.py:197 #: upscaler.py:193 upscaler.py:203
msgid "Please check the configuration file settings" msgid "Please check the configuration file settings"
msgstr "请检查配置文件设置" msgstr "请检查配置文件设置"
#: upscaler.py:196 #: upscaler.py:202
msgid "Specified driver executable directory doesn't exist" msgid "Specified driver executable directory doesn't exist"
msgstr "指定驱动的可执行文件不存在" msgstr "指定驱动的可执行文件不存在"
#: upscaler.py:223 #: upscaler.py:229
msgid "Failed to parse driver argument: {}" msgid "Failed to parse driver argument: {}"
msgstr "解析驱动程序参数失败:{}" msgstr "解析驱动程序参数失败:{}"
#: upscaler.py:248 #: upscaler.py:261
msgid "Anime4KCPP doesn't yet support GIF processing"
msgstr "Anime4KCPP 尚不支持GIF处理"
#: upscaler.py:263
msgid "Unrecognized driver: {}" msgid "Unrecognized driver: {}"
msgstr "无法识别的驱动名称:{}" msgstr "无法识别的驱动名称:{}"
#: upscaler.py:303 #: upscaler.py:301
msgid "Starting progress monitor" msgid "Starting progress monitor"
msgstr "启动进度监视器" msgstr "启动进度监视器"
#: upscaler.py:308 #: upscaler.py:306
msgid "Starting upscaled image cleaner" msgid "Starting upscaled image cleaner"
msgstr "启动已放大图像清理程序" msgstr "启动已放大图像清理程序"
#: upscaler.py:317 upscaler.py:334 #: upscaler.py:315 upscaler.py:332
msgid "Killing progress monitor" msgid "Killing progress monitor"
msgstr "终结进度监视器" msgstr "终结进度监视器"
#: upscaler.py:320 upscaler.py:337 #: upscaler.py:318 upscaler.py:335
msgid "Killing upscaled image cleaner" msgid "Killing upscaled image cleaner"
msgstr "终结已放大图像清理程序" msgstr "终结已放大图像清理程序"
#: upscaler.py:341 #: upscaler.py:339
msgid "Terminating all processes" msgid "Terminating all processes"
msgstr "正在终止所有进程" msgstr "正在终止所有进程"
#: upscaler.py:348 #: upscaler.py:346
msgid "Main process waiting for subprocesses to exit" msgid "Main process waiting for subprocesses to exit"
msgstr "主进程开始等待子进程结束" msgstr "主进程开始等待子进程结束"
#: upscaler.py:367 upscaler.py:371 #: upscaler.py:365 upscaler.py:369
msgid "Subprocess {} exited with code {}" msgid "Subprocess {} exited with code {}"
msgstr "子进程 {} 结束,返回码 {}" msgstr "子进程 {} 结束,返回码 {}"
#: upscaler.py:377 #: upscaler.py:375
msgid "Stop signal received" msgid "Stop signal received"
msgstr "收到停止信号" msgstr "收到停止信号"
#: upscaler.py:382 #: upscaler.py:380
msgid "Subprocess execution ran into an error" msgid "Subprocess execution ran into an error"
msgstr "子进程执行遇到错误" msgstr "子进程执行遇到错误"
#: upscaler.py:430 #: upscaler.py:410
msgid "Upscaling single file: {}" msgid "Loading files into processing queue"
msgstr "放大单个文件:{}" msgstr "正在将文件添加到处理队列中"
#: upscaler.py:466 #: upscaler.py:415
msgid "Loading files from multiple paths"
msgstr "正在从多个路径中导入文件"
#: upscaler.py:416 upscaler.py:435 upscaler.py:442
msgid "Input path(s): {}"
msgstr "输入路径:{}"
#: upscaler.py:434
msgid "Loading single file"
msgstr "正在导入单个文件"
#: upscaler.py:441
msgid "Loading files from directory"
msgstr "正在从文件夹中导入文件"
#: upscaler.py:455
msgid "Loaded files into processing queue"
msgstr "文件已添加到处理队列"
#: upscaler.py:458
msgid "Input file: {}"
msgstr "输入文件:{}"
#: upscaler.py:485
msgid "Starting to upscale image" msgid "Starting to upscale image"
msgstr "开始放大图像" msgstr "开始放大图像"
#: upscaler.py:469 upscaler.py:487 upscaler.py:545 #: upscaler.py:488 upscaler.py:550
msgid "Upscaling completed" msgid "Upscaling completed"
msgstr "放大完成" msgstr "放大完成"
#: upscaler.py:482 #: upscaler.py:502
msgid "Starting to upscale video with Anime4KCPP"
msgstr "开始用 Anime4KCPP 放大视频"
#: upscaler.py:496
msgid "Reading video information" msgid "Reading video information"
msgstr "读取视频信息" msgstr "读取视频信息"
#: upscaler.py:510 #: upscaler.py:516
msgid "Aborting: No video stream found" msgid "Aborting: No video stream found"
msgstr "程序中止:文件中未找到视频流" msgstr "程序中止:文件中未找到视频流"
#: upscaler.py:531 #: upscaler.py:521
msgid "Unsupported pixel format: {}"
msgstr "不支持的像素格式:{}"
#: upscaler.py:534
msgid "Framerate: {}" msgid "Framerate: {}"
msgstr "帧率:{}" msgstr "帧率:{}"
#: upscaler.py:543 #: upscaler.py:538
msgid "Unsupported pixel format: {}"
msgstr "不支持的像素格式:{}"
#: upscaler.py:548
msgid "Starting to upscale extracted frames" msgid "Starting to upscale extracted frames"
msgstr "开始对提取的帧进行放大" msgstr "开始对提取的帧进行放大"
#: upscaler.py:550 #: upscaler.py:555
msgid "File {} ({}) neither an image of a video" msgid "File {} ({}) neither an image nor a video"
msgstr "文件 {} {} 既不是图片也不是视频" msgstr "文件 {} {} 既不是图片也不是视频"
#: upscaler.py:551 #: upscaler.py:556
msgid "Skipping this file" msgid "Skipping this file"
msgstr "将跳过此文件" msgstr "将跳过此文件"
#: upscaler.py:561 #: upscaler.py:566
msgid "Converting extracted frames into GIF image" msgid "Converting extracted frames into GIF image"
msgstr "正在将提取的帧转换为 GIF" msgstr "正在将提取的帧转换为 GIF"
#: upscaler.py:565 upscaler.py:574 #: upscaler.py:570 upscaler.py:579
msgid "Conversion completed" msgid "Conversion completed"
msgstr "转换已完成" msgstr "转换已完成"
#: upscaler.py:570 #: upscaler.py:575
msgid "Converting extracted frames into video" msgid "Converting extracted frames into video"
msgstr "正在将提取的帧转换为视频" msgstr "正在将提取的帧转换为视频"
#: upscaler.py:578 #: upscaler.py:583
msgid "Migrating audio, subtitles and other streams to upscaled video" msgid "Migrating audio, subtitles and other streams to upscaled video"
msgstr "正在将音频、字幕和其他流迁移到放大后的视频" msgstr "正在将音频、字幕和其他流迁移到放大后的视频"
#: upscaler.py:587 #: upscaler.py:593
msgid "Failed to migrate streams" msgid "Failed to migrate streams"
msgstr "迁移流失败" msgstr "迁移流失败"
#: upscaler.py:588 #: upscaler.py:594
msgid "Trying to output video without additional streams" msgid "Trying to output video without additional streams"
msgstr "正在尝试输出不含其他流的视频" msgstr "正在尝试输出不含其他流的视频"
#: upscaler.py:599 #: upscaler.py:610
msgid "Output video file exists, aborting" msgid "Output video file exists"
msgstr "输出目标文件已存在,取消输出" msgstr "输出目标文件已存在"
#: upscaler.py:603 #: upscaler.py:614
msgid "Created temporary directory to contain file"
msgstr "为文件创建了临时目录"
#: upscaler.py:617
msgid "Writing intermediate file to: {}" msgid "Writing intermediate file to: {}"
msgstr "正在将中间视频文件写入至:{}" msgstr "正在将中间视频文件写入至:{}"
#: video2x.py:84 #: video2x.py:85
msgid "" msgid ""
"Video2X Version: {}\n" "Video2X CLI Version: {}\n"
"Upscaler Version: {}\n"
"Author: K4YT3X\n" "Author: K4YT3X\n"
"License: GNU GPL v3\n" "License: GNU GPL v3\n"
"Github Page: https://github.com/k4yt3x/video2x\n" "Github Page: https://github.com/k4yt3x/video2x\n"
"Contact: k4yt3x@k4yt3x.com" "Contact: k4yt3x@k4yt3x.com"
msgstr "" msgstr ""
"Video2X 版本: {}\n" "Video2X 版本: {}\n"
"放大组件版本:{}\n"
"作者: K4YT3X\n" "作者: K4YT3X\n"
"开源许可: GNU GPL v3\n" "开源许可: GNU GPL v3\n"
"GitHub 主页https://github.com/k4yt3x/video2x\n" "GitHub 主页https://github.com/k4yt3x/video2x\n"
"联系方式k4yt3x@k4yt3x.com" "联系方式k4yt3x@k4yt3x.com"
#: video2x.py:106 #: video2x.py:108
msgid "Video2X Options" msgid "Video2X Options"
msgstr "Video2X 选项" msgstr "Video2X 选项"
#: video2x.py:107 #: video2x.py:109
msgid "show this help message and exit" msgid "show this help message and exit"
msgstr "显示此帮助消息并退出" msgstr "显示此帮助消息并退出"
#: video2x.py:108 #: video2x.py:110
msgid "source video file/directory" msgid "source video file/directory"
msgstr "源视频文件/目录" msgstr "源视频文件/目录"
#: video2x.py:109 #: video2x.py:111
msgid "output video file/directory" msgid "output video file/directory"
msgstr "输出视频文件/目录" msgstr "输出视频文件/目录"
#: video2x.py:110 #: video2x.py:112
msgid "video2x config file path" msgid "video2x config file path"
msgstr "video2x 配置文件路径" msgstr "video2x 配置文件路径"
#: video2x.py:112 #: video2x.py:114
msgid "display version, lawful information and exit" msgid "display version, lawful information and exit"
msgstr "显示版本和法律信息并退出" msgstr "显示版本和法律信息并退出"
#: video2x.py:115 #: video2x.py:117
msgid "Upscaling Options" msgid "Upscaling Options"
msgstr "视频放大选项" msgstr "视频放大选项"
#: video2x.py:116 #: video2x.py:118
msgid "upscaling driver" msgid "upscaling driver"
msgstr "视频放大驱动" msgstr "视频放大驱动"
#: video2x.py:117 #: video2x.py:119
msgid "scaling ratio" msgid "scaling ratio"
msgstr "缩放比" msgstr "缩放比"
#: video2x.py:118 #: video2x.py:120
msgid "number of processes to use for upscaling" msgid "number of processes to use for upscaling"
msgstr "并发进程数" msgstr "并发进程数"
#: video2x.py:119 #: video2x.py:121
msgid "preserve extracted and upscaled frames" msgid "preserve extracted and upscaled frames"
msgstr "保留提取的和放大的帧" msgstr "保留提取的和放大的帧"
#: video2x.py:159 #: video2x.py:161
msgid "This file cannot be imported" msgid "This file cannot be imported"
msgstr "此文件无法被当作模块导入" msgstr "此文件无法被当作模块导入"
#: video2x.py:234 #: video2x.py:236
msgid "Program completed, taking {} seconds" msgid "Program completed, taking {} seconds"
msgstr "程序执行完毕,总计花费 {} 秒" msgstr "程序执行完毕,总计花费 {} 秒"
#: video2x.py:237 #: video2x.py:239
msgid "An exception has occurred" msgid "An exception has occurred"
msgstr "发生了异常" msgstr "发生了异常"
#~ msgid "Anime4KCPP doesn't yet support GIF processing"
#~ msgstr "Anime4KCPP 尚不支持GIF处理"
#~ msgid "Starting to upscale video with Anime4KCPP"
#~ msgstr "开始用 Anime4KCPP 放大视频"
#~ msgid "output video width" #~ msgid "output video width"
#~ msgstr "输出视频宽度" #~ msgstr "输出视频宽度"
@@ -317,6 +345,3 @@ msgstr "发生了异常"
#~ msgid "You must specify both width and height" #~ msgid "You must specify both width and height"
#~ msgstr "您必须同时指定宽度和高度" #~ msgstr "您必须同时指定宽度和高度"
#~ msgid "Upscaling videos in directory: {}"
#~ msgstr "放大该文件夹中的所有视频:{}"

0
src/progress_monitor.py Normal file → Executable file
View File

View File

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

View File

@@ -4,7 +4,7 @@
Name: Video2X Upscaler Name: Video2X Upscaler
Author: K4YT3X Author: K4YT3X
Date Created: December 10, 2018 Date Created: December 10, 2018
Last Modified: May 16, 2020 Last Modified: May 29, 2020
Description: This file contains the Upscaler class. Each Description: This file contains the Upscaler class. Each
instance of the Upscaler class is an upscaler on an image or instance of the Upscaler class is an upscaler on an image or
@@ -25,6 +25,7 @@ import copy
import gettext import gettext
import importlib import importlib
import locale import locale
import mimetypes
import pathlib import pathlib
import queue import queue
import re import re
@@ -49,7 +50,7 @@ language.install()
_ = language.gettext _ = language.gettext
# version information # version information
UPSCALER_VERSION = '4.1.0' UPSCALER_VERSION = '4.2.0'
# these names are consistent for # these names are consistent for
# - driver selection in command line # - driver selection in command line
@@ -59,6 +60,7 @@ AVAILABLE_DRIVERS = ['waifu2x_caffe',
'waifu2x_converter_cpp', 'waifu2x_converter_cpp',
'waifu2x_ncnn_vulkan', 'waifu2x_ncnn_vulkan',
'srmd_ncnn_vulkan', 'srmd_ncnn_vulkan',
'realsr_ncnn_vulkan',
'anime4kcpp'] 'anime4kcpp']
@@ -134,7 +136,9 @@ class Upscaler:
# therefore, plain print is used # therefore, plain print is used
print(_('Cleaning up cache directory: {}').format(directory)) print(_('Cleaning up cache directory: {}').format(directory))
shutil.rmtree(directory) shutil.rmtree(directory)
except (OSError, FileNotFoundError): except FileNotFoundError:
pass
except OSError:
print(_('Unable to delete: {}').format(directory)) print(_('Unable to delete: {}').format(directory))
traceback.print_exc() traceback.print_exc()
@@ -278,7 +282,7 @@ class Upscaler:
process_directory.mkdir(parents=True, exist_ok=True) process_directory.mkdir(parents=True, exist_ok=True)
# waifu2x-converter-cpp will perform multi-threading within its own process # waifu2x-converter-cpp will perform multi-threading within its own process
if self.driver in ['waifu2x_converter_cpp', 'waifu2x_ncnn_vulkan', 'srmd_ncnn_vulkan']: if self.driver in ['waifu2x_converter_cpp', 'waifu2x_ncnn_vulkan', 'srmd_ncnn_vulkan', 'realsr_ncnn_vulkan', 'anime4kcpp']:
process_directories = [self.extracted_frames] process_directories = [self.extracted_frames]
else: else:
@@ -404,8 +408,14 @@ class Upscaler:
# define processing queue # define processing queue
self.processing_queue = queue.Queue() self.processing_queue = queue.Queue()
Avalon.info(_('Loading files into processing queue'))
# if input is a list of files # if input is a list of files
if isinstance(self.input, list): if isinstance(self.input, list):
Avalon.info(_('Loading files from multiple paths'))
Avalon.debug_info(_('Input path(s): {}').format(self.input))
# make output directory if it doesn't exist # make output directory if it doesn't exist
self.output.mkdir(parents=True, exist_ok=True) self.output.mkdir(parents=True, exist_ok=True)
@@ -422,12 +432,15 @@ class Upscaler:
# if input specified is single file # if input specified is single file
elif self.input.is_file(): elif self.input.is_file():
Avalon.info(_('Upscaling single file: {}').format(self.input)) Avalon.info(_('Loading single file'))
Avalon.debug_info(_('Input path(s): {}').format(self.input))
self.processing_queue.put((self.input.absolute(), self.output.absolute())) self.processing_queue.put((self.input.absolute(), self.output.absolute()))
# if input specified is a directory # if input specified is a directory
elif self.input.is_dir(): elif self.input.is_dir():
Avalon.info(_('Loading files from directory'))
Avalon.debug_info(_('Input path(s): {}').format(self.input))
# make output directory if it doesn't exist # make output directory if it doesn't exist
self.output.mkdir(parents=True, exist_ok=True) self.output.mkdir(parents=True, exist_ok=True)
for input_path in [f for f in self.input.iterdir() if f.is_file()]: for input_path in [f for f in self.input.iterdir() if f.is_file()]:
@@ -440,6 +453,11 @@ class Upscaler:
# record file count for external calls # record file count for external calls
self.total_files = self.processing_queue.qsize() self.total_files = self.processing_queue.qsize()
Avalon.info(_('Loaded files into processing queue'))
# print all files in queue for debugging
for job in self.processing_queue.queue:
Avalon.debug_info(_('Input file: {}').format(job[0].absolute()))
try: try:
while not self.processing_queue.empty(): while not self.processing_queue.empty():
@@ -455,6 +473,13 @@ class Upscaler:
input_file_type = input_file_mime_type.split('/')[0] input_file_type = input_file_mime_type.split('/')[0]
input_file_subtype = input_file_mime_type.split('/')[1] input_file_subtype = input_file_mime_type.split('/')[1]
# in case python-magic fails to detect file type
# try guessing file mime type with mimetypes
if input_file_type not in ['image', 'video']:
input_file_mime_type = mimetypes.guess_type(self.current_input_file.name)[0]
input_file_type = input_file_mime_type.split('/')[0]
input_file_subtype = input_file_mime_type.split('/')[1]
# start handling input # start handling input
# if input file is a static image # if input file is a static image
if input_file_type == 'image' and input_file_subtype != 'gif': if input_file_type == 'image' and input_file_subtype != 'gif':
@@ -528,7 +553,7 @@ class Upscaler:
# if file is none of: image, image/gif, video # if file is none of: image, image/gif, video
# skip to the next task # skip to the next task
else: else:
Avalon.error(_('File {} ({}) neither an image of a video').format(self.current_input_file, input_file_mime_type)) Avalon.error(_('File {} ({}) neither an image nor a video').format(self.current_input_file, input_file_mime_type))
Avalon.warning(_('Skipping this file')) Avalon.warning(_('Skipping this file'))
self.processing_queue.task_done() self.processing_queue.task_done()
self.total_processed += 1 self.total_processed += 1

View File

@@ -5,7 +5,7 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2020-05-12 04:27-0400\n" "POT-Creation-Date: 2020-05-22 17:51-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -19,268 +19,289 @@ msgstr ""
msgid "Upscaling Progress" msgid "Upscaling Progress"
msgstr "" msgstr ""
#: upscaler.py:106 #: upscaler.py:110
msgid "Specified or default cache directory is a file/link" msgid "Specified or default cache directory is a file/link"
msgstr "" msgstr ""
#: upscaler.py:112 #: upscaler.py:116
msgid "Creating cache directory {}" msgid "Creating cache directory {}"
msgstr "" msgstr ""
#: upscaler.py:115 #: upscaler.py:119
msgid "Unable to create {}" msgid "Unable to create {}"
msgstr "" msgstr ""
#: upscaler.py:120 #: upscaler.py:124
msgid "Extracted frames are being saved to: {}" msgid "Extracted frames are being saved to: {}"
msgstr "" msgstr ""
#: upscaler.py:122 #: upscaler.py:126
msgid "Upscaled frames are being saved to: {}" msgid "Upscaled frames are being saved to: {}"
msgstr "" msgstr ""
#: upscaler.py:132 #: upscaler.py:136
msgid "Cleaning up cache directory: {}" msgid "Cleaning up cache directory: {}"
msgstr "" msgstr ""
#: upscaler.py:135 #: upscaler.py:141
msgid "Unable to delete: {}" msgid "Unable to delete: {}"
msgstr "" msgstr ""
#: upscaler.py:141 upscaler.py:156 upscaler.py:167 #: upscaler.py:147 upscaler.py:162 upscaler.py:173
msgid "Input and output path type mismatch" msgid "Input and output path type mismatch"
msgstr "" msgstr ""
#: upscaler.py:142 #: upscaler.py:148
msgid "Input is multiple files but output is not directory" msgid "Input is multiple files but output is not directory"
msgstr "" msgstr ""
#: upscaler.py:146 #: upscaler.py:152
msgid "Input path {} is neither a file nor a directory" msgid "Input path {} is neither a file nor a directory"
msgstr "" msgstr ""
#: upscaler.py:150 upscaler.py:172 #: upscaler.py:156 upscaler.py:178
msgid "Input directory and output directory cannot be the same" msgid "Input directory and output directory cannot be the same"
msgstr "" msgstr ""
#: upscaler.py:157 #: upscaler.py:163
msgid "Input is single file but output is directory" msgid "Input is single file but output is directory"
msgstr "" msgstr ""
#: upscaler.py:160 #: upscaler.py:166
msgid "No suffix found in output file path" msgid "No suffix found in output file path"
msgstr "" msgstr ""
#: upscaler.py:161 #: upscaler.py:167
msgid "Suffix must be specified" msgid "Suffix must be specified"
msgstr "" msgstr ""
#: upscaler.py:168 #: upscaler.py:174
msgid "Input is directory but output is existing single file" msgid "Input is directory but output is existing single file"
msgstr "" msgstr ""
#: upscaler.py:177 #: upscaler.py:183
msgid "Input path is neither a file nor a directory" msgid "Input path is neither a file nor a directory"
msgstr "" msgstr ""
#: upscaler.py:186 #: upscaler.py:192
msgid "FFmpeg or FFprobe cannot be found under the specified path" msgid "FFmpeg or FFprobe cannot be found under the specified path"
msgstr "" msgstr ""
#: upscaler.py:187 upscaler.py:197 #: upscaler.py:193 upscaler.py:203
msgid "Please check the configuration file settings" msgid "Please check the configuration file settings"
msgstr "" msgstr ""
#: upscaler.py:196 #: upscaler.py:202
msgid "Specified driver executable directory doesn't exist" msgid "Specified driver executable directory doesn't exist"
msgstr "" msgstr ""
#: upscaler.py:223 #: upscaler.py:229
msgid "Failed to parse driver argument: {}" msgid "Failed to parse driver argument: {}"
msgstr "" msgstr ""
#: upscaler.py:248 #: upscaler.py:261
msgid "Anime4KCPP doesn't yet support GIF processing"
msgstr ""
#: upscaler.py:263
msgid "Unrecognized driver: {}" msgid "Unrecognized driver: {}"
msgstr "" msgstr ""
#: upscaler.py:303 #: upscaler.py:301
msgid "Starting progress monitor" msgid "Starting progress monitor"
msgstr "" msgstr ""
#: upscaler.py:308 #: upscaler.py:306
msgid "Starting upscaled image cleaner" msgid "Starting upscaled image cleaner"
msgstr "" msgstr ""
#: upscaler.py:317 upscaler.py:334 #: upscaler.py:315 upscaler.py:332
msgid "Killing progress monitor" msgid "Killing progress monitor"
msgstr "" msgstr ""
#: upscaler.py:320 upscaler.py:337 #: upscaler.py:318 upscaler.py:335
msgid "Killing upscaled image cleaner" msgid "Killing upscaled image cleaner"
msgstr "" msgstr ""
#: upscaler.py:341 #: upscaler.py:339
msgid "Terminating all processes" msgid "Terminating all processes"
msgstr "" msgstr ""
#: upscaler.py:348 #: upscaler.py:346
msgid "Main process waiting for subprocesses to exit" msgid "Main process waiting for subprocesses to exit"
msgstr "" msgstr ""
#: upscaler.py:367 upscaler.py:371 #: upscaler.py:365 upscaler.py:369
msgid "Subprocess {} exited with code {}" msgid "Subprocess {} exited with code {}"
msgstr "" msgstr ""
#: upscaler.py:377 #: upscaler.py:375
msgid "Stop signal received" msgid "Stop signal received"
msgstr "" msgstr ""
#: upscaler.py:382 #: upscaler.py:380
msgid "Subprocess execution ran into an error" msgid "Subprocess execution ran into an error"
msgstr "" msgstr ""
#: upscaler.py:430 #: upscaler.py:410
msgid "Upscaling single file: {}" msgid "Loading files into processing queue"
msgstr "" msgstr ""
#: upscaler.py:466 #: upscaler.py:415
msgid "Loading files from multiple paths"
msgstr ""
#: upscaler.py:416 upscaler.py:435 upscaler.py:442
msgid "Input path(s): {}"
msgstr ""
#: upscaler.py:434
msgid "Loading single file"
msgstr ""
#: upscaler.py:441
msgid "Loading files from directory"
msgstr ""
#: upscaler.py:455
msgid "Loaded files into processing queue"
msgstr ""
#: upscaler.py:458
msgid "Input file: {}"
msgstr ""
#: upscaler.py:485
msgid "Starting to upscale image" msgid "Starting to upscale image"
msgstr "" msgstr ""
#: upscaler.py:469 upscaler.py:487 upscaler.py:545 #: upscaler.py:488 upscaler.py:550
msgid "Upscaling completed" msgid "Upscaling completed"
msgstr "" msgstr ""
#: upscaler.py:482 #: upscaler.py:502
msgid "Starting to upscale video with Anime4KCPP"
msgstr ""
#: upscaler.py:496
msgid "Reading video information" msgid "Reading video information"
msgstr "" msgstr ""
#: upscaler.py:510 #: upscaler.py:516
msgid "Aborting: No video stream found" msgid "Aborting: No video stream found"
msgstr "" msgstr ""
#: upscaler.py:531 #: upscaler.py:521
msgid "Unsupported pixel format: {}"
msgstr ""
#: upscaler.py:534
msgid "Framerate: {}" msgid "Framerate: {}"
msgstr "" msgstr ""
#: upscaler.py:543 #: upscaler.py:538
msgid "Unsupported pixel format: {}"
msgstr ""
#: upscaler.py:548
msgid "Starting to upscale extracted frames" msgid "Starting to upscale extracted frames"
msgstr "" msgstr ""
#: upscaler.py:550 #: upscaler.py:555
msgid "File {} ({}) neither an image of a video" msgid "File {} ({}) neither an image nor a video"
msgstr "" msgstr ""
#: upscaler.py:551 #: upscaler.py:556
msgid "Skipping this file" msgid "Skipping this file"
msgstr "" msgstr ""
#: upscaler.py:561 #: upscaler.py:566
msgid "Converting extracted frames into GIF image" msgid "Converting extracted frames into GIF image"
msgstr "" msgstr ""
#: upscaler.py:565 upscaler.py:574 #: upscaler.py:570 upscaler.py:579
msgid "Conversion completed" msgid "Conversion completed"
msgstr "" msgstr ""
#: upscaler.py:570 #: upscaler.py:575
msgid "Converting extracted frames into video" msgid "Converting extracted frames into video"
msgstr "" msgstr ""
#: upscaler.py:578 #: upscaler.py:583
msgid "Migrating audio, subtitles and other streams to upscaled video" msgid "Migrating audio, subtitles and other streams to upscaled video"
msgstr "" msgstr ""
#: upscaler.py:587 #: upscaler.py:593
msgid "Failed to migrate streams" msgid "Failed to migrate streams"
msgstr "" msgstr ""
#: upscaler.py:588 #: upscaler.py:594
msgid "Trying to output video without additional streams" msgid "Trying to output video without additional streams"
msgstr "" msgstr ""
#: upscaler.py:599 #: upscaler.py:610
msgid "Output video file exists, aborting" msgid "Output video file exists"
msgstr "" msgstr ""
#: upscaler.py:603 #: upscaler.py:614
msgid "Created temporary directory to contain file"
msgstr ""
#: upscaler.py:617
msgid "Writing intermediate file to: {}" msgid "Writing intermediate file to: {}"
msgstr "" msgstr ""
#: video2x.py:84 #: video2x.py:85
msgid "" msgid ""
"Video2X Version: {}\n" "Video2X CLI Version: {}\n"
"Upscaler Version: {}\n"
"Author: K4YT3X\n" "Author: K4YT3X\n"
"License: GNU GPL v3\n" "License: GNU GPL v3\n"
"Github Page: https://github.com/k4yt3x/video2x\n" "Github Page: https://github.com/k4yt3x/video2x\n"
"Contact: k4yt3x@k4yt3x.com" "Contact: k4yt3x@k4yt3x.com"
msgstr "" msgstr ""
#: video2x.py:106 #: video2x.py:108
msgid "Video2X Options" msgid "Video2X Options"
msgstr "" msgstr ""
#: video2x.py:107 #: video2x.py:109
msgid "show this help message and exit" msgid "show this help message and exit"
msgstr "" msgstr ""
#: video2x.py:108 #: video2x.py:110
msgid "source video file/directory" msgid "source video file/directory"
msgstr "" msgstr ""
#: video2x.py:109 #: video2x.py:111
msgid "output video file/directory" msgid "output video file/directory"
msgstr "" msgstr ""
#: video2x.py:110 #: video2x.py:112
msgid "video2x config file path" msgid "video2x config file path"
msgstr "" msgstr ""
#: video2x.py:112 #: video2x.py:114
msgid "display version, lawful information and exit" msgid "display version, lawful information and exit"
msgstr "" msgstr ""
#: video2x.py:115 #: video2x.py:117
msgid "Upscaling Options" msgid "Upscaling Options"
msgstr "" msgstr ""
#: video2x.py:116 #: video2x.py:118
msgid "upscaling driver" msgid "upscaling driver"
msgstr "" msgstr ""
#: video2x.py:117 #: video2x.py:119
msgid "scaling ratio" msgid "scaling ratio"
msgstr "" msgstr ""
#: video2x.py:118 #: video2x.py:120
msgid "number of processes to use for upscaling" msgid "number of processes to use for upscaling"
msgstr "" msgstr ""
#: video2x.py:119 #: video2x.py:121
msgid "preserve extracted and upscaled frames" msgid "preserve extracted and upscaled frames"
msgstr "" msgstr ""
#: video2x.py:159 #: video2x.py:161
msgid "This file cannot be imported" msgid "This file cannot be imported"
msgstr "" msgstr ""
#: video2x.py:234 #: video2x.py:236
msgid "Program completed, taking {} seconds" msgid "Program completed, taking {} seconds"
msgstr "" msgstr ""
#: video2x.py:237 #: video2x.py:239
msgid "An exception has occurred" msgid "An exception has occurred"
msgstr "" msgstr ""

View File

@@ -13,7 +13,7 @@ __ __ _ _ ___ __ __
Name: Video2X Controller Name: Video2X Controller
Creator: K4YT3X Creator: K4YT3X
Date Created: Feb 24, 2018 Date Created: Feb 24, 2018
Last Modified: May 15, 2020 Last Modified: May 23, 2020
Editor: BrianPetkovsek Editor: BrianPetkovsek
Last Modified: June 17, 2019 Last Modified: June 17, 2019
@@ -80,7 +80,7 @@ language.install()
_ = language.gettext _ = language.gettext
CLI_VERSION = '4.0.0' CLI_VERSION = '4.0.1'
LEGAL_INFO = _('''Video2X CLI Version: {} LEGAL_INFO = _('''Video2X CLI Version: {}
Upscaler Version: {} Upscaler Version: {}
@@ -107,8 +107,15 @@ def parse_arguments():
# video options # video options
video2x_options = parser.add_argument_group(_('Video2X Options')) video2x_options = parser.add_argument_group(_('Video2X Options'))
video2x_options.add_argument('-h', '--help', action='help', help=_('show this help message and exit')) video2x_options.add_argument('-h', '--help', action='help', help=_('show this help message and exit'))
video2x_options.add_argument('-i', '--input', type=pathlib.Path, help=_('source video file/directory'))
video2x_options.add_argument('-o', '--output', type=pathlib.Path, help=_('output video file/directory')) # 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', video2x_options.add_argument('-c', '--config', type=pathlib.Path, help=_('video2x config file path'), action='store',
default=pathlib.Path(__file__).parent.absolute() / 'video2x.yaml') default=pathlib.Path(__file__).parent.absolute() / 'video2x.yaml')
video2x_options.add_argument('-v', '--version', help=_('display version, lawful information and exit'), action='store_true') video2x_options.add_argument('-v', '--version', help=_('display version, lawful information and exit'), action='store_true')

View File

@@ -1,7 +1,7 @@
# Name: Video2X Configuration File # Name: Video2X Configuration File
# Creator: K4YT3X # Creator: K4YT3X
# Date Created: October 23, 2018 # Date Created: October 23, 2018
# Last Modified: May 14, 2020 # Last Modified: May 26, 2020
# Values here are the default values. Change the value here to # Values here are the default values. Change the value here to
# save the default value permanently. # save the default value permanently.
# Items commented out are parameters irrelevant to this context # Items commented out are parameters irrelevant to this context
@@ -76,6 +76,17 @@ srmd_ncnn_vulkan:
g: 0 # gpu device to use (default=0) g: 0 # gpu device to use (default=0)
j: '1:2:2' # thread count for load/proc/save (default=1:2:2) j: '1:2:2' # thread count for load/proc/save (default=1:2:2)
x: false # enable tta mode x: false # enable tta mode
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
anime4kcpp: anime4kcpp:
path: '%LOCALAPPDATA%\video2x\anime4kcpp\CLI\Anime4KCPP_CLI\Anime4KCPP_CLI' path: '%LOCALAPPDATA%\video2x\anime4kcpp\CLI\Anime4KCPP_CLI\Anime4KCPP_CLI'
#input: null # File for loading (string [=./pic/p1.png]) #input: null # File for loading (string [=./pic/p1.png])
@@ -119,10 +130,11 @@ ffmpeg:
'-f': image2 # force image2 format '-f': image2 # force image2 format
output_options: output_options:
'-vcodec': libx264 # video codec '-vcodec': libx264 # video codec
'-pix_fmt': 'yuv444p10le' # overwrite default pixel format '-pix_fmt': 'yuv420p' # overwrite default pixel format
'-crf': 17 # H.264 Constant Rate Factor '-crf': 17 # H.264 Constant Rate Factor
'-b:v': null # target average bitrate '-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 '-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 # Step 3: Streams Migration
# migrate audio and subtitle streams from original # migrate audio and subtitle streams from original
# video into the upscaled video # video into the upscaled video
@@ -138,6 +150,7 @@ ffmpeg:
- '1:d?' # copy data streams - '1:d?' # copy data streams
- '1:t?' # copy fonts - '1:t?' # copy fonts
'-c': copy # copy codec for all streams '-c': copy # copy codec for all streams
# '-vf': 'minterpolate=''fps=60''' # minterpolate frame interpolation
'-map_metadata': 0 # copy known metadata tags '-map_metadata': 0 # copy known metadata tags
# '-movflags': 'use_metadata_tags' # copy custom/arbitrary metadata tags # '-movflags': 'use_metadata_tags' # copy custom/arbitrary metadata tags
'-pix_fmt': null '-pix_fmt': null

View File

@@ -4,7 +4,7 @@
Creator: Video2X GUI Creator: Video2X GUI
Author: K4YT3X Author: K4YT3X
Date Created: May 5, 2020 Date Created: May 5, 2020
Last Modified: May 15, 2020 Last Modified: May 26, 2020
""" """
# local imports # local imports
@@ -15,6 +15,7 @@ from wrappers.ffmpeg import Ffmpeg
# built-in imports # built-in imports
import contextlib import contextlib
import json import json
import mimetypes
import os import os
import pathlib import pathlib
import sys import sys
@@ -25,13 +26,13 @@ import urllib
import yaml import yaml
# third-party imports # third-party imports
from PyQt5 import QtGui, uic from PyQt5 import uic
from PyQt5.QtCore import * from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import * from PyQt5.QtWidgets import *
import magic import magic
# QObject, pyqtSlot, pyqtSignal, QRunnable, QThreadPool, QAbstractTableModel, Qt
GUI_VERSION = '2.1.0' GUI_VERSION = '2.5.0'
LEGAL_INFO = f'''Video2X GUI Version: {GUI_VERSION}\\ LEGAL_INFO = f'''Video2X GUI Version: {GUI_VERSION}\\
Upscaler Version: {UPSCALER_VERSION}\\ Upscaler Version: {UPSCALER_VERSION}\\
@@ -45,6 +46,7 @@ AVAILABLE_DRIVERS = {
'Waifu2X Converter CPP': 'waifu2x_converter_cpp', 'Waifu2X Converter CPP': 'waifu2x_converter_cpp',
'Waifu2X NCNN Vulkan': 'waifu2x_ncnn_vulkan', 'Waifu2X NCNN Vulkan': 'waifu2x_ncnn_vulkan',
'SRMD NCNN Vulkan': 'srmd_ncnn_vulkan', 'SRMD NCNN Vulkan': 'srmd_ncnn_vulkan',
'RealSR NCNN Vulkan': 'realsr_ncnn_vulkan',
'Anime4KCPP': 'anime4kcpp' 'Anime4KCPP': 'anime4kcpp'
} }
@@ -132,6 +134,14 @@ class InputTableModel(QAbstractTableModel):
input_file_mime_type = magic.from_file(str(file_path.absolute()), mime=True) input_file_mime_type = magic.from_file(str(file_path.absolute()), mime=True)
input_file_type = input_file_mime_type.split('/')[0] input_file_type = input_file_mime_type.split('/')[0]
input_file_subtype = input_file_mime_type.split('/')[1] input_file_subtype = input_file_mime_type.split('/')[1]
# in case python-magic fails to detect file type
# try guessing file mime type with mimetypes
if input_file_type not in ['image', 'video']:
input_file_mime_type = mimetypes.guess_type(file_path.name)[0]
input_file_type = input_file_mime_type.split('/')[0]
input_file_subtype = input_file_mime_type.split('/')[1]
if input_file_type == 'image': if input_file_type == 'image':
if input_file_subtype == 'gif': if input_file_subtype == 'gif':
return 'GIF' return 'GIF'
@@ -183,11 +193,22 @@ class Video2XMainWindow(QMainWindow):
# set window title and icon # set window title and icon
self.video2x_icon_path = str(resource_path('images/video2x.png')) self.video2x_icon_path = str(resource_path('images/video2x.png'))
self.setWindowTitle(f'Video2X GUI {GUI_VERSION}') self.setWindowTitle(f'Video2X GUI {GUI_VERSION}')
self.setWindowIcon(QtGui.QIcon(self.video2x_icon_path)) self.setWindowIcon(QIcon(self.video2x_icon_path))
# register shortcut keys
QShortcut(QKeySequence(Qt.CTRL + Qt.Key_W), self, self.close)
QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Q), self, self.close)
QShortcut(QKeySequence(Qt.CTRL + Qt.Key_I), self, self.select_input_file)
QShortcut(QKeySequence(Qt.CTRL + Qt.Key_O), self, self.select_output_file)
QShortcut(QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_I), self, self.select_input_folder)
QShortcut(QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_O), self, self.select_output_folder)
# menu bar # menu bar
self.action_exit = self.findChild(QAction, 'actionExit') self.action_exit = self.findChild(QAction, 'actionExit')
self.action_exit.triggered.connect(sys.exit) self.action_exit.triggered.connect(self.close)
self.action_shortcuts = self.findChild(QAction, 'actionShortcuts')
self.action_shortcuts.triggered.connect(self.show_shortcuts)
self.action_about = self.findChild(QAction, 'actionAbout') self.action_about = self.findChild(QAction, 'actionAbout')
self.action_about.triggered.connect(self.show_about) self.action_about.triggered.connect(self.show_about)
@@ -326,6 +347,17 @@ class Video2XMainWindow(QMainWindow):
self.srmd_ncnn_vulkan_jobs_line_edit = self.findChild(QLineEdit, 'srmdNcnnVulkanJobsLineEdit') self.srmd_ncnn_vulkan_jobs_line_edit = self.findChild(QLineEdit, 'srmdNcnnVulkanJobsLineEdit')
self.srmd_ncnn_vulkan_tta_check_box = self.findChild(QCheckBox, 'srmdNcnnVulkanTtaCheckBox') self.srmd_ncnn_vulkan_tta_check_box = self.findChild(QCheckBox, 'srmdNcnnVulkanTtaCheckBox')
# realsr-ncnn-vulkan
self.realsr_ncnn_vulkan_path_line_edit = self.findChild(QLineEdit, 'realsrNcnnVulkanPathLineEdit')
self.enable_line_edit_file_drop(self.realsr_ncnn_vulkan_path_line_edit)
self.realsr_ncnn_vulkan_path_select_button = self.findChild(QPushButton, 'realsrNcnnVulkanPathSelectButton')
self.realsr_ncnn_vulkan_path_select_button.clicked.connect(lambda: self.select_driver_binary_path(self.realsr_ncnn_vulkan_path_line_edit))
self.realsr_ncnn_vulkan_tile_size_spin_box = self.findChild(QSpinBox, 'realsrNcnnVulkanTileSizeSpinBox')
self.realsr_ncnn_vulkan_model_combo_box = self.findChild(QComboBox, 'realsrNcnnVulkanModelComboBox')
self.realsr_ncnn_vulkan_gpu_id_spin_box = self.findChild(QSpinBox, 'realsrNcnnVulkanGpuIdSpinBox')
self.realsr_ncnn_vulkan_jobs_line_edit = self.findChild(QLineEdit, 'realsrNcnnVulkanJobsLineEdit')
self.realsr_ncnn_vulkan_tta_check_box = self.findChild(QCheckBox, 'realsrNcnnVulkanTtaCheckBox')
# anime4k # anime4k
self.anime4kcpp_path_line_edit = self.findChild(QLineEdit, 'anime4kCppPathLineEdit') self.anime4kcpp_path_line_edit = self.findChild(QLineEdit, 'anime4kCppPathLineEdit')
self.enable_line_edit_file_drop(self.anime4kcpp_path_line_edit) self.enable_line_edit_file_drop(self.anime4kcpp_path_line_edit)
@@ -363,6 +395,7 @@ class Video2XMainWindow(QMainWindow):
self.ffmpeg_assemble_video_output_options_video_codec_line_edit = self.findChild(QLineEdit, 'ffmpegAssembleVideoOutputOptionsVideoCodecLineEdit') self.ffmpeg_assemble_video_output_options_video_codec_line_edit = self.findChild(QLineEdit, 'ffmpegAssembleVideoOutputOptionsVideoCodecLineEdit')
self.ffmpeg_assemble_video_output_options_pixel_format_line_edit = self.findChild(QLineEdit, 'ffmpegAssembleVideoOutputOptionsPixelFormatLineEdit') self.ffmpeg_assemble_video_output_options_pixel_format_line_edit = self.findChild(QLineEdit, 'ffmpegAssembleVideoOutputOptionsPixelFormatLineEdit')
self.ffmpeg_assemble_video_output_options_crf_spin_box = self.findChild(QSpinBox, 'ffmpegAssembleVideoOutputOptionsCrfSpinBox') self.ffmpeg_assemble_video_output_options_crf_spin_box = self.findChild(QSpinBox, 'ffmpegAssembleVideoOutputOptionsCrfSpinBox')
self.ffmpeg_assemble_video_output_options_tune_combo_box = self.findChild(QComboBox, 'ffmpegAssembleVideoOutputOptionsTuneComboBox')
self.ffmpeg_assemble_video_output_options_bitrate_line_edit = self.findChild(QLineEdit, 'ffmpegAssembleVideoOutputOptionsBitrateLineEdit') self.ffmpeg_assemble_video_output_options_bitrate_line_edit = self.findChild(QLineEdit, 'ffmpegAssembleVideoOutputOptionsBitrateLineEdit')
self.ffmpeg_assemble_video_output_options_ensure_divisible_check_box = self.findChild(QCheckBox, 'ffmpegAssembleVideoOutputOptionsEnsureDivisibleCheckBox') self.ffmpeg_assemble_video_output_options_ensure_divisible_check_box = self.findChild(QCheckBox, 'ffmpegAssembleVideoOutputOptionsEnsureDivisibleCheckBox')
self.ffmpeg_assemble_video_hardware_acceleration_check_box = self.findChild(QCheckBox, 'ffmpegAssembleVideoHardwareAccelerationCheckBox') self.ffmpeg_assemble_video_hardware_acceleration_check_box = self.findChild(QCheckBox, 'ffmpegAssembleVideoHardwareAccelerationCheckBox')
@@ -374,9 +407,12 @@ class Video2XMainWindow(QMainWindow):
self.ffmpeg_migrate_streams_output_options_mapping_data_check_box_check_box = self.findChild(QCheckBox, 'ffmpegMigrateStreamsOutputOptionsMappingDataCheckBox') self.ffmpeg_migrate_streams_output_options_mapping_data_check_box_check_box = self.findChild(QCheckBox, 'ffmpegMigrateStreamsOutputOptionsMappingDataCheckBox')
self.ffmpeg_migrate_streams_output_options_mapping_font_check_box_check_box = self.findChild(QCheckBox, 'ffmpegMigrateStreamsOutputOptionsMappingFontCheckBox') self.ffmpeg_migrate_streams_output_options_mapping_font_check_box_check_box = self.findChild(QCheckBox, 'ffmpegMigrateStreamsOutputOptionsMappingFontCheckBox')
self.ffmpeg_migrate_streams_output_options_pixel_format_line_edit = self.findChild(QLineEdit, 'ffmpegMigrateStreamsOutputOptionsPixelFormatLineEdit') self.ffmpeg_migrate_streams_output_options_pixel_format_line_edit = self.findChild(QLineEdit, 'ffmpegMigrateStreamsOutputOptionsPixelFormatLineEdit')
self.ffmpeg_migrate_streams_output_options_copy_codec_check_box = self.findChild(QCheckBox, 'ffmpegMigrateStreamsOutputOptionsCopyCodecCheckBox') self.ffmpeg_migrate_streams_output_options_frame_interpolation_spin_box = self.findChild(QSpinBox, 'ffmpegMigrateStreamsOutputOptionsFrameInterpolationSpinBox')
self.ffmpeg_migrate_streams_output_options_copy_known_metadata_tags_check_box = self.findChild(QCheckBox, 'ffmpegMigrateStreamsOutputOptionsOtherCopyKnownMetadataTagsCheckBox') self.ffmpeg_migrate_streams_output_options_frame_interpolation_spin_box.valueChanged.connect(self.mutually_exclude_frame_interpolation_stream_copy)
self.ffmpeg_migrate_streams_output_options_copy_arbitrary_metadata_tags_check_box = self.findChild(QCheckBox, 'ffmpegMigrateStreamsOutputOptionsOtherCopyArbitraryMetadataTagsCheckBox') self.ffmpeg_migrate_streams_output_options_frame_interpolation_spin_box.textChanged.connect(self.mutually_exclude_frame_interpolation_stream_copy)
self.ffmpeg_migrate_streams_output_options_copy_streams_check_box = self.findChild(QCheckBox, 'ffmpegMigrateStreamsOutputOptionsCopyStreamsCheckBox')
self.ffmpeg_migrate_streams_output_options_copy_known_metadata_tags_check_box = self.findChild(QCheckBox, 'ffmpegMigrateStreamsOutputOptionsCopyKnownMetadataTagsCheckBox')
self.ffmpeg_migrate_streams_output_options_copy_arbitrary_metadata_tags_check_box = self.findChild(QCheckBox, 'ffmpegMigrateStreamsOutputOptionsCopyArbitraryMetadataTagsCheckBox')
self.ffmpeg_migrate_streams_hardware_acceleration_check_box = self.findChild(QCheckBox, 'ffmpegMigrateStreamsHardwareAccelerationCheckBox') self.ffmpeg_migrate_streams_hardware_acceleration_check_box = self.findChild(QCheckBox, 'ffmpegMigrateStreamsHardwareAccelerationCheckBox')
# Gifski settings # Gifski settings
@@ -396,48 +432,6 @@ class Video2XMainWindow(QMainWindow):
# load configurations after GUI initialization # load configurations after GUI initialization
self.load_configurations() self.load_configurations()
def dragEnterEvent(self, event):
if event.mimeData().hasUrls():
event.accept()
else:
event.ignore()
def dropEvent(self, event):
input_paths = [pathlib.Path(u.toLocalFile()) for u in event.mimeData().urls()]
for path in input_paths:
if (path.is_file() or path.is_dir()) and not self.input_table_path_exists(path):
self.input_table_data.append(path)
self.update_input_table()
self.update_output_path()
def enable_line_edit_file_drop(self, line_edit: QLineEdit):
line_edit.dragEnterEvent = self.dragEnterEvent
line_edit.dropEvent = lambda event: line_edit.setText(str(pathlib.Path(event.mimeData().urls()[0].toLocalFile()).absolute()))
def show_ffprobe_output(self, event):
input_paths = [pathlib.Path(u.toLocalFile()) for u in event.mimeData().urls()]
if not input_paths[0].is_file():
return
ffmpeg_object = Ffmpeg(self.ffmpeg_settings)
file_info_json = ffmpeg_object.probe_file_info(input_paths[0])
self.ffprobe_plain_text_edit.setPlainText(json.dumps(file_info_json, indent=2))
@staticmethod
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)
def load_configurations(self): def load_configurations(self):
# get config file path from line edit # get config file path from line edit
@@ -515,6 +509,14 @@ class Video2XMainWindow(QMainWindow):
self.srmd_ncnn_vulkan_jobs_line_edit.setText(settings['j']) self.srmd_ncnn_vulkan_jobs_line_edit.setText(settings['j'])
self.srmd_ncnn_vulkan_tta_check_box.setChecked(settings['x']) self.srmd_ncnn_vulkan_tta_check_box.setChecked(settings['x'])
# realsr-ncnn-vulkan
settings = self.config['realsr_ncnn_vulkan']
self.realsr_ncnn_vulkan_path_line_edit.setText(str(pathlib.Path(os.path.expandvars(settings['path'])).absolute()))
self.realsr_ncnn_vulkan_tile_size_spin_box.setValue(settings['t'])
self.realsr_ncnn_vulkan_gpu_id_spin_box.setValue(settings['g'])
self.realsr_ncnn_vulkan_jobs_line_edit.setText(settings['j'])
self.realsr_ncnn_vulkan_tta_check_box.setChecked(settings['x'])
# anime4k # anime4k
settings = self.config['anime4kcpp'] settings = self.config['anime4kcpp']
self.anime4kcpp_path_line_edit.setText(str(pathlib.Path(os.path.expandvars(settings['path'])).absolute())) self.anime4kcpp_path_line_edit.setText(str(pathlib.Path(os.path.expandvars(settings['path'])).absolute()))
@@ -549,6 +551,7 @@ class Video2XMainWindow(QMainWindow):
self.ffmpeg_assemble_video_output_options_video_codec_line_edit.setText(settings['output_options']['-vcodec']) self.ffmpeg_assemble_video_output_options_video_codec_line_edit.setText(settings['output_options']['-vcodec'])
self.ffmpeg_assemble_video_output_options_pixel_format_line_edit.setText(settings['output_options']['-pix_fmt']) self.ffmpeg_assemble_video_output_options_pixel_format_line_edit.setText(settings['output_options']['-pix_fmt'])
self.ffmpeg_assemble_video_output_options_crf_spin_box.setValue(settings['output_options']['-crf']) self.ffmpeg_assemble_video_output_options_crf_spin_box.setValue(settings['output_options']['-crf'])
self.ffmpeg_assemble_video_output_options_tune_combo_box.setCurrentText(settings['output_options']['-tune'])
self.ffmpeg_assemble_video_output_options_bitrate_line_edit.setText(settings['output_options']['-b:v']) self.ffmpeg_assemble_video_output_options_bitrate_line_edit.setText(settings['output_options']['-b:v'])
# migrate streams # migrate streams
@@ -615,6 +618,14 @@ class Video2XMainWindow(QMainWindow):
self.config['srmd_ncnn_vulkan']['j'] = self.srmd_ncnn_vulkan_jobs_line_edit.text() self.config['srmd_ncnn_vulkan']['j'] = self.srmd_ncnn_vulkan_jobs_line_edit.text()
self.config['srmd_ncnn_vulkan']['x'] = self.srmd_ncnn_vulkan_tta_check_box.isChecked() self.config['srmd_ncnn_vulkan']['x'] = self.srmd_ncnn_vulkan_tta_check_box.isChecked()
# realsr-ncnn-vulkan
self.config['realsr_ncnn_vulkan']['path'] = os.path.expandvars(self.realsr_ncnn_vulkan_path_line_edit.text())
self.config['realsr_ncnn_vulkan']['t'] = self.realsr_ncnn_vulkan_tile_size_spin_box.value()
self.config['realsr_ncnn_vulkan']['m'] = str((pathlib.Path(self.config['realsr_ncnn_vulkan']['path']).parent / self.realsr_ncnn_vulkan_model_combo_box.currentText()).absolute())
self.config['realsr_ncnn_vulkan']['g'] = self.realsr_ncnn_vulkan_gpu_id_spin_box.value()
self.config['realsr_ncnn_vulkan']['j'] = self.realsr_ncnn_vulkan_jobs_line_edit.text()
self.config['realsr_ncnn_vulkan']['x'] = self.realsr_ncnn_vulkan_tta_check_box.isChecked()
# anime4k # anime4k
self.config['anime4kcpp']['path'] = os.path.expandvars(self.anime4kcpp_path_line_edit.text()) self.config['anime4kcpp']['path'] = os.path.expandvars(self.anime4kcpp_path_line_edit.text())
self.config['anime4kcpp']['passes'] = self.anime4kcpp_passes_spin_box.value() self.config['anime4kcpp']['passes'] = self.anime4kcpp_passes_spin_box.value()
@@ -648,6 +659,7 @@ class Video2XMainWindow(QMainWindow):
self.config['ffmpeg']['assemble_video']['output_options']['-vcodec'] = self.ffmpeg_assemble_video_output_options_video_codec_line_edit.text() self.config['ffmpeg']['assemble_video']['output_options']['-vcodec'] = self.ffmpeg_assemble_video_output_options_video_codec_line_edit.text()
self.config['ffmpeg']['assemble_video']['output_options']['-pix_fmt'] = self.ffmpeg_assemble_video_output_options_pixel_format_line_edit.text() self.config['ffmpeg']['assemble_video']['output_options']['-pix_fmt'] = self.ffmpeg_assemble_video_output_options_pixel_format_line_edit.text()
self.config['ffmpeg']['assemble_video']['output_options']['-crf'] = self.ffmpeg_assemble_video_output_options_crf_spin_box.value() self.config['ffmpeg']['assemble_video']['output_options']['-crf'] = self.ffmpeg_assemble_video_output_options_crf_spin_box.value()
self.config['ffmpeg']['assemble_video']['output_options']['-tune'] = self.ffmpeg_assemble_video_output_options_tune_combo_box.currentText()
if self.ffmpeg_assemble_video_output_options_bitrate_line_edit.text() != '': if self.ffmpeg_assemble_video_output_options_bitrate_line_edit.text() != '':
self.config['ffmpeg']['assemble_video']['output_options']['-b:v'] = self.ffmpeg_assemble_video_output_options_bitrate_line_edit.text() self.config['ffmpeg']['assemble_video']['output_options']['-b:v'] = self.ffmpeg_assemble_video_output_options_bitrate_line_edit.text()
else: else:
@@ -691,8 +703,18 @@ class Video2XMainWindow(QMainWindow):
self.config['ffmpeg']['migrate_streams']['output_options']['-pix_fmt'] = self.ffmpeg_migrate_streams_output_options_pixel_format_line_edit.text() self.config['ffmpeg']['migrate_streams']['output_options']['-pix_fmt'] = self.ffmpeg_migrate_streams_output_options_pixel_format_line_edit.text()
if (fps := self.ffmpeg_migrate_streams_output_options_frame_interpolation_spin_box.value()) > 0:
if ('-vf' in self.config['ffmpeg']['migrate_streams']['output_options'] and
len(self.config['ffmpeg']['migrate_streams']['output_options']['-vf']) > 0 and
'minterpolate=' not in self.config['ffmpeg']['migrate_streams']['output_options']['-vf']):
self.config['ffmpeg']['migrate_streams']['output_options']['-vf'] += f',minterpolate=\'fps={fps}\''
else:
self.config['ffmpeg']['migrate_streams']['output_options']['-vf'] = f'minterpolate=\'fps={fps}\''
else:
self.config['ffmpeg']['migrate_streams']['output_options'].pop('-vf', None)
# copy source codec # copy source codec
if self.ffmpeg_migrate_streams_output_options_copy_codec_check_box.isChecked(): if self.ffmpeg_migrate_streams_output_options_copy_streams_check_box.isChecked():
self.config['ffmpeg']['migrate_streams']['output_options']['-c'] = 'copy' self.config['ffmpeg']['migrate_streams']['output_options']['-c'] = 'copy'
else: else:
self.config['ffmpeg']['migrate_streams']['output_options'].pop('-c', None) self.config['ffmpeg']['migrate_streams']['output_options'].pop('-c', None)
@@ -728,6 +750,56 @@ class Video2XMainWindow(QMainWindow):
self.config['gifski']['once'] = self.gifski_once_check_box.isChecked() self.config['gifski']['once'] = self.gifski_once_check_box.isChecked()
self.config['gifski']['quiet'] = self.gifski_quiet_check_box.isChecked() self.config['gifski']['quiet'] = self.gifski_quiet_check_box.isChecked()
def dragEnterEvent(self, event):
if event.mimeData().hasUrls():
event.accept()
else:
event.ignore()
def dropEvent(self, event):
input_paths = [pathlib.Path(u.toLocalFile()) for u in event.mimeData().urls()]
for path in input_paths:
if (path.is_file() or path.is_dir()) and not self.input_table_path_exists(path):
self.input_table_data.append(path)
self.update_output_path()
self.update_input_table()
def enable_line_edit_file_drop(self, line_edit: QLineEdit):
line_edit.dragEnterEvent = self.dragEnterEvent
line_edit.dropEvent = lambda event: line_edit.setText(str(pathlib.Path(event.mimeData().urls()[0].toLocalFile()).absolute()))
def show_ffprobe_output(self, event):
input_paths = [pathlib.Path(u.toLocalFile()) for u in event.mimeData().urls()]
if not input_paths[0].is_file():
return
ffmpeg_object = Ffmpeg(self.ffmpeg_settings)
file_info_json = ffmpeg_object.probe_file_info(input_paths[0])
self.ffprobe_plain_text_edit.setPlainText(json.dumps(file_info_json, indent=2))
@staticmethod
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)
def mutually_exclude_frame_interpolation_stream_copy(self):
if self.ffmpeg_migrate_streams_output_options_frame_interpolation_spin_box.value() > 0:
self.ffmpeg_migrate_streams_output_options_copy_streams_check_box.setChecked(False)
self.ffmpeg_migrate_streams_output_options_copy_streams_check_box.setDisabled(True)
else:
self.ffmpeg_migrate_streams_output_options_copy_streams_check_box.setChecked(True)
self.ffmpeg_migrate_streams_output_options_copy_streams_check_box.setDisabled(False)
def update_gui_for_driver(self): def update_gui_for_driver(self):
current_driver = AVAILABLE_DRIVERS[self.driver_combo_box.currentText()] current_driver = AVAILABLE_DRIVERS[self.driver_combo_box.currentText()]
@@ -744,6 +816,10 @@ class Video2XMainWindow(QMainWindow):
self.scale_ratio_double_spin_box.setMinimum(2.0) self.scale_ratio_double_spin_box.setMinimum(2.0)
self.scale_ratio_double_spin_box.setMaximum(4.0) self.scale_ratio_double_spin_box.setMaximum(4.0)
self.scale_ratio_double_spin_box.setValue(2.0) self.scale_ratio_double_spin_box.setValue(2.0)
elif current_driver == 'realsr_ncnn_vulkan':
self.scale_ratio_double_spin_box.setMinimum(4.0)
self.scale_ratio_double_spin_box.setMaximum(4.0)
self.scale_ratio_double_spin_box.setValue(4.0)
# update preferred processes/threads count # update preferred processes/threads count
if current_driver == 'anime4kcpp': if current_driver == 'anime4kcpp':
@@ -764,13 +840,16 @@ class Video2XMainWindow(QMainWindow):
for item in items_to_delete: for item in items_to_delete:
self.input_table_data.remove(item) self.input_table_data.remove(item)
self.update_output_path()
self.update_input_table() self.update_input_table()
def input_table_clear_all(self): def input_table_clear_all(self):
self.input_table_data = [] self.input_table_data = []
self.update_output_path()
self.update_input_table() self.update_input_table()
def input_table_path_exists(self, input_path): def input_table_path_exists(self, input_path: pathlib.Path) -> bool:
for path in self.input_table_data: for path in self.input_table_data:
# not using Path.samefile since file may not exist # not using Path.samefile since file may not exist
if str(path.absolute()) == str(input_path.absolute()): if str(path.absolute()) == str(input_path.absolute()):
@@ -790,58 +869,74 @@ class Video2XMainWindow(QMainWindow):
return pathlib.Path(folder_selected) return pathlib.Path(folder_selected)
def update_output_path(self): def update_output_path(self):
# if there is more than one input # if input list is empty
if len(self.input_table_data) != 1: # clear output path
return if len(self.input_table_data) == 0:
self.output_line_edit.setText('')
input_path = self.input_table_data[0] # if there are multiple output files
# give up if input path doesn't exist or isn't a file or a directory # use cwd/output directory for output
if not input_path.exists() or not (input_path.is_file() or input_path.is_dir()): elif len(self.input_table_data) > 1:
return self.output_line_edit.setText(str((pathlib.Path.cwd() / 'output').absolute()))
if input_path.is_file(): # if there's only one input file
# generate output file/directory name automatically
elif len(self.input_table_data) == 1:
input_path = self.input_table_data[0]
# give up if input path doesn't exist or isn't a file or a directory
if not input_path.exists() or not (input_path.is_file() or input_path.is_dir()):
return
# generate suffix automatically
input_file_mime_type = magic.from_file(str(input_path.absolute()), mime=True)
input_file_type = input_file_mime_type.split('/')[0]
input_file_subtype = input_file_mime_type.split('/')[1]
# if input file is an image
if input_file_type == 'image':
# if file is a gif, use .gif
if input_file_subtype == 'gif':
suffix = '.gif'
# otherwise, use .png by default for all images
else:
suffix = '.png'
# if input is video, use .mp4 as output by default
elif input_file_type == 'video':
suffix = '.mp4'
# if failed to detect file type
# use input file's suffix
else:
suffix = input_path.suffix
output_path = input_path.parent / f'{input_path.stem}_output{suffix}'
elif input_path.is_dir():
output_path = input_path.parent / f'{input_path.stem}_output'
# try up to 1000 times
output_path_id = 0
while output_path.exists() and output_path_id <= 1000:
if input_path.is_file(): if input_path.is_file():
output_path = input_path.parent / pathlib.Path(f'{input_path.stem}_output_{output_path_id}{suffix}')
elif input_path.is_dir():
output_path = input_path.parent / pathlib.Path(f'{input_path.stem}_output_{output_path_id}')
output_path_id += 1
if not output_path.exists(): # generate suffix automatically
self.output_line_edit.setText(str(output_path.absolute())) input_file_mime_type = magic.from_file(str(input_path.absolute()), mime=True)
input_file_type = input_file_mime_type.split('/')[0]
input_file_subtype = input_file_mime_type.split('/')[1]
# in case python-magic fails to detect file type
# try guessing file mime type with mimetypes
if input_file_type not in ['image', 'video']:
input_file_mime_type = mimetypes.guess_type(input_path.name)[0]
input_file_type = input_file_mime_type.split('/')[0]
input_file_subtype = input_file_mime_type.split('/')[1]
# if input file is an image
if input_file_type == 'image':
# if file is a gif, use .gif
if input_file_subtype == 'gif':
suffix = '.gif'
# otherwise, use .png by default for all images
else:
suffix = '.png'
# if input is video, use .mp4 as output by default
elif input_file_type == 'video':
suffix = '.mp4'
# if failed to detect file type
# use input file's suffix
else:
suffix = input_path.suffix
output_path = input_path.parent / f'{input_path.stem}_output{suffix}'
elif input_path.is_dir():
output_path = input_path.parent / f'{input_path.stem}_output'
# try up to 1000 times
output_path_id = 0
while output_path.exists() and output_path_id <= 1000:
if input_path.is_file():
output_path = input_path.parent / pathlib.Path(f'{input_path.stem}_output_{output_path_id}{suffix}')
elif input_path.is_dir():
output_path = input_path.parent / pathlib.Path(f'{input_path.stem}_output_{output_path_id}')
output_path_id += 1
if not output_path.exists():
self.output_line_edit.setText(str(output_path.absolute()))
def select_input_file(self): def select_input_file(self):
if ((input_file := self.select_file('Select Input File')) is None or if ((input_file := self.select_file('Select Input File')) is None or
@@ -880,15 +975,28 @@ class Video2XMainWindow(QMainWindow):
self.config_line_edit.setText(str(config_file.absolute())) self.config_line_edit.setText(str(config_file.absolute()))
self.load_configurations() self.load_configurations()
def select_driver_binary_path(self, driver_line_edit): def select_driver_binary_path(self, driver_line_edit: QLineEdit):
if (driver_binary_path := self.select_file('Select Driver Binary File')) is None: if (driver_binary_path := self.select_file('Select Driver Binary File')) is None:
return return
driver_line_edit.setText(str(driver_binary_path.absolute())) driver_line_edit.setText(str(driver_binary_path.absolute()))
def show_about(self, message: str): def show_shortcuts(self):
message_box = QMessageBox(self)
message_box.setWindowTitle('Video2X Shortcuts')
message_box.setTextFormat(Qt.MarkdownText)
shortcut_information = '''**Ctrl+W**:\tExit application\\
**Ctrl+Q**:\tExit application\\
**Ctrl+I**:\tOpen select input file dialog\\
**Ctrl+O**:\tOpen select output file dialog\\
**Ctrl+Shift+I**:\tOpen select input folder dialog\\
**Ctrl+Shift+O**:\tOpen select output folder dialog'''
message_box.setText(shortcut_information)
message_box.exec_()
def show_about(self):
message_box = QMessageBox(self) message_box = QMessageBox(self)
message_box.setWindowTitle('About Video2X') message_box.setWindowTitle('About Video2X')
message_box.setIconPixmap(QtGui.QPixmap(self.video2x_icon_path).scaled(64, 64)) message_box.setIconPixmap(QPixmap(self.video2x_icon_path).scaled(64, 64))
message_box.setTextFormat(Qt.MarkdownText) message_box.setTextFormat(Qt.MarkdownText)
message_box.setText(LEGAL_INFO) message_box.setText(LEGAL_INFO)
message_box.exec_() message_box.exec_()
@@ -915,14 +1023,14 @@ class Video2XMainWindow(QMainWindow):
message_box.setTextFormat(Qt.MarkdownText) message_box.setTextFormat(Qt.MarkdownText)
error_message = '''Upscaler ran into an error:\\ error_message = '''Upscaler ran into an error:\\
**{}**\\ {}\\
Check the console output for details.\\ Check the console output for details.\\
When reporting an error, please include console output.\\ When reporting an error, please include console output.\\
You can [submit an issue on GitHub](https://github.com/k4yt3x/video2x/issues/new?assignees=K4YT3X&labels=bug&template=bug-report.md&title={}) to report this error.''' You can [submit an issue on GitHub](https://github.com/k4yt3x/video2x/issues/new?assignees=K4YT3X&labels=bug&template=bug-report.md&title={}) to report this error.'''
message_box.setText(error_message.format(exception, urllib.parse.quote(str(exception)))) message_box.setText(error_message.format(exception, urllib.parse.quote(str(exception))))
message_box.exec_() message_box.exec_()
def progress_monitor(self, progress_callback): def progress_monitor(self, progress_callback: pyqtSignal):
# initialize progress bar values # initialize progress bar values
upscale_begin_time = time.time() upscale_begin_time = time.time()
@@ -976,7 +1084,7 @@ You can [submit an issue on GitHub](https://github.com/k4yt3x/video2x/issues/new
# if show frame is checked, show preview image # if show frame is checked, show preview image
if self.frame_preview_show_preview_check_box.isChecked() and last_frame_upscaled.is_file(): if self.frame_preview_show_preview_check_box.isChecked() and last_frame_upscaled.is_file():
last_frame_pixmap = QtGui.QPixmap(str(last_frame_upscaled.absolute())) last_frame_pixmap = QPixmap(str(last_frame_upscaled.absolute()))
# the -2 here behind geometry subtracts frame size from width and height # the -2 here behind geometry subtracts frame size from width and height
self.frame_preview_label.setPixmap(last_frame_pixmap.scaled(self.frame_preview_label.width() - 2, self.frame_preview_label.setPixmap(last_frame_pixmap.scaled(self.frame_preview_label.width() - 2,
self.frame_preview_label.height() - 2, self.frame_preview_label.height() - 2,
@@ -1093,13 +1201,39 @@ You can [submit an issue on GitHub](https://github.com/k4yt3x/video2x/issues/new
self.reset_progress_display() self.reset_progress_display()
def stop(self): def stop(self):
with contextlib.suppress(AttributeError):
self.upscaler.running = False
def closeEvent(self, event): try:
# if upscaler is running, ask the user for confirmation
if self.upscaler.running is True:
confirmation = QMessageBox.question(self,
'Stopping Confirmation',
'Are you sure you want to want to stop the upscaling process?',
QMessageBox.Yes,
QMessageBox.No)
# if the user indeed wants to stop processing
if confirmation == QMessageBox.Yes:
with contextlib.suppress(AttributeError):
self.upscaler.running = False
return True
# if the user doesn't want ot stop processing
else:
return False
# if the upscaler is not running
else:
return True
# if an AttributeError happens
# that means the upscaler object haven't been created yet
except AttributeError:
return True
def closeEvent(self, event: QCloseEvent):
# try cleaning up temp directories # try cleaning up temp directories
self.stop() if self.stop():
event.accept() event.accept()
else:
event.ignore()
# this file shouldn't be imported # this file shouldn't be imported

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject> <!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.12.0, 2020-05-14T22:33:50. --> <!-- Written by QtCreator 4.12.0, 2020-05-26T06:35:20. -->
<qtcreator> <qtcreator>
<data> <data>
<variable>EnvironmentId</variable> <variable>EnvironmentId</variable>

View File

@@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>671</width> <width>673</width>
<height>802</height> <height>844</height>
</rect> </rect>
</property> </property>
<property name="acceptDrops"> <property name="acceptDrops">
@@ -270,7 +270,57 @@
<item> <item>
<widget class="QComboBox" name="driverComboBox"> <widget class="QComboBox" name="driverComboBox">
<property name="toolTip"> <property name="toolTip">
<string>Driver to use for upscaling. Waifu2x Caffe is only for Nvidia GPUs.</string> <string>&lt;p style=&quot;-qt-block-indent: 0; text-indent: 0px; margin: 0px;&quot;&gt;&lt;span style=&quot;font-size: 8pt;&quot;&gt;Driver to use for
upscaling. &lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li style=&quot;-qt-block-indent: 0; text-indent: 0px; margin: 0px;&quot;&gt;&lt;span style=&quot;font-size: 8pt;&quot;&gt;Waifu2X Caffe&lt;/span&gt;
&lt;ul&gt;
&lt;li style=&quot;-qt-block-indent: 0; text-indent: 0px; margin: 0px;&quot;&gt;&lt;span
style=&quot;font-size: 8pt; font-weight: 600;&quot;&gt;requires Nvidia GPU and CUDA/cuDNN&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;-qt-block-indent: 0; text-indent: 0px; margin: 0px;&quot;&gt;&lt;span style=&quot;font-size: 8pt;&quot;&gt;Caffe
implementation of waifu2x which is classic and stable&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;-qt-block-indent: 0; text-indent: 0px; margin: 0px;&quot;&gt;&lt;span style=&quot;font-size: 8pt;&quot;&gt;Lots of models
available&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;-qt-block-indent: 0; text-indent: 0px; margin: 0px;&quot;&gt;&lt;span style=&quot;font-size: 8pt;&quot;&gt;Waifu2X Converter
CPP&lt;/span&gt;
&lt;ul&gt;
&lt;li style=&quot;-qt-block-indent: 0; text-indent: 0px; margin: 0px;&quot;&gt;&lt;span style=&quot;font-size: 8pt;&quot;&gt;CPP
implementation of waifu2x&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;-qt-block-indent: 0; text-indent: 0px; margin: 0px;&quot;&gt;&lt;span style=&quot;font-size: 8pt;&quot;&gt;Uses OpenCL
and OpenCV for graphical processing&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;-qt-block-indent: 0; text-indent: 0px; margin: 0px;&quot;&gt;&lt;span style=&quot;font-size: 8pt;&quot;&gt;Waifu2X NCNN
Vulkan&lt;/span&gt;
&lt;ul&gt;
&lt;li style=&quot;-qt-block-indent: 0; text-indent: 0px; margin: 0px;&quot;&gt;&lt;span style=&quot;font-size: 8pt;&quot;&gt;NCNN
implementation of waifu2x&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;-qt-block-indent: 0; text-indent: 0px; margin: 0px;&quot;&gt;&lt;span style=&quot;font-size: 8pt;&quot;&gt;Uses Vulkan
API for graphical processing&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;-qt-block-indent: 0; text-indent: 0px; margin: 0px;&quot;&gt;&lt;span style=&quot;font-size: 8pt;&quot;&gt;SRMD NCNN
Vulkan&lt;/span&gt;
&lt;ul&gt;
&lt;li style=&quot;-qt-block-indent: 0; text-indent: 0px; margin: 0px;&quot;&gt;&lt;span style=&quot;font-size: 8pt;&quot;&gt;NCNN
implementation of SRMD&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;-qt-block-indent: 0; text-indent: 0px; margin: 0px;&quot;&gt;&lt;span style=&quot;font-size: 8pt;&quot;&gt;Uses Vulkan
API for graphical processing&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;-qt-block-indent: 0; text-indent: 0px; margin: 0px;&quot;&gt;&lt;span style=&quot;font-size: 8pt;&quot;&gt;Anime4KCPP&lt;/span&gt;
&lt;ul&gt;
&lt;li style=&quot;-qt-block-indent: 0; text-indent: 0px; margin: 0px;&quot;&gt;&lt;span style=&quot;font-size: 8pt;&quot;&gt;CPP
implementation of Anime4K&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;-qt-block-indent: 0; text-indent: 0px; margin: 0px;&quot;&gt;&lt;span style=&quot;font-size: 8pt;&quot;&gt;Very fast but
low quality&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;-qt-block-indent: 0; text-indent: 0px; margin: 0px;&quot;&gt;&lt;span style=&quot;font-size: 8pt;&quot;&gt;Multithreading
is preferred&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</string>
</property> </property>
<item> <item>
<property name="text"> <property name="text">
@@ -292,6 +342,11 @@
<string>SRMD NCNN Vulkan</string> <string>SRMD NCNN Vulkan</string>
</property> </property>
</item> </item>
<item>
<property name="text">
<string>RealSR NCNN Vulkan</string>
</property>
</item>
<item> <item>
<property name="text"> <property name="text">
<string>Anime4KCPP</string> <string>Anime4KCPP</string>
@@ -1334,6 +1389,131 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="realsrNcnnVulkanTab">
<attribute name="title">
<string>RealSR NCNN Vulkan</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_34">
<item>
<layout class="QHBoxLayout" name="realsrNcnnVulkanPathHorizontalLayout">
<item>
<widget class="QLineEdit" name="realsrNcnnVulkanPathLineEdit"/>
</item>
<item>
<widget class="QPushButton" name="realsrNcnnVulkanPathSelectButton">
<property name="text">
<string>Select Binary Path</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="realsrNcnnVulkanTileSizeHorizontalLayout">
<item>
<widget class="QLabel" name="realsrNcnnVulkanTileSizeLabel">
<property name="text">
<string>Tile Size</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="realsrNcnnVulkanTileSizeSpinBox">
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>99999</number>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="realsrNcnnVulkanModelHorizontalLayout">
<item>
<widget class="QLabel" name="realsrNcnnVulkanModelLabel">
<property name="text">
<string>Model</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="realsrNcnnVulkanModelComboBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If the input file contains very little noise, DF2K will produce sharper outputs.&lt;/p&gt;&lt;p&gt;However, if the input is noisy, DF2K might produce artifacts. DF2K_JPEG will then be preferred.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<item>
<property name="text">
<string>models-DF2K_JPEG</string>
</property>
</item>
<item>
<property name="text">
<string>models-DF2K</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="realsrNcnnVulkanGpuIdHorizontalLayout">
<item>
<widget class="QLabel" name="realsrNcnnVulkanGpuIdLabel">
<property name="text">
<string>GPU ID</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="realsrNcnnVulkanGpuIdSpinBox"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="realsrNcnnVulkanJobsHorizontalLayout">
<item>
<widget class="QLabel" name="realsrNcnnVulkanJobsLabel">
<property name="text">
<string>Jobs</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="realsrNcnnVulkanJobsLineEdit">
<property name="text">
<string>1:2:2</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="realsrNcnnVulkanTtaCheckBox">
<property name="text">
<string>TTA</string>
</property>
</widget>
</item>
<item>
<spacer name="realsrNcnnVulkanVerticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>331</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="anime4kCppTab"> <widget class="QWidget" name="anime4kCppTab">
<attribute name="title"> <attribute name="title">
<string>Anime4K CPP</string> <string>Anime4K CPP</string>
@@ -1657,7 +1837,7 @@
<item> <item>
<widget class="QTabWidget" name="ffmpegSettingsTabWidget"> <widget class="QTabWidget" name="ffmpegSettingsTabWidget">
<property name="currentIndex"> <property name="currentIndex">
<number>0</number> <number>2</number>
</property> </property>
<widget class="QWidget" name="ffmpegGlobalOptionsTab"> <widget class="QWidget" name="ffmpegGlobalOptionsTab">
<attribute name="title"> <attribute name="title">
@@ -1879,7 +2059,7 @@
</sizepolicy> </sizepolicy>
</property> </property>
<property name="text"> <property name="text">
<string>yuv444p10le</string> <string>yuv420p</string>
</property> </property>
</widget> </widget>
</item> </item>
@@ -1906,6 +2086,64 @@
</item> </item>
</layout> </layout>
</item> </item>
<item>
<layout class="QHBoxLayout" name="ffmpegAssembleVideoOutputOptionsTuneHorizontalLayout">
<item>
<widget class="QLabel" name="ffmpegAssembleVideoOutputOptionsTuneLabel">
<property name="text">
<string>H.264/H.265 Tune (-tune)</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="ffmpegAssembleVideoOutputOptionsTuneComboBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;- film (x264 only): use for high quality movie content; lowers deblocking&lt;/p&gt;&lt;p&gt;- animation (x264 only): good for cartoons; uses higher deblocking and more reference frames&lt;/p&gt;&lt;p&gt;- grain: preserves the grain structure in old, grainy film material&lt;/p&gt;&lt;p&gt;- stillimage: (x264 only) good for slideshow-like content&lt;/p&gt;&lt;p&gt;- fastdecode: allows faster decoding by disabling certain filters&lt;/p&gt;&lt;p&gt;- zerolatency: good for fast encoding and low-latency streaming&lt;/p&gt;&lt;p&gt;- psnr: ignore this as it is only used for codec development&lt;/p&gt;&lt;p&gt;- ssim: ignore this as it is only used for codec development &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<item>
<property name="text">
<string>animation</string>
</property>
</item>
<item>
<property name="text">
<string>film</string>
</property>
</item>
<item>
<property name="text">
<string>grain</string>
</property>
</item>
<item>
<property name="text">
<string>stillimage</string>
</property>
</item>
<item>
<property name="text">
<string>fastdecode</string>
</property>
</item>
<item>
<property name="text">
<string>zerolatency</string>
</property>
</item>
<item>
<property name="text">
<string>psnr</string>
</property>
</item>
<item>
<property name="text">
<string>ssim</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item> <item>
<layout class="QHBoxLayout" name="ffmpegAssembleVideoOutputOptionsBitrateHorizontalLayout"> <layout class="QHBoxLayout" name="ffmpegAssembleVideoOutputOptionsBitrateHorizontalLayout">
<item> <item>
@@ -1933,7 +2171,7 @@
<item> <item>
<widget class="QCheckBox" name="ffmpegAssembleVideoOutputOptionsEnsureDivisibleCheckBox"> <widget class="QCheckBox" name="ffmpegAssembleVideoOutputOptionsEnsureDivisibleCheckBox">
<property name="text"> <property name="text">
<string>Ensure output width and height are divisible by 2</string> <string>Ensure output width and height are divisible by 2 (-vf: &quot;pad=ceil(iw/2)*2:ceil(ih/2)*2&quot;)</string>
</property> </property>
<property name="checked"> <property name="checked">
<bool>true</bool> <bool>true</bool>
@@ -2070,9 +2308,9 @@
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_32"> <layout class="QVBoxLayout" name="verticalLayout_32">
<item> <item>
<layout class="QHBoxLayout" name="ffmpegMigrateStreamsOutputOptionsOtherPixelFormatHorizontalLayout"> <layout class="QHBoxLayout" name="ffmpegMigrateStreamsOutputOptionsPixelFormatHorizontalLayout">
<item> <item>
<widget class="QLabel" name="ffmpegMigrateStreamsOutputOptionsOtherPixelFormatLabel"> <widget class="QLabel" name="ffmpegMigrateStreamsOutputOptionsPixelFormatLabel">
<property name="text"> <property name="text">
<string>Pixel Format (-pix_fmt)</string> <string>Pixel Format (-pix_fmt)</string>
</property> </property>
@@ -2084,9 +2322,30 @@
</layout> </layout>
</item> </item>
<item> <item>
<widget class="QCheckBox" name="ffmpegMigrateStreamsOutputOptionsCopyCodecCheckBox"> <layout class="QHBoxLayout" name="ffmpegMigrateStreamsOutputOptionsFrameInterpolationHorizontalLayout">
<item>
<widget class="QLabel" name="ffmpegMigrateStreamsOutputOptionsFrameInterpolationLabel">
<property name="text">
<string>Frame Interpolation (-filter &quot;minterpolate='fps=n'&quot;)</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="ffmpegMigrateStreamsOutputOptionsFrameInterpolationSpinBox">
<property name="maximum">
<number>9999</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="ffmpegMigrateStreamsOutputOptionsCopyStreamsCheckBox">
<property name="toolTip">
<string>Copy streams without re-encoding</string>
</property>
<property name="text"> <property name="text">
<string>Copy codec</string> <string>Copy streams (-c copy)</string>
</property> </property>
<property name="checked"> <property name="checked">
<bool>true</bool> <bool>true</bool>
@@ -2094,9 +2353,9 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QCheckBox" name="ffmpegMigrateStreamsOutputOptionsOtherCopyKnownMetadataTagsCheckBox"> <widget class="QCheckBox" name="ffmpegMigrateStreamsOutputOptionsCopyKnownMetadataTagsCheckBox">
<property name="text"> <property name="text">
<string>Copy known metadata tags</string> <string>Copy known metadata tags (-map_metadata 0)</string>
</property> </property>
<property name="checked"> <property name="checked">
<bool>true</bool> <bool>true</bool>
@@ -2104,9 +2363,9 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QCheckBox" name="ffmpegMigrateStreamsOutputOptionsOtherCopyArbitraryMetadataTagsCheckBox"> <widget class="QCheckBox" name="ffmpegMigrateStreamsOutputOptionsCopyArbitraryMetadataTagsCheckBox">
<property name="text"> <property name="text">
<string>Copy arbitrary metadata tags</string> <string>Copy arbitrary metadata tags (-movflags use_metadata_tags)</string>
</property> </property>
<property name="checked"> <property name="checked">
<bool>true</bool> <bool>true</bool>
@@ -2114,7 +2373,7 @@
</widget> </widget>
</item> </item>
<item> <item>
<spacer name="verticalSpacer"> <spacer name="ffmpegMigrateStreamsOutputOptionsOtherVerticalSpacer">
<property name="orientation"> <property name="orientation">
<enum>Qt::Vertical</enum> <enum>Qt::Vertical</enum>
</property> </property>
@@ -2511,7 +2770,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>671</width> <width>673</width>
<height>21</height> <height>21</height>
</rect> </rect>
</property> </property>
@@ -2525,6 +2784,7 @@
<property name="title"> <property name="title">
<string>Help</string> <string>Help</string>
</property> </property>
<addaction name="actionShortcuts"/>
<addaction name="actionAbout"/> <addaction name="actionAbout"/>
</widget> </widget>
<addaction name="menuFile"/> <addaction name="menuFile"/>
@@ -2541,6 +2801,11 @@
<string>About</string> <string>About</string>
</property> </property>
</action> </action>
<action name="actionShortcuts">
<property name="text">
<string>Shortcuts</string>
</property>
</action>
</widget> </widget>
<resources/> <resources/>
<connections/> <connections/>

View File

@@ -4,7 +4,7 @@
Name: Video2X Setup Script Name: Video2X Setup Script
Creator: K4YT3X Creator: K4YT3X
Date Created: November 28, 2018 Date Created: November 28, 2018
Last Modified: May 16, 2020 Last Modified: May 29, 2020
Editor: BrianPetkovsek Editor: BrianPetkovsek
Editor: SAT3LL Editor: SAT3LL
@@ -17,8 +17,9 @@ Installation Details:
- waifu2x-caffe: %LOCALAPPDATA%\\video2x\\waifu2x-caffe - waifu2x-caffe: %LOCALAPPDATA%\\video2x\\waifu2x-caffe
- waifu2x-cpp-converter: %LOCALAPPDATA%\\video2x\\waifu2x-converter-cpp - waifu2x-cpp-converter: %LOCALAPPDATA%\\video2x\\waifu2x-converter-cpp
- waifu2x_ncnn_vulkan: %LOCALAPPDATA%\\video2x\\waifu2x-ncnn-vulkan - waifu2x_ncnn_vulkan: %LOCALAPPDATA%\\video2x\\waifu2x-ncnn-vulkan
- anime4kcpp: %LOCALAPPDATA%\\video2x\\anime4kcpp
- srmd_ncnn_vulkan: %LOCALAPPDATA%\\video2x\\srmd-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 # built-in imports
@@ -43,7 +44,7 @@ import zipfile
# Therefore, they will be installed during the Python dependency # Therefore, they will be installed during the Python dependency
# installation step and imported later in the script. # installation step and imported later in the script.
SETUP_VERSION = '2.1.0' SETUP_VERSION = '2.2.0'
# global static variables # global static variables
LOCALAPPDATA = pathlib.Path(os.getenv('localappdata')) LOCALAPPDATA = pathlib.Path(os.getenv('localappdata'))
@@ -54,8 +55,9 @@ DRIVER_OPTIONS = ['all',
'waifu2x_caffe', 'waifu2x_caffe',
'waifu2x_converter_cpp', 'waifu2x_converter_cpp',
'waifu2x_ncnn_vulkan', 'waifu2x_ncnn_vulkan',
'anime4kcpp', 'srmd_ncnn_vulkan',
'srmd_ncnn_vulkan'] # 'realsr_ncnn_vulkan',
'anime4kcpp']
def parse_arguments(): def parse_arguments():
@@ -103,7 +105,7 @@ class Video2xSetup:
def _install_python_requirements(self): def _install_python_requirements(self):
""" Read requirements.txt and return its content """ Read requirements.txt and return its content
""" """
pip_install('requirements.txt') pip_install('requirements-windows.txt')
def _cleanup(self): def _cleanup(self):
""" Cleanup all the temp files downloaded """ Cleanup all the temp files downloaded
@@ -209,6 +211,32 @@ class Video2xSetup:
# rename the newly extracted directory # rename the newly extracted directory
(LOCALAPPDATA / 'video2x' / zipf.namelist()[0]).rename(waifu2x_ncnn_vulkan_directory) (LOCALAPPDATA / 'video2x' / zipf.namelist()[0]).rename(waifu2x_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*\.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): def _install_anime4kcpp(self):
""" Install Anime4KCPP """ Install Anime4KCPP
""" """

0
src/wrappers/anime4kcpp.py Normal file → Executable file
View File

0
src/wrappers/ffmpeg.py Normal file → Executable file
View File

0
src/wrappers/gifski.py Normal file → Executable file
View File

View File

@@ -0,0 +1,102 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Name: RealSR NCNN Vulkan Driver
Creator: K4YT3X
Date Created: May 26, 2020
Last Modified: May 26, 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 shlex
import subprocess
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):
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, choices=[4], 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')
return parser.parse_args(arguments)
def load_configurations(self, upscaler):
self.driver_settings['s'] = int(upscaler.scale_ratio)
self.driver_settings['j'] = '{}:{}:{}'.format(upscaler.processes, upscaler.processes, upscaler.processes)
def upscale(self, input_directory, output_directory):
"""This is the core function for RealSR NCNN Vulkan class
Arguments:
input_directory {string} -- source directory path
output_directory {string} -- output directory path
ratio {int} -- output video ratio
"""
# overwrite config file settings
self.driver_settings['i'] = input_directory
self.driver_settings['o'] = output_directory
# by default, 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: {shlex.join(execute)}')
self.print_lock.release()
return subprocess.Popen(execute)

0
src/wrappers/srmd_ncnn_vulkan.py Normal file → Executable file
View File

0
src/wrappers/waifu2x_caffe.py Normal file → Executable file
View File

0
src/wrappers/waifu2x_converter_cpp.py Normal file → Executable file
View File

0
src/wrappers/waifu2x_ncnn_vulkan.py Normal file → Executable file
View File