feat(video): prefer max-fps source and bump edited output to 60fps

- youtube.ts: yt-dlp 에 `-S 'fps,res,br,ext'` 추가. 기본 정렬은 fps 를
  가중치로 안 써서 60fps 가 있어도 30fps 를 잡아오는 일이 잦았는데,
  이제 fps 1순위로 정렬해 가능한 한 부드러운 원본을 받는다. 60fps 가
  아예 없는 영상은 자연스럽게 그 영상의 최고 fps 로 폴백.

- editor.ts: 편집본은 항상 60fps 이상이 되도록 보장.
  · ffprobe 로 원본 fps 확인
  · ≥60fps 이면 기존대로 stream copy 로 빠르게 trim
  · <60fps 이면 minterpolate(mci, aobmc, bidir) 로 모션 보간해 60fps 로
    재인코딩. mci 는 느리지만 단순 프레임 복제보다 모션이 훨씬 자연스러움.
  · ffprobe 실패 시(확인 불가) 기존 동작 유지(stream copy → 재인코딩 폴백).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Claude
2026-05-16 02:33:37 +09:00
parent 59f96a12a6
commit 105c5bf09d
2 changed files with 48 additions and 4 deletions

View File

@@ -186,6 +186,11 @@ async function runJob(job: DownloadJob, bin: string): Promise<void> {
'--no-warnings',
'--no-playlist',
'--newline',
// 가능한 한 부드러운 영상을 받기 위해 fps 를 최우선으로 정렬한다.
// yt-dlp 기본 정렬은 fps 를 가중치로 안 써서 60fps 가 있어도 30fps 를 잡아오는 일이 잦다.
// 우선순위: fps → 해상도 → 비트레이트 → 확장자.
// 60fps 가 아예 없는 영상은 자연스럽게 그 영상의 최고 fps 로 폴백된다.
'-S', 'fps,res,br,ext',
'--progress-template', 'download:PROGRESS %(progress._percent_str)s',
'--print', 'after_move:OUT %(filepath)s',
'-o', path.join(dir, 'original.%(ext)s'),