블로그

AI로 얼굴 없이 숏폼 영상 만들기: 스크립트에서 자막, ffmpeg까지

숏폼은 여전히 가장 저렴한 유통 채널이지만, 많은 분들이 같은 지점에서 멈춥니다. 카메라 앞에 서기 싫다는 것이죠. 얼굴 없이 만드는 이른바 페이스리스(faceless) 영상이 그 해법입니다. 나레이션과 화면만으로 구성된 세로형 영상이고, 파이프라인을 뜯어보면 네 단계로 정리됩니다.1. 주제에서 스크립트로첫 단계는 순수한 텍스트 문제입니다. LLM에 주제를 주고 30~60초 분량의 스크립트를 받아옵니다. 여기서 가장 중요한 제약은 길이입니다. 45초짜리 세로 영상은 대략 110~130 단어 분량인데, 제약 없이 생성하면 300 단어가 나오고 렌더링 결과는 3분짜리가 됩니다.실무 팁 두 가지입니다. 훅(첫 문장)은 따로, 그리고 여러 개 생성하세요. 첫 1.5초가 이탈을 결정하는데 훅 5개를 뽑아서 고르는 비용은 매우 저렴합니다. 그리고 스크립트를 통짜 산문이 아니라 씬(scene) 배열의 JSON으로 받아두면 뒤에서 화면을 붙일 때 경계가 이미 나뉘어 있어 편합니다.2. 스크립트에서 음성으로TTS 엔드포인트는 어떤 것을 써도 읽어주긴 합니다. 놓치기 쉬운 부분은 오디오 파일만이 아니라 단어 단위 타임스탬프가 필요하다는 점입니다. 이게 없으면 자막 싱크를 맞출 수 없고, 이 포맷에서 체감 품질의 절반은 자막입니다.TTS 제공자가 타임스탬프를 주지 않는다면 생성된 오디오를 whisperX나 aeneas 같은 정렬 도구에 한 번 더 통과시켜 복원하면 됩니다. 패스가 하나 늘지만, 음성에 딱 붙는 자막과 미묘하게 밀리는 자막의 차이를 만듭니다.3. 타임스탬프에서 자막으로세로 영상 자막은 보통 한 번에 2~4 단어, 화면 중앙, 큰 글자에 두꺼운 외곽선입니다. 어떤 배경 위에서도 읽혀야 하기 때문입니다. 단어 타임스탬프를 자막 청크로 묶은 뒤 SRT보다 ASS로 내보내면 외곽선 두께, 그림자, 위치, 단어별 하이라이트를 다룰 수 있습니다.그리고 자막은 반드시 영상에 구워 넣으세요. 소프트 자막은 플랫폼마다 렌더링이 다르거나 아예 표시되지 않습니다.4. 합성마지막은 ffmpeg입니다. 타깃은 1080x1920이고, 중요한 연산은 두 가지입니다. 소스 영상을 찌그러뜨리지 않고 세로로 크롭하는 것, 그리고 오디오 라우드니스를 일정하게 유지하는 것입니다.ffmpeg -i bg.mp4 -i voice.mp3 \ -filter_complex "[0:v]scale=1080:-2,crop=1080:1920,subtitles=captions.ass[v]; \ [1:a]loudnorm=I=-16:TP=-1.5:LRA=11[a]" \ -map "[v]" -map "[a]" -shortest -c:v libx264 -pix_fmt yuv420p out.mp4loudnorm은 선택이 아닙니다. 정규화 없이 TTS 음성과 배경음악을 섞는 것이 영상이 아마추어처럼 들리는 가장 흔한 이유입니다.실제로 자주 깨지는 지점끝부분 무음 - TTS 출력에는 끝에 300~600ms의 무음이 붙는 경우가 많고 그대로 두면 데드 에어가 됩니다. silenceremove로 잘라내거나 마지막 단어 타임스탬프 기준으로 자르세요.자막 드리프트 - 제공자가 준 타임스탬프가 트리밍 이전 오디오 기준일 때가 있습니다. 자른 뒤에는 항상 다시 정렬하세요.렌더 비용 - 1080x1920 libx264는 CPU로도 충분하지만, 한 대에서 여러 작업을 몰아치면 큐가 밀립니다. 요청 핸들러 안에서 렌더링하지 말고 렌더러를 별도 컨테이너와 잡 큐로 분리하는 편이 낫습니다.직접 만들지 않는 선택지전체를 직접 구현하면 주말 두세 번 정도의 작업량에 LLM/TTS 호출 비용과 렌더 서버 비용이 더해집니다. 모든 단계를 통제하고 싶다면 그만한 가치가 있습니다.결과물만 필요하다면 같은 파이프라인을 호스팅 서비스로 제공하는 곳들이 있습니다. 제가 만들고 있는 Faceless Reels도 그중 하나로, 주제를 입력하면 스크립트, AI 음성, 자막, 음악까지 붙은 세로 영상을 틱톡/릴스/쇼츠용으로 만들어 줍니다. 빈 편집기 대신 스토리텔링, 두들 익스플레이너 같은 템플릿 워크플로우로 시작하는 구조인데, 손으로 만들 때 가장 잡기 어려웠던 부분이 인코딩이 아니라 바로 이 구조였습니다.어느 쪽을 택하든 멘탈 모델은 같습니다. 네 단계, 그리고 품질은 타임스탬프에 있습니다.

