mirror of
				https://github.com/k4yt3x/video2x.git
				synced 2025-10-31 04:40:59 +01:00 
			
		
		
		
	simplified the encoder
This commit is contained in:
		
							parent
							
								
									f3eaa47ec6
								
							
						
					
					
						commit
						0a052a3a72
					
				| @ -19,20 +19,16 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. | |||||||
| Name: Video Encoder | Name: Video Encoder | ||||||
| Author: K4YT3X | Author: K4YT3X | ||||||
| Date Created: June 17, 2021 | Date Created: June 17, 2021 | ||||||
| Last Modified: March 20, 2022 | Last Modified: April 9, 2022 | ||||||
| """ | """ | ||||||
| 
 | 
 | ||||||
| import os | import os | ||||||
| import pathlib | import pathlib | ||||||
| import signal | import signal | ||||||
| import subprocess | import subprocess | ||||||
| import threading |  | ||||||
| import time |  | ||||||
| from multiprocessing.managers import ListProxy |  | ||||||
| from multiprocessing.sharedctypes import Synchronized |  | ||||||
| 
 | 
 | ||||||
| import ffmpeg | import ffmpeg | ||||||
| from loguru import logger | from PIL import Image | ||||||
| 
 | 
 | ||||||
| from .pipe_printer import PipePrinter | from .pipe_printer import PipePrinter | ||||||
| 
 | 
 | ||||||
