mirror of
https://github.com/k4yt3x/video2x.git
synced 2026-02-10 23:21:09 +08:00
Compare commits
13 Commits
5.0.0-beta
...
5.0.0-beta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f17d75539c | ||
|
|
82512ef10c | ||
|
|
ad479e53b8 | ||
|
|
a356bfeaff | ||
|
|
dee8e23485 | ||
|
|
1fa0821057 | ||
|
|
b5ecffba81 | ||
|
|
672c9b8652 | ||
|
|
9f73e75f17 | ||
|
|
ef1a8f3e41 | ||
|
|
04f409ef80 | ||
|
|
51c8693dce | ||
|
|
bb572e2468 |
61
.github/workflows/release.yml
vendored
Normal file
61
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
name: Release
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
tags:
|
||||
- "*"
|
||||
|
||||
jobs:
|
||||
setup:
|
||||
name: Setup
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
tag: ${{ steps.get_tag.outputs.tag }}
|
||||
steps:
|
||||
- name: Get tag
|
||||
id: get_tag
|
||||
run: echo ::set-output name=tag::${GITHUB_REF/refs\/tags\//}
|
||||
|
||||
create-release:
|
||||
name: Create release
|
||||
needs:
|
||||
- setup
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
steps:
|
||||
- name: Create release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ needs.setup.outputs.tag }}
|
||||
release_name: Video2X ${{ needs.setup.outputs.tag }}
|
||||
draft: true
|
||||
prerelease: false
|
||||
|
||||
container:
|
||||
name: Build and upload container
|
||||
needs:
|
||||
- setup
|
||||
- create-release
|
||||
strategy:
|
||||
matrix:
|
||||
version:
|
||||
- slim-alpine
|
||||
- cuda
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
- uses: mr-smithers-excellent/docker-build-push@v5
|
||||
name: Build & push Docker image
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ secrets.GHCR_USER }}
|
||||
password: ${{ secrets.GHCR_TOKEN }}
|
||||
dockerfile: Dockerfile.${{ matrix.version }}
|
||||
image: video2x
|
||||
tags: latest, ${{ needs.setup.outputs.tag }}-${{ matrix.version }}
|
||||
@@ -18,7 +18,7 @@ RUN apk add --no-cache \
|
||||
|
||||
# stage 2: install wheels into final image
|
||||
FROM docker.io/library/python:3.10.2-alpine3.15
|
||||
LABEL maintainer="K4YT3X <i@k4yt3x.com>"
|
||||
LABEL maintainer="K4YT3X <i@k4yt3x.com>" \
|
||||
org.opencontainers.image.source="https://github.com/k4yt3x/video2x" \
|
||||
org.opencontainers.image.description="A lossless video/GIF/image upscaler"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<img src="https://img.shields.io/badge/dynamic/json?color=%23e85b46&label=Patreon&query=data.attributes.patron_count&suffix=%20patrons&url=https%3A%2F%2Fwww.patreon.com%2Fapi%2Fcampaigns%2F4507807&style=flat-square"/>
|
||||
</p>
|
||||
|
||||
### Official [Telegram Discussion Group](https://t.me/video2x)
|
||||
## [💬 Telegram Discussion Group](https://t.me/video2x)
|
||||
|
||||
Join our Telegram discussion group to ask any questions you have about Video2X, chat directly with the developers, or discuss about upscaling technologies and the future of Video2X in general.
|
||||
|
||||
|
||||
@@ -11,8 +11,9 @@ sudo podman run -it --rm \
|
||||
-m 15g \
|
||||
--cpus 0.9 \
|
||||
-v $HOME/projects/media2x/video2x:/video2x \
|
||||
-e PYTHONPATH="/video2x" \
|
||||
-e PYTHONPATH=/video2x \
|
||||
-e PYTHONDONTWRITEBYTECODE=1 \
|
||||
--entrypoint=/bin/bash \
|
||||
ghcr.io/k4yt3x/video2x:5.0.0-beta1-cuda
|
||||
ghcr.io/k4yt3x/video2x:5.0.0-beta4-cuda
|
||||
|
||||
# alias upscale='python3 -m video2x -i /host/input-large.mp4 -o /host/output-large.mp4 -p5 upscale -h 1440 -d waifu2x -n3'
|
||||
# alias upscale='python3 -m video2x -i /host/input-large.mp4 -o /host/output-large.mp4 -p3 upscale -h 1440 -d waifu2x -n3'
|
||||
|
||||
@@ -10,9 +10,10 @@ sudo podman run -it --rm \
|
||||
-m 15g \
|
||||
--cpus 0.9 \
|
||||
-v $HOME/projects/media2x/video2x:/video2x \
|
||||
-e PYTHONPATH="/video2x" \
|
||||
ghcr.io/k4yt3x/video2x:5.0.0-beta3-cuda \
|
||||
-e PYTHONPATH=/video2x \
|
||||
-e PYTHONDONTWRITEBYTECODE=1 \
|
||||
ghcr.io/k4yt3x/video2x:5.0.0-beta4-cuda \
|
||||
-i data/input.mp4 -o data/output.mp4 \
|
||||
-p5 \
|
||||
-p3 \
|
||||
upscale \
|
||||
-h 1440 -a waifu2x -n3
|
||||
|
||||
@@ -19,12 +19,12 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
Name: Package Init
|
||||
Author: K4YT3X
|
||||
Date Created: July 3, 2021
|
||||
Last Modified: February 11, 2022
|
||||
Last Modified: February 16, 2022
|
||||
"""
|
||||
|
||||
# version assignment has to precede imports to
|
||||
# prevent setup.cfg from producing import errors
|
||||
__version__ = "5.0.0-beta3"
|
||||
__version__ = "5.0.0-beta4"
|
||||
|
||||
# local imports
|
||||
from .video2x import Video2X
|
||||
|
||||
@@ -19,7 +19,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
Name: Video Decoder
|
||||
Author: K4YT3X
|
||||
Date Created: June 17, 2021
|
||||
Last Modified: February 12, 2022
|
||||
Last Modified: February 16, 2022
|
||||
"""
|
||||
|
||||
# built-in imports
|
||||
@@ -59,7 +59,7 @@ class VideoDecoder(threading.Thread):
|
||||
processing_queue: queue.Queue,
|
||||
processing_settings: tuple,
|
||||
ignore_max_image_pixels=True,
|
||||
):
|
||||
) -> None:
|
||||
threading.Thread.__init__(self)
|
||||
self.running = False
|
||||
self.input_path = input_path
|
||||
@@ -91,7 +91,7 @@ class VideoDecoder(threading.Thread):
|
||||
# stderr=subprocess.DEVNULL,
|
||||
)
|
||||
|
||||
def run(self):
|
||||
def run(self) -> None:
|
||||
self.running = True
|
||||
|
||||
# the index of the frame
|
||||
@@ -164,5 +164,5 @@ class VideoDecoder(threading.Thread):
|
||||
self.running = False
|
||||
return super().run()
|
||||
|
||||
def stop(self):
|
||||
def stop(self) -> None:
|
||||
self.running = False
|
||||
|
||||
@@ -19,7 +19,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
Name: Video Encoder
|
||||
Author: K4YT3X
|
||||
Date Created: June 17, 2021
|
||||
Last Modified: June 30, 2021
|
||||
Last Modified: February 16, 2022
|
||||
"""
|
||||
|
||||
# built-in imports
|
||||
@@ -61,7 +61,11 @@ class VideoEncoder(threading.Thread):
|
||||
total_frames: int,
|
||||
processed_frames: multiprocessing.managers.ListProxy,
|
||||
processed: multiprocessing.sharedctypes.Synchronized,
|
||||
):
|
||||
copy_audio: bool = True,
|
||||
copy_subtitle: bool = True,
|
||||
copy_data: bool = False,
|
||||
copy_attachments: bool = False,
|
||||
) -> None:
|
||||
threading.Thread.__init__(self)
|
||||
self.running = False
|
||||
self.input_path = input_path
|
||||
@@ -82,31 +86,31 @@ class VideoEncoder(threading.Thread):
|
||||
r=frame_rate,
|
||||
)
|
||||
|
||||
# map additional streams from original file
|
||||
"""
|
||||
# copy additional streams from original file
|
||||
# https://ffmpeg.org/ffmpeg.html#Stream-specifiers-1
|
||||
additional_streams = [
|
||||
# self.original["v?"],
|
||||
self.original["a?"],
|
||||
self.original["s?"],
|
||||
self.original["d?"],
|
||||
self.original["t?"],
|
||||
# self.original["1:v?"],
|
||||
self.original["a?"] if copy_audio is True else None,
|
||||
self.original["s?"] if copy_subtitle is True else None,
|
||||
self.original["d?"] if copy_data is True else None,
|
||||
self.original["t?"] if copy_attachments is True else None,
|
||||
]
|
||||
"""
|
||||
|
||||
# run FFmpeg and produce final output
|
||||
self.encoder = subprocess.Popen(
|
||||
ffmpeg.compile(
|
||||
ffmpeg.output(
|
||||
frames,
|
||||
*[s for s in additional_streams if s is not None],
|
||||
str(self.output_path),
|
||||
pix_fmt="yuv420p",
|
||||
vcodec="libx264",
|
||||
acodec="copy",
|
||||
# acodec="copy",
|
||||
r=frame_rate,
|
||||
crf=17,
|
||||
vsync="1",
|
||||
# map_metadata=1,
|
||||
# metadata="comment=Upscaled with Video2X",
|
||||
map_metadata=1,
|
||||
metadata="comment=Processed with Video2X",
|
||||
)
|
||||
.global_args("-hide_banner")
|
||||
.global_args("-nostats")
|
||||
@@ -123,7 +127,7 @@ class VideoEncoder(threading.Thread):
|
||||
# stderr=subprocess.DEVNULL,
|
||||
)
|
||||
|
||||
def run(self):
|
||||
def run(self) -> None:
|
||||
self.running = True
|
||||
frame_index = 0
|
||||
while self.running and frame_index < self.total_frames:
|
||||
@@ -165,5 +169,5 @@ class VideoEncoder(threading.Thread):
|
||||
self.running = False
|
||||
return super().run()
|
||||
|
||||
def stop(self):
|
||||
def stop(self) -> None:
|
||||
self.running = False
|
||||
|
||||
@@ -19,7 +19,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
Name: Interpolator
|
||||
Author: K4YT3X
|
||||
Date Created: May 27, 2021
|
||||
Last Modified: February 2, 2022
|
||||
Last Modified: February 16, 2022
|
||||
"""
|
||||
|
||||
# local imports
|
||||
@@ -46,7 +46,7 @@ class Interpolator(multiprocessing.Process):
|
||||
self,
|
||||
processing_queue: multiprocessing.Queue,
|
||||
processed_frames: multiprocessing.managers.ListProxy,
|
||||
):
|
||||
) -> None:
|
||||
multiprocessing.Process.__init__(self)
|
||||
self.running = False
|
||||
self.processing_queue = processing_queue
|
||||
@@ -54,7 +54,7 @@ class Interpolator(multiprocessing.Process):
|
||||
|
||||
signal.signal(signal.SIGTERM, self._stop)
|
||||
|
||||
def run(self):
|
||||
def run(self) -> None:
|
||||
self.running = True
|
||||
logger.info(f"Interpolator process {self.name} initiating")
|
||||
processor_objects = {}
|
||||
@@ -116,5 +116,5 @@ class Interpolator(multiprocessing.Process):
|
||||
self.running = False
|
||||
return super().run()
|
||||
|
||||
def _stop(self, _signal_number, _frame):
|
||||
def _stop(self, _signal_number, _frame) -> None:
|
||||
self.running = False
|
||||
|
||||
@@ -19,7 +19,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
Name: Upscaler
|
||||
Author: K4YT3X
|
||||
Date Created: May 27, 2021
|
||||
Last Modified: August 17, 2021
|
||||
Last Modified: February 16, 2022
|
||||
"""
|
||||
|
||||
# local imports
|
||||
@@ -56,7 +56,7 @@ class Upscaler(multiprocessing.Process):
|
||||
self,
|
||||
processing_queue: multiprocessing.Queue,
|
||||
processed_frames: multiprocessing.managers.ListProxy,
|
||||
):
|
||||
) -> None:
|
||||
multiprocessing.Process.__init__(self)
|
||||
self.running = False
|
||||
self.processing_queue = processing_queue
|
||||
@@ -64,7 +64,7 @@ class Upscaler(multiprocessing.Process):
|
||||
|
||||
signal.signal(signal.SIGTERM, self._stop)
|
||||
|
||||
def run(self):
|
||||
def run(self) -> None:
|
||||
self.running = True
|
||||
logger.opt(colors=True).info(
|
||||
f"Upscaler process <blue>{self.name}</blue> initiating"
|
||||
@@ -193,5 +193,5 @@ class Upscaler(multiprocessing.Process):
|
||||
self.running = False
|
||||
return super().run()
|
||||
|
||||
def _stop(self, _signal_number, _frame):
|
||||
def _stop(self, _signal_number, _frame) -> None:
|
||||
self.running = False
|
||||
|
||||
@@ -26,8 +26,8 @@ __ __ _ _ ___ __ __
|
||||
|
||||
Name: Video2X
|
||||
Creator: K4YT3X
|
||||
Date Created: Feb 24, 2018
|
||||
Last Modified: February 12, 2022
|
||||
Date Created: February 24, 2018
|
||||
Last Modified: February 16, 2022
|
||||
|
||||
Editor: BrianPetkovsek
|
||||
Last Modified: June 17, 2019
|
||||
@@ -73,11 +73,11 @@ import cv2
|
||||
import ffmpeg
|
||||
|
||||
|
||||
LEGAL_INFO = """Video2X {}
|
||||
Author: K4YT3X
|
||||
License: GNU GPL v3
|
||||
Github Page: https://github.com/k4yt3x/video2x
|
||||
Contact: k4yt3x@k4yt3x.com""".format(
|
||||
LEGAL_INFO = """Video2X\t\t{}
|
||||
Author:\t\tK4YT3X
|
||||
License:\tGNU AGPL v3
|
||||
Github Page:\thttps://github.com/k4yt3x/video2x
|
||||
Contact:\ti@k4yt3x.com""".format(
|
||||
__version__
|
||||
)
|
||||
|
||||
@@ -122,10 +122,10 @@ class Video2X:
|
||||
- interpolate: perform motion interpolation on a file
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.version = "5.0.0"
|
||||
def __init__(self) -> None:
|
||||
self.version = __version__
|
||||
|
||||
def _get_video_info(self, path: pathlib.Path):
|
||||
def _get_video_info(self, path: pathlib.Path) -> tuple:
|
||||
"""
|
||||
get video file information with FFmpeg
|
||||
|
||||
@@ -167,7 +167,7 @@ class Video2X:
|
||||
mode: str,
|
||||
processes: int,
|
||||
processing_settings: tuple,
|
||||
):
|
||||
) -> None:
|
||||
|
||||
# record original STDOUT and STDERR for restoration
|
||||
original_stdout = sys.stdout
|
||||
@@ -399,7 +399,7 @@ def parse_arguments() -> argparse.Namespace:
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
)
|
||||
parser.add_argument(
|
||||
"-v", "--version", help="show version information and exit", action="store_true"
|
||||
"--version", help="show version information and exit", action="store_true"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-i",
|
||||
@@ -430,7 +430,12 @@ def parse_arguments() -> argparse.Namespace:
|
||||
help="action to perform", dest="action", required=True
|
||||
)
|
||||
|
||||
upscale = action.add_parser("upscale", help="upscale a file", add_help=False)
|
||||
upscale = action.add_parser(
|
||||
"upscale",
|
||||
help="upscale a file",
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
add_help=False,
|
||||
)
|
||||
upscale.add_argument(
|
||||
"--help", action="help", help="show this help message and exit"
|
||||
)
|
||||
@@ -448,13 +453,19 @@ def parse_arguments() -> argparse.Namespace:
|
||||
"-t",
|
||||
"--threshold",
|
||||
type=float,
|
||||
help="skip if the % difference between two adjacent frames is below this value; set to 0 to process all frames",
|
||||
help=(
|
||||
"skip if the percent difference between two adjacent frames is below this"
|
||||
" value; set to 0 to process all frames"
|
||||
),
|
||||
default=0,
|
||||
)
|
||||
|
||||
# interpolator arguments
|
||||
interpolate = action.add_parser(
|
||||
"interpolate", help="interpolate frames for file", add_help=False
|
||||
"interpolate",
|
||||
help="interpolate frames for file",
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
add_help=False,
|
||||
)
|
||||
interpolate.add_argument(
|
||||
"--help", action="help", help="show this help message and exit"
|
||||
@@ -470,20 +481,27 @@ def parse_arguments() -> argparse.Namespace:
|
||||
"-t",
|
||||
"--threshold",
|
||||
type=float,
|
||||
help="skip if the % difference between two adjacent frames exceeds this value; set to 100 to interpolate all frames",
|
||||
help=(
|
||||
"skip if the percent difference between two adjacent frames exceeds this"
|
||||
" value; set to 100 to interpolate all frames"
|
||||
),
|
||||
default=10,
|
||||
)
|
||||
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main():
|
||||
def main() -> None:
|
||||
"""
|
||||
command line direct invocation
|
||||
program entry point
|
||||
"""
|
||||
|
||||
try:
|
||||
# display version and lawful informaition
|
||||
if "--version" in sys.argv:
|
||||
print(LEGAL_INFO)
|
||||
sys.exit(0)
|
||||
|
||||
# parse command line arguments
|
||||
args = parse_arguments()
|
||||
@@ -498,11 +516,6 @@ def main():
|
||||
# add new sink with custom handler
|
||||
logger.add(sys.stderr, colorize=True, format=LOGURU_FORMAT)
|
||||
|
||||
# display version and lawful informaition
|
||||
if args.version:
|
||||
print(LEGAL_INFO)
|
||||
sys.exit(0)
|
||||
|
||||
# print package version and copyright notice
|
||||
logger.opt(colors=True).info(f"<magenta>Video2X {__version__}</magenta>")
|
||||
logger.opt(colors=True).info(
|
||||
@@ -534,7 +547,7 @@ def main():
|
||||
)
|
||||
|
||||
# don't print the traceback for manual terminations
|
||||
except (SystemExit, KeyboardInterrupt) as e:
|
||||
except KeyboardInterrupt as e:
|
||||
raise SystemExit(e)
|
||||
|
||||
except Exception as e:
|
||||
|
||||
Reference in New Issue
Block a user