숏폼ffmpegAI

Building a Faceless Short-Form Video Pipeline

I spent a while building an automated pipeline that turns a topic into a finished 9:16 video. Most write-ups about this stop at "call an LLM, call a TTS API, done." The interesting problems are all in the layer after that, so here are the ones that actually cost me time.Forced alignment matters more than voice qualityThe naive approach chunks captions by word count and assumes a speaking rate. This breaks immediately, because TTS duration varies by voice, by punctuation, and by how the engine handles numbers. A 140-word script came back as 38s on one voice and 44s on another.The fix is to run forced alignment against the returned audio and derive caption timings from actual word timestamps. Some engines return word-level timings directly; otherwise a small alignment pass gets you there. Doing this after synthesis instead of predicting before it removes an entire category of bug. Any faceless reels ai pipeline that skips this will drift on longer clips.The ffmpeg filter graph is where things get slowA typical composite is: scale and crop background to 1080x1920, overlay caption images per segment, mix voiceover with a ducked music bed, then encode. Written as one filter_complex chain this is fine. Written as several sequential ffmpeg invocations with intermediate files, it is roughly 4x slower and burns disk.ffmpeg -i bg.mp4 -i vo.wav -i music.m4a \ -filter_complex "[0:v]scale=-2:1920,crop=1080:1920[v];[2:a]volume=0.15[m];[1:a][m]amix=inputs=2[a]" \ -map "[v]" -map "[a]" -c:v libx264 -preset veryfast -crf 23 out.mp4Two things that bit me: crop defaults to centre, which is wrong whenever the subject is off-centre, and amix normalises inputs by default, so the voiceover gets quieter as soon as you add music. Use amix=normalize=0 and duck the bed explicitly with sidechaincompress.Caption rendering: drawtext vs pre-rendered PNGffmpeg's drawtext is fast but painful for anything with emoji, mixed scripts, or per-word highlighting. Pre-rendering caption frames as transparent PNGs and overlaying them costs more I/O but gives full typographic control, and it makes the caption style a data file rather than a filter string. For a pipeline that needs several visual formats, the PNG route pays off quickly. This is broadly what a faceless reels generator does internally when it offers multiple caption styles.Concurrency limits are CPU, not APIScript and TTS calls are I/O-bound and parallelise freely. Encoding is CPU-bound and does not. Running eight renders concurrently on a 4-core box made each one slower than running them two at a time. Setting the render worker pool to roughly cores - 2 and queueing the rest was the single biggest throughput change.Determinism is worth engineering forIf a render fails halfway you want to re-run it and get byte-identical output up to the failure point. That means fixed random seeds, pinned font versions, and no wall-clock timestamps in filenames. This sounds pedantic until you are debugging why one video in a batch of thirty looks different. Format presets — one caption spec, one margin, one ducking curve, versioned together — are what makes a faceless reels maker produce a consistent-looking channel instead of thirty slightly different videos.What I would do differentlyStart with the render contract, not the LLM. Define exactly what a finished video looks like — resolution, safe margins, caption spec, audio levels — and build backwards. I did it the other way round and ended up rewriting the assembly stage twice because the script format kept changing shape.

AI 크리에이티브ffmpegvideo-automationshorts

채널톡 아이콘