fix time stdout
This commit is contained in:
+2468
-9
File diff suppressed because one or more lines are too long
+61
-5
@@ -1,4 +1,5 @@
|
|||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import json
|
import json
|
||||||
@@ -78,7 +79,7 @@ def get_file_info(input_file):
|
|||||||
cmd = [
|
cmd = [
|
||||||
'ffprobe',
|
'ffprobe',
|
||||||
'-v', 'error',
|
'-v', 'error',
|
||||||
'-show_entries', 'format=duration,size:stream=codec_name,width,height,r_frame_rate,channels,channel_layout',
|
'-show_entries', 'format=duration,size:stream=codec_type,codec_name,width,height,r_frame_rate,channels,channel_layout',
|
||||||
'-of', 'json',
|
'-of', 'json',
|
||||||
input_file
|
input_file
|
||||||
]
|
]
|
||||||
@@ -102,6 +103,18 @@ def get_audio_labels(input_file):
|
|||||||
labels.append(title)
|
labels.append(title)
|
||||||
return labels
|
return labels
|
||||||
|
|
||||||
|
def parse_fps(r_frame_rate):
|
||||||
|
"""Parse ffprobe r_frame_rate e.g. '60/1' or '30000/1001' to float."""
|
||||||
|
if not r_frame_rate:
|
||||||
|
return None
|
||||||
|
parts = str(r_frame_rate).strip().split('/')
|
||||||
|
if len(parts) == 2 and float(parts[1]) != 0:
|
||||||
|
return float(parts[0]) / float(parts[1])
|
||||||
|
try:
|
||||||
|
return float(parts[0])
|
||||||
|
except (ValueError, IndexError):
|
||||||
|
return None
|
||||||
|
|
||||||
def format_size(size_bytes):
|
def format_size(size_bytes):
|
||||||
for unit in ['B', 'KB', 'MB', 'GB']:
|
for unit in ['B', 'KB', 'MB', 'GB']:
|
||||||
if size_bytes < 1024:
|
if size_bytes < 1024:
|
||||||
@@ -193,9 +206,25 @@ def encode_dvr(input_file, output_dir, gpu):
|
|||||||
print(f"{Colors.YELLOW}Skipping {input_path} - output already exists{Colors.ENDC}")
|
print(f"{Colors.YELLOW}Skipping {input_path} - output already exists{Colors.ENDC}")
|
||||||
return
|
return
|
||||||
|
|
||||||
# Get audio labels
|
# Get audio labels and input FPS (for speed display when stderr is piped)
|
||||||
audio_labels = get_audio_labels(str(input_path))
|
audio_labels = get_audio_labels(str(input_path))
|
||||||
safe_log_info(f"Audio labels: {audio_labels}")
|
safe_log_info(f"Audio labels: {audio_labels}")
|
||||||
|
input_fps = None
|
||||||
|
for s in file_info.get('streams', []):
|
||||||
|
if s.get('codec_type') == 'video':
|
||||||
|
input_fps = parse_fps(s.get('r_frame_rate'))
|
||||||
|
break
|
||||||
|
if input_fps is None:
|
||||||
|
# Fallback: first stream with r_frame_rate (e.g. codec_type not in probe)
|
||||||
|
for s in file_info.get('streams', []):
|
||||||
|
if 'width' in s or s.get('codec_name', '').startswith(('h', 'm')):
|
||||||
|
input_fps = parse_fps(s.get('r_frame_rate'))
|
||||||
|
break
|
||||||
|
if input_fps is None:
|
||||||
|
for s in file_info.get('streams', []):
|
||||||
|
input_fps = parse_fps(s.get('r_frame_rate'))
|
||||||
|
if input_fps and input_fps > 0:
|
||||||
|
break
|
||||||
|
|
||||||
# FFmpeg command with NVIDIA HEVC encoder and maximum quality
|
# FFmpeg command with NVIDIA HEVC encoder and maximum quality
|
||||||
cmd = [
|
cmd = [
|
||||||
@@ -235,14 +264,41 @@ def encode_dvr(input_file, output_dir, gpu):
|
|||||||
bufsize=1
|
bufsize=1
|
||||||
)
|
)
|
||||||
|
|
||||||
# Stream output line-by-line from a single pipe
|
# Stream output line-by-line; compute speed when stderr is piped (FFmpeg shows speed=N/A)
|
||||||
for line in iter(process.stdout.readline, ''):
|
for line in iter(process.stdout.readline, ''):
|
||||||
if not line:
|
if not line:
|
||||||
break
|
break
|
||||||
text = line.strip()
|
text = line.strip().strip('\r')
|
||||||
try:
|
try:
|
||||||
if text.startswith('frame=') or ' fps=' in text:
|
if text.startswith('frame=') or ' fps=' in text:
|
||||||
safe_log_info(f"Progress: {text}", f"{Colors.PURPLE}Progress: {text}{Colors.ENDC}")
|
display = text
|
||||||
|
m_frame = re.search(r'frame=\s*(\d+)', text)
|
||||||
|
m_elapsed = re.search(r'elapsed=(\d+):(\d+):(\d+\.?\d*)', text)
|
||||||
|
m_size = re.search(r'size=\s*(\d+)\s*KiB', text)
|
||||||
|
if m_frame and m_elapsed:
|
||||||
|
frames = int(m_frame.group(1))
|
||||||
|
h, m, s = float(m_elapsed.group(1)), float(m_elapsed.group(2)), float(m_elapsed.group(3))
|
||||||
|
elapsed_sec = h * 3600 + m * 60 + s
|
||||||
|
if elapsed_sec > 0:
|
||||||
|
if input_fps and input_fps > 0:
|
||||||
|
speed_x = (frames / input_fps) / elapsed_sec
|
||||||
|
display = re.sub(r'speed=N/A', f'speed={speed_x:.2f}x', text)
|
||||||
|
# time = output position (HH:MM:SS.ms)
|
||||||
|
video_sec = frames / input_fps
|
||||||
|
t_h = int(video_sec // 3600)
|
||||||
|
t_m = int((video_sec % 3600) // 60)
|
||||||
|
t_s = video_sec % 60
|
||||||
|
time_str = f'{t_h}:{t_m:02d}:{t_s:06.3f}' if t_h else f'0:{t_m:02d}:{t_s:06.3f}'
|
||||||
|
display = re.sub(r'time=N/A', f'time={time_str}', display)
|
||||||
|
# bitrate when muxer has written data (stays N/A until size > 0)
|
||||||
|
size_kib = int(m_size.group(1)) if m_size else 0
|
||||||
|
if size_kib > 0 and elapsed_sec > 0:
|
||||||
|
bitrate_kbps = (size_kib * 8192) / (elapsed_sec * 1000)
|
||||||
|
display = re.sub(r'bitrate=N/A', f'bitrate={bitrate_kbps:.0f}kbits/s', display)
|
||||||
|
else:
|
||||||
|
enc_fps = frames / elapsed_sec
|
||||||
|
display = re.sub(r'speed=N/A', f'speed={enc_fps:.0f}fps', text)
|
||||||
|
safe_log_info(f"Progress: {text}", f"{Colors.PURPLE}Progress: {display}{Colors.ENDC}")
|
||||||
else:
|
else:
|
||||||
safe_log_info(f"FFmpeg: {text}", f"{Colors.GREEN}FFmpeg: {text}{Colors.ENDC}")
|
safe_log_info(f"FFmpeg: {text}", f"{Colors.GREEN}FFmpeg: {text}{Colors.ENDC}")
|
||||||
except (OSError, IOError) as e:
|
except (OSError, IOError) as e:
|
||||||
|
|||||||
Reference in New Issue
Block a user