From d82800e1a0138474f34b3092fa9da3a20927d76e Mon Sep 17 00:00:00 2001 From: GeoHaber <11169518+GeoHaber@users.noreply.github.com> Date: Mon, 26 Aug 2024 12:40:53 -0400 Subject: [PATCH] Bus fixes some minor bug fixes --- FFMpeg.py | 97 ++++++++++++++++++++++++++++++++++----------------- My_Utils.py | 34 +++++++++++++++--- Trans_code.py | 13 ++++--- 3 files changed, 101 insertions(+), 43 deletions(-) diff --git a/FFMpeg.py b/FFMpeg.py index e71d265..6a929aa 100644 --- a/FFMpeg.py +++ b/FFMpeg.py @@ -126,7 +126,6 @@ def ffmpeg_run(input_file: str, ff_com: list, skip_it: bool, execu: str = "ffmpe "-movflags", "+faststart", # Place moov atom at the beginning for fast start "-fflags", "+fastseek", # Enable fast seeking "-fflags", "+genpts", # Generate presentation timestamps -# "-level:v", "4.1", # Set the level for better compatibility "-keyint_min", "30", # Minimum interval between keyframes "-g", "60", # Set the GOP (Group of Pictures) size "-y", out_file, @@ -209,9 +208,8 @@ def run_ffm(args, de_bug=False): return False except Exception as e: - msj += f" Exception: {e}" + print(f"{msj} Exception: {e}\n{args}\n") return False - print( msj ) return True ##==============------------------- End -------------------==============## @@ -400,29 +398,66 @@ def add_subtl_from_file(input_file: str, de_bug: bool) -> tuple[list, bool]: if de_bug: print(" |No External Sub File |") return [], True - ##>>============-------------------< End >------------------==============<<## - # Define a helper function to select the appropriate encoder and options -def get_encoder_options(codec_name, src_pix_fmt, use_hw_accel): - hw_pix_fmt = "p010le" if src_pix_fmt.endswith("10le") else "nv12" +def get_encoder_options(codec_name, src_pix_fmt, use_hw_accel=False): + msj = sys._getframe().f_code.co_name + # Determine if the source is 10-bit + is_10bit = src_pix_fmt.endswith("10le") + # Set base values + target_quality='high' + quality_presets = { + 'low': {'bitrate': 2000, 'quality': 26}, + 'medium': {'bitrate': 3000, 'quality': 24}, + 'high': {'bitrate': 4000, 'quality': 22}, + 'higher': {'bitrate': 5000, 'quality': 18}, + } + preset = quality_presets[target_quality] + base_target_bitrate = preset['bitrate'] + global_quality = preset['quality'] + # Adjust for 10-bit content + if is_10bit: + target_bitrate = str(int(base_target_bitrate * 1.25)) + 'k' + else: + target_bitrate = str(base_target_bitrate) + 'k' + # Calculate max_bitrate and bufsize + max_bitrate = str(int(int(target_bitrate.rstrip('k')) * 1.5)) + 'k' + bufsize = str(int(int(max_bitrate.rstrip('k')) * 2)) + 'k' if use_hw_accel: - # Use hevc_qsv (HEVC) encoder with QSV options - return ['hevc_qsv', '-load_plugin', 'hevc_hw', - '-init_hw_device', 'qsv=qsv:MFX_IMPL_hw_any', - '-filter_hw_device', 'qsv', - '-pix_fmt', hw_pix_fmt, - '-look_ahead', '1', # Enable lookahead - '-look_ahead_depth', '50', # Set lookahead depth to ? 40 frames - '-global_quality', '22', # Use global_quality instead of CRF for QSV - '-preset', 'slower'] # Encoder preset + print(f" {msj} HW accelerated") + hw_pix_fmt = "p010le" if is_10bit else "nv12" + return [ + 'hevc_qsv', + '-load_plugin', 'hevc_hw', + '-init_hw_device', 'qsv=qsv:MFX_IMPL_hw_any', + '-filter_hw_device', 'qsv', + '-pix_fmt', hw_pix_fmt, + '-b:v', target_bitrate, + '-maxrate', max_bitrate, + '-bufsize', bufsize, + '-look_ahead', '1', + '-look_ahead_depth', '90', + '-global_quality', str(round(global_quality)), + '-rc:v', 'vbr_la', # Use variable bitrate with lookahead + '-preset', 'slow', + ] else: - # Use libx265 (HEVC) or libx264 (H.264) encoder with software options and 10Bit - return ['libx265', '-pix_fmt', 'yuv420p10le', '-crf', '22', '-preset', 'slow'] -# return ['libx265', '-pix_fmt', src_pix_fmt, '-crf', '22', '-preset', 'slow'] + print(f" {msj} SW") + sw_pix_fmt = "yuv420p10le" if is_10bit else "yuv420p" + return [ + 'libx265', + '-x265-params', 'bframes=8:psy-rd=1:aq-mode=3:aq-strength=0.8:deblock=1,1', + '-pix_fmt', sw_pix_fmt, + '-crf', str(round(global_quality)), + '-b:v', target_bitrate, + '-maxrate', max_bitrate, + '-bufsize', bufsize, + '-preset', 'slow', + ] ##>>============-------------------< End >------------------==============<<## + @perf_monitor def parse_video(strm_in, de_bug=False, use_hw_accel=True ): ''' Parse and extract data from video streams ''' @@ -471,15 +506,11 @@ def parse_video(strm_in, de_bug=False, use_hw_accel=True ): # XXX: Estimate Average bits_per_pixel glb_totfrms = round(frm_rate * glb_vidolen) - avbpp = round (100000 * _vi_btrt / (glb_totfrms * vid_width * vid_heigh) +1) - - max_vid_btrt = 4700000 + max_vid_btrt = 5000000 msj = " 8" - if pix_fmt.endswith("10le") : msj = "10" - avbpp *= 1.25 max_vid_btrt *= 1.25 mins, secs = divmod(glb_vidolen, 60) @@ -497,13 +528,13 @@ def parse_video(strm_in, de_bug=False, use_hw_accel=True ): ff_vid = ['-map', f'0:v:{indx}', f'-c:v:{indx}'] # Determine if codec copy or conversion is needed, and update ff_vid accordingly if codec_name == 'hevc': - if avbpp < 80 and _vi_btrt < max_vid_btrt : + if _vi_btrt < max_vid_btrt : extra += ' => Copy' ff_vid.extend(['copy']) skip_it = True else: extra += f' Reduce BitRate: {hm_sz(max_vid_btrt):>6} ' - encoder_options = get_encoder_options(codec_name, this_vid['pix_fmt'], use_hw_accel) + encoder_options = get_encoder_options(codec_name, this_vid['pix_fmt'], use_hw_accel ) ff_vid.extend(encoder_options) else: extra += ' => Convert to Hevc' @@ -525,11 +556,13 @@ def parse_video(strm_in, de_bug=False, use_hw_accel=True ): nw = 1920 nh = round( (nw / vid_width) * vid_heigh / 2) * 2 # Ensure nh is always even ff_vid = [ - '-map', f'0:v:{indx}', - f'-c:v:{indx}', 'libx265', # Specify the H.265 codec here - '-pix_fmt', f"{this_vid['pix_fmt']}", - '-crf', '22','-preset', 'slow', - '-vf', f'scale={nw}:{nh}', + '-map', f'0:v:{indx}', + f'-c:v:{indx}', 'libx265', # Specify H.265 codec here + '-vf', f'scale={nw}:{nh}', + '-pix_fmt', "yuv420p10le", + '-crf', '22', + '-b:v', "3500k", + '-preset', 'slow', ] extra = f' {output} Scale {vid_width}x{vid_heigh} to {nw}x{nh}' skip_it = False @@ -541,7 +574,7 @@ def parse_video(strm_in, de_bug=False, use_hw_accel=True ): ff_vid.extend([f"-metadata:s:v:{indx}", "handler_name=VideoHandler x265"]) skip_it = False - message = f" ||{codec_name:^8}|{vid_width:<4}x{vid_heigh:<4}|{aspct_r}|Bit: {msj}|Btrt: {hm_sz(_vi_btrt):>6}|Avbpp: {avbpp:>3}|Fps: {frm_rate:>7}|Tfm: {hm_sz(glb_totfrms,'F'):>8}|{extra}|" + message = f" ||{codec_name:^8}|{vid_width:<4}x{vid_heigh:<4}|{aspct_r}|Bit: {msj}|Btrt: {hm_sz(_vi_btrt):>6}|Fps: {frm_rate:>7}|Tfm: {hm_sz(glb_totfrms,'F'):>8}|{extra}|" print(f"\033[91m{message}\033[0m") ff_video += ff_vid diff --git a/My_Utils.py b/My_Utils.py index 6435f6f..1d267b2 100644 --- a/My_Utils.py +++ b/My_Utils.py @@ -290,7 +290,19 @@ def __init__(self, spin_text="|/-o+\\", indent=0): self.spin_text = spin_text self.spin_length = len(spin_text) self.prefix = " " * indent # Indentation string - + self.last_message_length = 0 # To keep track of the length of the last printed message + self.cursor_hidden = False + + def hide_cursor(self): + if not self.cursor_hidden: + sys.stderr.write("\033[?25l") # Hide cursor + sys.stderr.flush() + self.cursor_hidden = True + def show_cursor(self): + if self.cursor_hidden: + sys.stderr.write("\033[?25h") # Show cursor + sys.stderr.flush() + self.cursor_hidden = False def print_spin(self, extra: str = "") -> None: """ Prints a spinner in the console to indicate progress. @@ -298,11 +310,25 @@ def print_spin(self, extra: str = "") -> None: Args: extra (str): Additional text to display after the spinner. """ + self.hide_cursor() + terminal_width = shutil.get_terminal_size().columns spin_char = self.spin_text[self.spinner_count % self.spin_length] - sys.stderr.write(f"\r{self.prefix}| {spin_char} | {extra}") + message = f"\r{self.prefix}| {spin_char} | {extra}" + if len(message) > terminal_width: + message = message[:terminal_width - 1] # Truncate to fit the terminal width + clear_spaces = max(self.last_message_length - len(message), 0) + sys.stderr.write(f"{message}{' ' * clear_spaces}") sys.stderr.flush() + self.last_message_length = len(message) self.spinner_count += 1 + def stop(self): + """ + Stops the spinner and shows the cursor. + """ + self.show_cursor() + sys.stderr.write("\n") # Move to the next line after stopping + sys.stderr.flush() ''' # Example usage: if __name__ == "__main__": @@ -311,13 +337,13 @@ def print_spin(self, extra: str = "") -> None: spinner_with_indent = Spinner(indent=4) for _ in range(100): # Simulate a task with 10 iterations - spinner_no_indent.print_spinner(f" {_} Processing without indent...") + spinner_no_indent.print_spin(f" {_} Processing without indent...") time.sleep(0.1) # Simulate work being done print("\n") for _ in range(100): # Simulate a task with 10 iterations - spinner_with_indent.print_spinner(f" {_} Processing with indent...") + spinner_with_indent.print_spin(f" {_} Processing with indent...") time.sleep(0.1) # Simulate work being done print("\nTask completed!") diff --git a/Trans_code.py b/Trans_code.py index aba9650..21c652f 100644 --- a/Trans_code.py +++ b/Trans_code.py @@ -223,6 +223,7 @@ def scan_folder(root: str, xtnsio: List[str], sort_order: bool, do_clustering: b str_t = time.perf_counter() msj = f"{sys._getframe().f_code.co_name} Start: {time.strftime('%H:%M:%S')}" print(f"Scan: {root}\tSize: {hm_sz(get_tree_size(root))}\n{msj}") + spinner = Spinner(indent=0) # Ensure xtnsio is a tuple # if isinstance(xtnsio, str): @@ -257,8 +258,9 @@ def process_files(executor=None): print(f"Skipping inaccessible file: {f_path}") continue - _, ext = os.path.splitext(one_file.lower()) - if ext in xtnsio: + _, ext = os.path.splitext(one_file) + if ext.lower() in xtnsio: + spinner.print_spin(f" {one_file} ") try: file_s = os.path.getsize(f_path) if not os.access(f_path, os.W_OK) or not (os.stat(f_path).st_mode & stat.S_IWUSR): @@ -302,8 +304,6 @@ def handle_result(result): else: process_files() - end_t = time.perf_counter() - print(f" Scan Done : {time.strftime('%H:%M:%S')}\tTotal: {hm_time(end_t - str_t)}") if do_clustering: print(f" Start Clustering : {time.strftime('%H:%M:%S')}") @@ -312,11 +312,10 @@ def handle_result(result): data.append([file_s, duration]) perform_clustering(data, _lst) + order = "Descending >" if sort_order else "Ascending <" end_t = time.perf_counter() - print(f"\n Scan: Done : {time.strftime('%H:%M:%S')}\tTotal: {hm_time(end_t - str_t)}") + print(f"\n Sort: {order}\n Scan: Done : {time.strftime('%H:%M:%S')}\tTotal: {hm_time(end_t - str_t)}\n") - order = "Descending >" if sort_order else "Ascending <" - print(f" Sort: {order}") return sorted(_lst, key=lambda item: item[1], reverse=sort_order)