| @ -48,7 +44,7 @@ LOGURU_FFMPEG_LOGLEVELS = { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class VideoEncoder(threading.Thread): | class VideoEncoder: | ||||||
|     def __init__( |     def __init__( | ||||||
|         self, |         self, | ||||||
|         input_path: pathlib.Path, |         input_path: pathlib.Path, | ||||||
| @ -56,29 +52,14 @@ class VideoEncoder(threading.Thread): | |||||||
|         output_path: pathlib.Path, |         output_path: pathlib.Path, | ||||||
|         output_width: int, |         output_width: int, | ||||||
|         output_height: int, |         output_height: int, | ||||||
|         total_frames: int, |  | ||||||
|         processed_frames: ListProxy, |  | ||||||
|         processed: Synchronized, |  | ||||||
|         pause: Synchronized, |  | ||||||
|         copy_audio: bool = True, |         copy_audio: bool = True, | ||||||
|         copy_subtitle: bool = True, |         copy_subtitle: bool = True, | ||||||
|         copy_data: bool = False, |         copy_data: bool = False, | ||||||
|         copy_attachments: bool = False, |         copy_attachments: bool = False, | ||||||
|     ) -> None: |     ) -> None: | ||||||
|         threading.Thread.__init__(self) |  | ||||||
|         self.running = False |  | ||||||
|         self.input_path = input_path |  | ||||||
|         self.output_path = output_path |  | ||||||
|         self.total_frames = total_frames |  | ||||||
|         self.processed_frames = processed_frames |  | ||||||
|         self.processed = processed |  | ||||||
|         self.pause = pause |  | ||||||
| 
 |  | ||||||
|         # stores exceptions if the thread exits with errors |  | ||||||
|         self.exception = None |  | ||||||
| 
 | 
 | ||||||
|         # create FFmpeg input for the original input video |         # create FFmpeg input for the original input video | ||||||
|         self.original = ffmpeg.input(input_path) |         original = ffmpeg.input(input_path) | ||||||
| 
 | 
 | ||||||
|         # define frames as input |         # define frames as input | ||||||
|         frames = ffmpeg.input( |         frames = ffmpeg.input( | ||||||
| @ -93,11 +74,11 @@ class VideoEncoder(threading.Thread): | |||||||
|         # copy additional streams from original file |         # copy additional streams from original file | ||||||
|         # https://ffmpeg.org/ffmpeg.html#Stream-specifiers-1 |         # https://ffmpeg.org/ffmpeg.html#Stream-specifiers-1 | ||||||
|         additional_streams = [ |         additional_streams = [ | ||||||
|             # self.original["1:v?"], |             # original["1:v?"], | ||||||
|             self.original["a?"] if copy_audio is True else None, |             original["a?"] if copy_audio is True else None, | ||||||
|             self.original["s?"] if copy_subtitle is True else None, |             original["s?"] if copy_subtitle is True else None, | ||||||
|             self.original["d?"] if copy_data is True else None, |             original["d?"] if copy_data is True else None, | ||||||
|             self.original["t?"] if copy_attachments is True else None, |             original["t?"] if copy_attachments is True else None, | ||||||
|         ] |         ] | ||||||
| 
 | 
 | ||||||
|         # run FFmpeg and produce final output |         # run FFmpeg and produce final output | ||||||
| @ -106,7 +87,7 @@ class VideoEncoder(threading.Thread): | |||||||
|                 ffmpeg.output( |                 ffmpeg.output( | ||||||
|                     frames, |                     frames, | ||||||
|                     *[s for s in additional_streams if s is not None], |                     *[s for s in additional_streams if s is not None], | ||||||
|                     str(self.output_path), |                     str(output_path), | ||||||
|                     vcodec="libx264", |                     vcodec="libx264", | ||||||
|                     scodec="copy", |                     scodec="copy", | ||||||
|                     vsync="cfr", |                     vsync="cfr", | ||||||
| @ -138,41 +119,19 @@ class VideoEncoder(threading.Thread): | |||||||
|         self.pipe_printer = PipePrinter(self.encoder.stderr) |         self.pipe_printer = PipePrinter(self.encoder.stderr) | ||||||
|         self.pipe_printer.start() |         self.pipe_printer.start() | ||||||
| 
 | 
 | ||||||
|     def run(self) -> None: |     def write(self, frame: Image.Image) -> None: | ||||||
|         self.running = True |         """ | ||||||
|         frame_index = 0 |         write a frame into FFmpeg encoder's STDIN | ||||||
|         while self.running and frame_index < self.total_frames: |  | ||||||
| 
 | 
 | ||||||
|             # pause if pause flag is set |         :param frame Image.Image: the Image object to use for writing | ||||||
|             if self.pause.value is True: |         """ | ||||||
|                 time.sleep(0.1) |         self.encoder.stdin.write(frame.tobytes()) | ||||||
|                 continue |  | ||||||
| 
 |  | ||||||
|             try: |  | ||||||
|                 image = self.processed_frames[frame_index] |  | ||||||
|                 if image is None: |  | ||||||
|                     time.sleep(0.1) |  | ||||||
|                     continue |  | ||||||
| 
 |  | ||||||
|                 # send the image to FFmpeg for encoding |  | ||||||
|                 self.encoder.stdin.write(image.tobytes()) |  | ||||||
| 
 |  | ||||||
|                 # remove the image from memory |  | ||||||
|                 self.processed_frames[frame_index] = None |  | ||||||
| 
 |  | ||||||
|                 with self.processed.get_lock(): |  | ||||||
|                     self.processed.value += 1 |  | ||||||
| 
 |  | ||||||
|                 frame_index += 1 |  | ||||||
| 
 |  | ||||||
|             # send exceptions into the client connection pipe |  | ||||||
|             except Exception as error: |  | ||||||
|                 self.exception = error |  | ||||||
|                 logger.exception(error) |  | ||||||
|                 break |  | ||||||
|         else: |  | ||||||
|             logger.debug("Encoding queue depleted") |  | ||||||
| 
 | 
 | ||||||
|  |     def join(self) -> None: | ||||||
|  |         """ | ||||||
|  |         signal the encoder that all frames have been sent and the FFmpeg | ||||||
|  |         should be instructed to wrap-up the processing | ||||||
|  |         """ | ||||||
|         # flush the remaining data in STDIN and STDERR |         # flush the remaining data in STDIN and STDERR | ||||||
|         self.encoder.stdin.flush() |         self.encoder.stdin.flush() | ||||||
|         self.encoder.stderr.flush() |         self.encoder.stderr.flush() | ||||||
| @ -191,9 +150,3 @@ class VideoEncoder(threading.Thread): | |||||||
|         # wait for PIPE printer to exit |         # wait for PIPE printer to exit | ||||||
|         self.pipe_printer.stop() |         self.pipe_printer.stop() | ||||||
|         self.pipe_printer.join() |         self.pipe_printer.join() | ||||||
| 
 |  | ||||||
|         logger.info("Encoder thread exiting") |  | ||||||
|         return super().run() |  | ||||||
| 
 |  | ||||||
|     def stop(self) -> None: |  | ||||||
|         self.running = False |  | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user