corrigido o progresso na inteface e o encoder
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import subprocess
|
||||
import json
|
||||
import os
|
||||
from database import FFmpegProfile
|
||||
from core.state import state
|
||||
|
||||
@@ -11,111 +12,108 @@ class FFmpegEngine:
|
||||
self.profile = FFmpegProfile.get_or_none(FFmpegProfile.is_active == True)
|
||||
|
||||
if not self.profile:
|
||||
state.log("⚠️ Nenhum perfil FFmpeg ativo!")
|
||||
state.log("⚠️ AVISO: Nenhum perfil FFmpeg ativo! Usando defaults.")
|
||||
|
||||
def get_file_info(self, filepath):
|
||||
cmd = ['ffprobe', '-v', 'quiet', '-print_format', 'json', '-show_streams', '-show_format', filepath]
|
||||
try:
|
||||
output = subprocess.check_output(cmd).decode('utf-8')
|
||||
return json.loads(output)
|
||||
except: return None
|
||||
except Exception as e:
|
||||
state.log(f"Erro FFprobe: {e}")
|
||||
return None
|
||||
|
||||
def get_duration(self, filepath):
|
||||
try: return float(self.get_file_info(filepath)['format']['duration'])
|
||||
except: return 0
|
||||
|
||||
def build_command(self, input_file, output_file):
|
||||
if not self.profile: raise Exception("Perfil não selecionado")
|
||||
if not self.profile: raise Exception("Perfil não configurado.")
|
||||
p = self.profile
|
||||
metadata = self.get_file_info(input_file)
|
||||
if not metadata: raise Exception("Metadados inválidos")
|
||||
if not metadata: raise Exception("Arquivo inválido.")
|
||||
|
||||
cmd = ['ffmpeg', '-y']
|
||||
cmd = ['ffmpeg', '-y']
|
||||
|
||||
# --- HARDWARE INIT ---
|
||||
# VAAPI (Intel Linux/Docker) - O Jeito Correto
|
||||
# --- CONFIGURAÇÃO DE HARDWARE OTIMIZADA ---
|
||||
video_filters = []
|
||||
|
||||
if 'vaapi' in p.video_codec:
|
||||
cmd.extend(['-init_hw_device', 'vaapi=va:/dev/dri/renderD128'])
|
||||
cmd.extend(['-hwaccel', 'vaapi', '-hwaccel_output_format', 'vaapi', '-hwaccel_device', 'va'])
|
||||
cmd.extend(['-i', input_file])
|
||||
# Filtro essencial para VAAPI: garante formato NV12 na GPU
|
||||
# Mas como usamos hwaccel_output_format vaapi, o filtro pode ser simplificado ou scale_vaapi
|
||||
# Vamos usar o padrão seguro que funciona em Haswell:
|
||||
video_filters = 'format=nv12,hwupload'
|
||||
# TENTATIVA OTIMIZADA: HWAccel habilitado na entrada
|
||||
# Isso reduz a CPU drasticamente se o decode for suportado
|
||||
cmd.extend(['-hwaccel', 'vaapi'])
|
||||
cmd.extend(['-hwaccel_device', '/dev/dri/renderD128'])
|
||||
cmd.extend(['-hwaccel_output_format', 'vaapi'])
|
||||
|
||||
# Não precisamos de 'hwupload' se o output format já é vaapi
|
||||
# Mas vamos deixar o filtro scale_vaapi caso precise redimensionar (opcional)
|
||||
# video_filters.append('scale_vaapi=format=nv12')
|
||||
|
||||
elif 'qsv' in p.video_codec:
|
||||
cmd.extend(['-hwaccel', 'qsv', '-i', input_file])
|
||||
video_filters = None
|
||||
cmd.extend(['-hwaccel', 'qsv', '-c:v', 'h264_qsv'])
|
||||
|
||||
elif 'nvenc' in p.video_codec:
|
||||
cmd.extend(['-hwaccel', 'cuda', '-i', input_file])
|
||||
video_filters = None
|
||||
|
||||
else:
|
||||
# CPU
|
||||
cmd.extend(['-i', input_file])
|
||||
video_filters = None
|
||||
cmd.extend(['-hwaccel', 'cuda'])
|
||||
|
||||
# Input e Threads (Limita CPU se cair pra software decode)
|
||||
cmd.extend(['-threads', '4', '-i', input_file])
|
||||
|
||||
# --- VÍDEO ---
|
||||
cmd.extend(['-map', '0:v:0'])
|
||||
|
||||
cmd.extend(['-map', '0:v:0'])
|
||||
|
||||
if p.video_codec == 'copy':
|
||||
cmd.extend(['-c:v', 'copy'])
|
||||
else:
|
||||
cmd.extend(['-c:v', p.video_codec])
|
||||
|
||||
# Se tem filtro de hardware (VAAPI precisa subir pra GPU se hwaccel falhar no decode)
|
||||
if 'vaapi' in p.video_codec:
|
||||
# Se usarmos -hwaccel vaapi, o stream ja esta na GPU.
|
||||
# Mas as vezes precisamos garantir o filtro scale_vaapi se fosse redimensionar.
|
||||
# Para manter simples e funcional no Haswell:
|
||||
# cmd.extend(['-vf', 'format=nv12,hwupload']) <--- Se nao usar hwaccel
|
||||
# Com hwaccel, nao precisa do hwupload, mas precisa garantir compatibilidade
|
||||
pass
|
||||
# Filtros
|
||||
if video_filters:
|
||||
cmd.extend(['-vf', ",".join(video_filters)])
|
||||
|
||||
# Configs de Encoder
|
||||
# Qualidade
|
||||
if 'vaapi' in p.video_codec:
|
||||
# VAAPI usa QP, não CRF padrão
|
||||
# Se der erro, troque '-qp' por '-rc_mode CQP -global_quality'
|
||||
# -qp é o modo Qualidade Constante do VAAPI
|
||||
# Se der erro, remova -qp e use -b:v 5M
|
||||
cmd.extend(['-qp', str(p.crf)])
|
||||
|
||||
elif 'qsv' in p.video_codec:
|
||||
cmd.extend(['-global_quality', str(p.crf), '-look_ahead', '1'])
|
||||
cmd.extend(['-preset', p.preset])
|
||||
|
||||
elif 'nvenc' in p.video_codec:
|
||||
cmd.extend(['-cq', str(p.crf), '-preset', p.preset])
|
||||
|
||||
elif 'libx264' in p.video_codec:
|
||||
cmd.extend(['-crf', str(p.crf), '-preset', p.preset])
|
||||
|
||||
# --- ÁUDIO ---
|
||||
allowed = p.audio_langs.split(',') if p.audio_langs else []
|
||||
# --- ÁUDIO (AAC Stereo) ---
|
||||
allowed_langs = [l.strip().lower() for l in (p.audio_langs or "").split(',')]
|
||||
audio_streams = [s for s in metadata['streams'] if s['codec_type'] == 'audio']
|
||||
|
||||
acount = 0
|
||||
for s in audio_streams:
|
||||
l = s.get('tags', {}).get('language', 'und')
|
||||
if not allowed or l in allowed or 'und' in allowed:
|
||||
lang = s.get('tags', {}).get('language', 'und').lower()
|
||||
if not allowed_langs or lang in allowed_langs or 'und' in allowed_langs:
|
||||
cmd.extend(['-map', f'0:{s["index"]}'])
|
||||
cmd.extend([f'-c:a:{acount}', 'aac', f'-b:a:{acount}', '192k'])
|
||||
# AAC é leve e compatível
|
||||
cmd.extend([f'-c:a:{acount}', 'aac', f'-b:a:{acount}', '192k', f'-ac:{acount}', '2'])
|
||||
acount += 1
|
||||
if acount == 0: cmd.extend(['-map', '0:a:0', '-c:a', 'aac'])
|
||||
|
||||
if acount == 0 and audio_streams:
|
||||
cmd.extend(['-map', '0:a:0', '-c:a', 'aac', '-b:a', '192k'])
|
||||
|
||||
# --- LEGENDAS ---
|
||||
lallowed = p.subtitle_langs.split(',') if p.subtitle_langs else []
|
||||
# --- LEGENDAS (Copy) ---
|
||||
sub_allowed = [l.strip().lower() for l in (p.subtitle_langs or "").split(',')]
|
||||
sub_streams = [s for s in metadata['streams'] if s['codec_type'] == 'subtitle']
|
||||
|
||||
scount = 0
|
||||
for s in sub_streams:
|
||||
l = s.get('tags', {}).get('language', 'und')
|
||||
if not lallowed or l in lallowed or 'und' in lallowed:
|
||||
lang = s.get('tags', {}).get('language', 'und').lower()
|
||||
if not sub_allowed or lang in sub_allowed or 'und' in sub_allowed:
|
||||
cmd.extend(['-map', f'0:{s["index"]}'])
|
||||
cmd.extend([f'-c:s:{scount}', 'copy'])
|
||||
scount += 1
|
||||
|
||||
cmd.extend(['-metadata', 'title=', '-metadata', 'comment=CleiFlow'])
|
||||
# Metadados
|
||||
clean_title = os.path.splitext(os.path.basename(output_file))[0]
|
||||
cmd.extend(['-metadata', f'title={clean_title}'])
|
||||
cmd.append(output_file)
|
||||
|
||||
# LOG DO COMANDO PARA DEBUG
|
||||
state.log(f"🛠️ CMD: {' '.join(cmd)}")
|
||||
|
||||
return cmd
|
||||
Reference in New Issue
Block a user