Archives
Trending
Support
Login
clear text
XML
Django
JavaScript
MATLAB
C
C++
C#
Python
SQL
Shell
Bash
Markdown
YAML
JSON
HTML
CSS
PHP
Java
Ruby
Go
Rust
Swift
Kotlin
Arduino
TypeScript
Perl
Autohotkey
Lua
SQF
R
Scala
Haskell
Groovy
Dart
Clojure
VB.NET
Objective-C
PowerShell
Bash
CoffeeScript
Verilog
def _docker_ffmpeg_args(cpus=None, cpuset=None, use_gpu=False): args = ['docker','run','--rm', '-e','DOCKER_CONFIG=/dev/null'] if cpus: args += ['--cpus', str(cpus)] if cpuset: args += ['--cpuset-cpus', str(cpuset)] if use_gpu: args += ['--gpus=all', '-e','NVIDIA_VISIBLE_DEVICES=all', '-e','NVIDIA_DRIVER_CAPABILITIES=all'] args += [ '--security-opt','seccomp=unconfined', '--cap-add','SYS_NICE', '-v', docker_mount_point, 'ghcr.io/aperim/nvidia-cuda-ffmpeg:latest', ] return args def _nvenc_cmd( file_path: str, out_path: str, vkbps: int, vf_h: int, is_10bit: bool, # non usato qui n_audio: int, ext_low: str, # compat audio_map_relidx: list[int] | None = None, force_stereo: bool = FORCE_STEREO, use_dplii_matrix: bool = True, keep_subtitles: bool = True, # nuovo: se True, mantieni i sottotitoli ) -> list[str]: cmd = _docker_ffmpeg_args(use_gpu=True) + [ '-y','-nostdin','-hide_banner','-loglevel','error', '-hwaccel','cuda', '-i', file_path, '-vf', f'scale=-2:{vf_h}:force_original_aspect_ratio=decrease', ] # --- Mapping --- # Video principale cmd += ['-map','0:v:0'] # Audio: o filtro esplicito o tutte if audio_map_relidx is not None: cmd += ['-map','-0:a'] # drop tutte le audio for idx in sorted(audio_map_relidx): cmd += ['-map', f'0:a:{idx}'] eff_n_audio = len(audio_map_relidx) else: cmd += ['-map','0:a?'] eff_n_audio = n_audio # Sottotitoli (se richiesto) if keep_subtitles: cmd += ['-map','0:s?'] eff_n_subs = 1 # serve solo per flag copy; non puntiamo gli indici qui else: eff_n_subs = 0 # --- Video (come tuo originale NVENC) --- cmd += [ '-c:v','hevc_nvenc', '-rc','vbr_hq','-multipass','fullres', '-b:v', f'{int(vkbps)}k', '-maxrate', f'{int(vkbps*1.08)}k', '-bufsize', f'{int(vkbps*2.0)}k', '-rc-lookahead','32', '-spatial_aq','1','-temporal_aq','1','-aq-strength','8', '-bf','3','-b_ref_mode','middle', '-g','240', ] # --- Audio --- if eff_n_audio > 0: cmd += ['-c:a','libfdk_aac'] # Default globale (copre eventuali stream non indicizzati) cmd += ['-b:a', f'{AUDIO_KBPS_PER_TRACK}k'] # Impostazioni per ciascuna traccia audio for i in range(eff_n_audio): cmd += [f'-b:a:{i}', f'{AUDIO_KBPS_PER_TRACK}k'] if force_stereo: cmd += [f'-ac:a:{i}', '2'] if use_dplii_matrix: # indica encoding matrix dolby pro logic II (metadato utile) cmd += [f'-filter:a:{i}', 'aresample=matrix_encoding=dplii'] # Titolo pulito della traccia cmd += [f'-metadata:s:a:{i}', f'title=AAC LC 2.0 {AUDIO_KBPS_PER_TRACK} kbps'] # Disposition: prima audio default, le altre non-default cmd += ['-disposition:a:0','default'] for i in range(1, eff_n_audio): cmd += [f'-disposition:a:{i}','0'] # rimuove default/forced se ereditati else: cmd += ['-an'] # nessuna traccia audio # --- Sottotitoli: copia "as-is" (MKV è perfetto per srt/ass/pgs/vobsub) --- if keep_subtitles and eff_n_subs: cmd += ['-c:s','copy'] # opzionale: assicurati che nessun sottotitolo sia "default" # (evita sorprese quando ffmpeg ereditasse i flag) cmd += ['-disposition:s','0'] # --- Metadati/Capitoli del container --- # Puliamo: BPS/NUMBER_OF_BYTES/encoder ecc. (ri-setteremo noi dopo il size-check) cmd += ['-map_metadata','-1'] # Matroska container (lavoriamo solo in mkv) cmd.append(out_path) return cmd def _run(cmd: List[str]) -> Tuple[int, float, str]: start = time.time() p = subprocess.run(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE) elapsed = time.time() - start return p.returncode, elapsed, (p.stderr.decode('utf-8', errors='ignore') if p.stderr else "") def run_encode_once(out_path: str, ctx: EncodeContext, plan: TargetPlan, audio_map_relidx: Optional[List[int]] = None) -> Tuple[int, float, int]: try: if os.path.exists(out_path): os.remove(out_path) except Exception: pass cmd = _nvenc_cmd( file_path=ctx.file_path, out_path=out_path, vkbps=int(plan.v_kbps), vf_h=int(plan.vf_height), is_10bit=ctx.is_10bit, n_audio=ctx.n_audio, ext_low=Path(ctx.file_path).suffix.lower(), audio_map_relidx=audio_map_relidx ) eff_n_audio = (len(audio_map_relidx) if audio_map_relidx is not None else ctx.n_audio) logger.info( "[encode] start: out=%s, v=%s kb/s, a_total=%s kb/s, total=%s kb/s, vf_h=%s, audio_streams=%d, dur=%s (%.0fs)", out_path, plan.v_kbps, plan.target_audio_kbps_total, plan.safe_total_kbps, plan.vf_height, eff_n_audio, _fmt_hms(ctx.duration_s), ctx.duration_s ) rc, elapsed, stderr = _run(cmd) out_size = os.path.getsize(out_path) if (rc == 0 and os.path.exists(out_path)) else -1 if rc != 0: tail = (stderr[-400:] if stderr else "") logger.error( "[encode] failed: rc=%s, elapsed=%.1fs, out_exists=%s, stderr_tail=%s", rc, elapsed, os.path.exists(out_path), tail ) else: # bitrate effettivo totale e fattore realtime eff_total_kbps = int((out_size * 8) / max(1.0, ctx.duration_s) / 1000) delta_pct = ( (eff_total_kbps / plan.safe_total_kbps - 1.0) * 100.0 ) if plan.safe_total_kbps else 0.0 rt_factor = (ctx.duration_s / max(1e-6, elapsed)) logger.info( "[encode] done: rc=0, elapsed=%.1fs (%.2fx realtime), size=%s (%d B), eff_total=%d kb/s " "(plan_total=%s, Δ=%.2f%%)", elapsed, rt_factor, _fmt_bytes(out_size), out_size, eff_total_kbps, plan.safe_total_kbps, delta_pct ) return rc, elapsed, out_size
Mark as private (unlisted)
for 30 minutes
for 6 hours
for 1 day
for 1 week
for 1 month
for 1 year
everlasting (like CCCP)