Communitygithub.com

비디오 제작

사용자가 이미지 슬라이드쇼, 텍스트/자막이 포함된 클립, 트리밍, 병합, 음악/음성 추가, 소셜 미디어용 크기 조정, 애니메이션 렌더링 등 비디오 파일(.mp4, .mov, .webm, .gif)을 생성, 편집 또는 변환하려는 경우 이 스킬을 사용합니다.

비디오 제작란 무엇인가요?

이 스킬은 ffmpeg(코어 엔진)과 Python(Pillow 및 MoviePy)을 사용하여 프로그래밍 방식으로 비디오를 제작할 수 있게 해줍니다. 사용자 요청에 따라 다양한 형식과 해상도(16:9, 9:16, 1:1)로 슬라이드쇼, 텍스트 오버레이, 캡션, 배경 음악, 속도 조절, GIF 변환 등을 처리합니다. 핵심 워크플로는 계획, 도구 체인 확인, 씬 기반 인코딩, 최종 렌더링, 검증 순서로 진행되며, 특히 '하나의 최종 렌더링'만 수행하도록 설계되어 효율성을 극대화합니다. 각 씬을 별도 파일로 인코딩하고 concat 디먹서로 무손실 병합하는 방식으로 불필요한 재인코딩을 최소화하며, 중단 시 부분 파일로 남지 않도록 안전 장치를 포함합니다. 또한 ffprobe를 통한 검증, 접촉 시트 생성, 체크리스트를 제공하여 최종 결과물의 품질을 보장합니다. 이 스킬은 Claude Code, Cursor, Codex 등 다양한 AI 에이전트 플랫폼에서 명령어 기반으로 작동합니다.

지원 대상~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/SahilRakhaiya05/Father-Using-This-Skills/tree/HEAD/plugins/video-making

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

비디오 제작 스킬

코드로 만드는 애니메이션 모션 그래픽(키네틱 타입, 설명 영상, 런칭 비디오, 애니메이션 차트, 다양한 시각적 스타일의 로어 서드)에는 motion-graphics 스킬을 사용하세요. 이 스킬은 영상, 사진, 오디오 및 ffmpeg 편집을 위한 것입니다.

ffmpeg(코어 엔진)과 Python(프레임/그래픽용 Pillow, 고급 편집용 MoviePy)을 사용하여 프로그래밍 방식으로 비디오를 제작합니다. 항상 먼저 계획하고, 그 다음 제작하고, 마지막으로 검증하세요.


1. 제작 전 계획

명령어를 작성하기 전에 다음 사항을 결정하세요.

결정 사항기본값참고
화면 비율16:9 (1920x1080)릴스/쇼츠/틱톡은 9:16 (1080x1920), 피드용은 1:1 (1080x1080)
프레임 속도30fps영화 느낌은 24, 화면 녹화/게임 플레이는 60
길이요청대로릴스/쇼츠 ≤ 60~90초
형식MP4 (H.264 + AAC)어디서나 재생 가능; WebM은 요청 시에만; GIF는 짧은 루프에만
오디오선택 사항음악, 음성 해설, 또는 무음

짧은 쇼트 리스트를 작성하세요: 각 장면 → 지속 시간, 시각적 요소, 텍스트, 전환, 오디오.


2. 도구 체인 확인

which ffmpeg ffprobe || (apt-get update && apt-get install -y ffmpeg)
python3 -c "import PIL, moviepy" 2>/dev/null || pip install pillow moviepy --break-system-packages
fc-list | head   # 텍스트에 사용할 수 있는 글꼴 확인

3. 표준 인코딩 설정

사용자가 다른 요청을 하지 않는 한 모든 최종 렌더링에 다음을 사용하세요.

-c:v libx264 -preset veryfast -crf 23 -pix_fmt yuv420p -movflags +faststart \
-c:a aac -b:a 192k
  • -pix_fmt yuv420p — 휴대폰, QuickTime 및 브라우저에서 재생하는 데 필요합니다.
  • -movflags +faststart — 비디오가 완전히 다운로드되기 전에 재생을 시작할 수 있게 합니다.
  • -crf 18 = 거의 무손실(파일 크기 증가), -crf 28 = 파일 크기 감소, 품질 저하.
  • -preset veryfast는 렌더링 속도를 빠르게 유지합니다. 최고 품질이 요청될 때만 slow를 사용하세요.
  • H.264의 경우 너비와 높이는 짝수여야 합니다.

3b. 빠르게 렌더링 — 사용자가 기다리고 있습니다

전체 렌더링은 가장 느린 단계이므로 요청당 하나의 전체 렌더링만 계획하세요.

  1. 인코딩 전에 미리보기. 몇 개의 프레임(가장 바쁜 순간, 첫 번째 및 마지막 프레임)을 최종 크기로 추출하거나 그리고 프레임 구성, 텍스트 크기 및 색상을 확인하세요. 사진 비디오의 경우: scripts/slideshow.py OUT.mp4 photos… --preview는 1초 안에 연락 시트를 만듭니다.
  2. 하나의 거대한 그래프가 아닌 장면 단위. 각 장면을 동일한 크기, fps 및 인코더 설정으로 자체 파일로 인코딩하고, concat 디먹서와 -c copy로 결합한 다음, -c:v copy로 사운드를 마지막에 추가하세요. 나중에 하나의 장면을 수정하는 것은 해당 장면만 다시 인코딩하는 것을 의미합니다.
  3. 전환은 장면 파일 내에 있습니다.(가장자리에서 페이드 인/아웃). 두 개의 완성된 파일을 교차 페이드하면 두 번째 전체 인코딩이 강제됩니다.
  4. 정지 영상을 저렴하게 유지. -loop 1(매 프레임마다 이미지를 다시 디코딩) 대신 loop 필터로 그림을 한 번 디코딩하고 반복하세요: ffmpeg -framerate 30 -i still.png -vf "format=yuv420p,loop=-1:1,trim=duration=4,setpts=PTS-STARTPTS" -c:v libx264 -preset veryfast -crf 20 -pix_fmt yuv420p still.mp4
  5. 실제 이름 아래에 절대 반쯤 완성된 파일을 두지 마세요. name.part.mp4로 작성하고 ffmpeg가 0으로 종료될 때만 이름을 바꾸세요. 중단된 렌더링은 재생될 수 있지만 짧게 잘립니다.
  6. 다른 요청이 없으면 출력 크기와 30fps로 프레임을 그리세요. 웹 페이지를 프레임 단위로 캡처할 때는 PNG보다 JPEG(품질 ~90)로 저장하세요. 쓰기 및 읽기가 훨씬 빠릅니다.

10장의 사진 → 1080p로 측정: 기존의 단일 -loop 1 + xfade 그래프는 13.2초가 걸렸습니다. slideshow.py --crossfade는 6.4초, 장면 파일 경로는 8.9초(음악 포함)가 걸렸습니다.

완성된 비디오 변경:

변경 사항방법
한 장면의 내용 변경해당 장면 파일을 다시 렌더링하고 -c copy로 다시 결합
새 음악 / 엔딩 트리밍-c:v copy (새 음악: -map 0:v -map 1:a)
캡션 굽기, 작은 복사본 만들기완성된 파일을 한 번 다시 인코딩
모든 프레임에서 변경되는 사항전체 렌더링은 피할 수 없음

4. 레시피

4.0 한 줄 명령어로 사진 슬라이드쇼

python3 scripts/slideshow.py out.mp4 photos/*.jpg --seconds 3 --fade 0.5 --music song.mp3      # 빠름, 검은색으로 페이드
python3 scripts/slideshow.py out.mp4 photos/*.jpg --crossfade                                 # 실제 교차 페이드
python3 scripts/slideshow.py out.mp4 photos/*.jpg --zoom --size 1080x1920                      # 켄 번스 효과, 세로 모드

4.1 이미지로 슬라이드쇼 만들기 (페이드 전환 포함), 수동으로

# 각 이미지를 3초 동안 표시, 0.5초 교차 페이드, 1080p로 크기 조정/패딩
# 각 정지 이미지는 한 번 디코딩되고 loop 필터로 반복됩니다(-loop 1보다 2배 빠름)
F="scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2,setsar=1,format=yuv420p,loop=-1:1,trim=duration=3,setpts=PTS-STARTPTS,fps=30"
ffmpeg -framerate 30 -i img1.jpg -framerate 30 -i img2.jpg -framerate 30 -i img3.jpg \
-filter_complex "\
[0]$F[a];[1]$F[b];[2]$F[c];\
[a][b]xfade=transition=fade:duration=0.5:offset=2.5[ab];\
[ab][c]xfade=transition=fade:duration=0.5:offset=5[out]" \
-map "[out]" -c:v libx264 -preset veryfast -crf 23 -pix_fmt yuv420p -movflags +faststart slideshow.mp4

클립 n의 오프셋 = (이전 지속 시간의 합) − (n × 페이드 지속 시간).

4.2 정지 이미지에 켄 번스 효과 (느린 줌)

# d = 출력 프레임 수 (30fps에서 150 = 5초); -loop 불필요, zoompan이 프레임을 생성합니다
ffmpeg -i photo.jpg -vf "scale=3840:-2,zoompan=z='min(zoom+0.0008,1.2)':d=150:x='iw/2-(iw/zoom/2)':y='ih/2-(ih/zoom/2)':s=1920x1080:fps=30" \
-c:v libx264 -preset veryfast -crf 23 -pix_fmt yuv420p zoom.mp4

먼저 3840으로 업스케일링하면 작은 이미지에서 zoompan이 보여주는 떨리는 움직임을 방지할 수 있습니다.

4.3 텍스트 오버레이 / 타이틀 카드

ffmpeg -i input.mp4 -vf "drawtext=fontfile=/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf:\
text='My Title':fontsize=72:fontcolor=white:box=1:[email protected]:boxborderw=20:\
x=(w-text_w)/2:y=h-150:enable='between(t,0,4)'" \
-c:v libx264 -preset veryfast -crf 23 -pix_fmt yuv420p -c:a copy titled.mp4

아포스트로피, 이모지 또는 라틴어가 아닌 스크립트(힌디어 등)가 포함된 텍스트의 경우, 해당 스크립트를 지원하는 글꼴을 사용하여 Pillow로 텍스트를 PNG로 렌더링한 다음 오버레이하세요:

ffmpeg -i input.mp4 -i title.png -filter_complex "overlay=(W-w)/2:H-h-100:enable='between(t,0,4)'" ...

4.4 빈 화면에서 단색 타이틀 카드 만들기

ffmpeg -f lavfi -i color=c=0x111827:s=1920x1080:d=3:r=30 \
-vf "drawtext=fontfile=/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf:text='Chapter 1':fontsize=96:fontcolor=white:x=(w-text_w)/2:y=(h-text_h)/2" \
-c:v libx264 -preset veryfast -crf 23 -pix_fmt yuv420p card.mp4

4.5 클립 자르기

# 정확한 자르기(재인코딩): 00:00:05부터 10초 동안
ffmpeg -ss 00:00:05 -i input.mp4 -t 10 -c:v libx264 -preset veryfast -crf 23 -pix_fmt yuv420p -c:a aac trimmed.mp4
# 빠른 자르기(재인코딩 없음, 가장 가까운 키프레임에서 자름)
ffmpeg -ss 00:00:05 -i input.mp4 -t 10 -c copy trimmed_fast.mp4

4.6 클립 결합

동일한 코덱/해상도/fps → concat 디먹서 (재인코딩 없음):

printf "file 'a.mp4'\nfile 'b.mp4'\nfile 'c.mp4'\n" > list.txt
ffmpeg -f concat -safe 0 -i list.txt -c copy joined.mp4

다른 소스 → 먼저 정규화(크기 조정, fps, 오디오 레이트)하거나 concat 필터 사용:

ffmpeg -i a.mp4 -i b.mp4 -filter_complex \
"[0:v]scale=1920:1080,setsar=1,fps=30[v0];[1:v]scale=1920:1080,setsar=1,fps=30[v1];\
[v0][0:a][v1][1:a]concat=n=2:v=1:a=1[v][a]" \
-map "[v]" -map "[a]" -c:v libx264 -preset veryfast -crf 23 -pix_fmt yuv420p -c:a aac joined.mp4

(클립에 오디오 트랙이 없으면 무음을 추가하세요: -f lavfi -i anullsrc=r=48000:cl=stereo 그리고 -shortest 사용.)

4.7 배경 음악 추가

# 비디오 아래에 음악, 끝에서 페이드 아웃, 비디오가 끝나면 중지
# st = 비디오 길이 - 페이드 길이 (여기서는 30초 비디오, 3초 페이드) — ffprobe로 길이를 얻습니다
ffmpeg -i video.mp4 -i music.mp3 -filter_complex \
"[1:a]volume=0.3,afade=t=out:st=27:d=3[m]" \
-map 0:v -map "[m]" -c:v copy -c:a aac -shortest with_music.mp4

# 기존 음성 아래에 음악 믹싱
ffmpeg -i video.mp4 -i music.mp3 -filter_complex \
"[1:a]volume=0.15[m];[0:a][m]amix=inputs=2:duration=first[a]" \
-map 0:v -map "[a]" -c:v copy -c:a aac mixed.mp4

4.8 자막 / 캡션

.srt 파일을 작성하세요:

1
00:00:00,000 --> 00:00:03,000
비디오에 오신 것을 환영합니다.

2
00:00:03,000 --> 00:00:06,500
이것이 우리가 다룰 내용입니다.

자막을 굽습니다:

ffmpeg -i input.mp4 -vf "subtitles=subs.srt:force_style='FontSize=24,PrimaryColour=&HFFFFFF,OutlineColour=&H000000,BorderStyle=1,Outline=2'" \
-c:v libx264 -preset veryfast -crf 23 -pix_fmt yuv420p -c:a copy captioned.mp4

4.9 소셜 미디어용 크기 조정 (세로 9:16)

# 검은색 막대 대신 흐린 배경 채우기
ffmpeg -i landscape.mp4 -filter_complex \
"[0]scale=1080:1920:force_original_aspect_ratio=increase,crop=1080:1920,boxblur=20[bg];\
[0]scale=1080:-2[fg];[bg][fg]overlay=(W-w)/2:(H-h)/2" \
-c:v libx264 -preset veryfast -crf 23 -pix_fmt yuv420p -c:a copy vertical.mp4

4.10 속도 높이기 / 낮추기

# 2배 속도 (비디오 + 오디오)
ffmpeg -i in.mp4 -filter_complex "[0:v]setpts=0.5*PTS[v];[0:a]atempo=2.0[a]" -map "[v]" -map "[a]" fast.mp4

4.11 비디오를 GIF로 변환 (고품질)

ffmpeg -i in.mp4 -vf "fps=15,scale=640:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" -loop 0 out.gif

4.12 코드로 프레임 렌더링 (애니메이션, 차트, 모션 그래픽)

ffmpeg 필터로 충분하지 않을 때는 Python으로 각 프레임을 그리고 이어 붙이세요:

from PIL import Image, ImageDraw, ImageFont
import os, subprocess

W, H, FPS, SECONDS = 1920, 1080, 30, 4
os.makedirs("frames", exist_ok=True)
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 96)

for i in range(FPS * SECONDS):
    t = i / (FPS * SECONDS)
    img = Image.new("RGB", (W, H), (17, 24, 39))
    d = ImageDraw.Draw(img)
    x = int(-600 + t * (W + 600))          # 텍스트가 화면을 가로질러 움직입니다
    d.text((x, H // 2 - 48), "Hello!", font=font, fill=(255, 255, 255))
    img.save(f"frames/{i:05d}.png")

subprocess.run(["ffmpeg", "-y", "-framerate", str(FPS), "-i", "frames/%05d.png",
                "-c:v", "libx264", "-preset", "veryfast", "-crf", "23",
                "-pix_fmt", "yuv420p", "-movflags", "+faststart", "animation.mp4"], check=True)

더 부드러운 움직임을 위해 이징(예: t*t*(3-2*t))을 사용하세요.

4.13 MoviePy (빠른 고급 편집)

from moviepy import VideoFileClip, TextClip, CompositeVideoClip, concatenate_videoclips, AudioFileClip

clip1 = VideoFileClip("a.mp4").subclipped(0, 5)
clip2 = VideoFileClip("b.mp4").subclipped(2, 8)
video = concatenate_videoclips([clip1, clip2], method="compose")
music = AudioFileClip("music.mp3")
video = video.with_audio(music.subclipped(0, min(video.duration, music.duration)))   # 음악이 더 짧을 수 있음
video.write_videofile("out.mp4", fps=30, codec="libx264", audio_codec="aac", preset="veryfast")

(MoviePy 2.x API가 표시되었습니다. 1.x는 subclip/set_audio를 사용합니다. pip show moviepy로 확인하세요.)


5. 전달 전 확인

확인 없이 비디오를 절대 전달하지 마세요:

# 지속 시간, 해상도, 코덱, fps
ffprobe -v error -show_entries format=duration:stream=codec_name,width,height,r_frame_rate -of default=nw=1 out.mp4

# 주요 순간에 정지 프레임을 추출하여 확인
ffmpeg -ss 1 -i out.mp4 -frames:v 1 check_1s.png
ffmpeg -i out.mp4 -vf "fps=1/3,scale=480:-1,tile=4x2" -frames:v 1 contact_sheet.png

체크리스트:

  • 지속 시간이 계획과 일치
  • 해상도와 화면 비율이 올바르며, 원치 않는 검은 막대나 늘어짐이 없음
  • 텍스트를 읽을 수 있고 안전 여백 내에 있음(가장자리에서 약 5% 유지, 9:16의 경우 앱 UI가 있는 하단 약 15%는 피함)
  • 전환이 의도한 위치에 적용됨
  • 오디오가 있음(예상되는 경우), 클리핑되지 않고 깔끔하게 끝남
  • 휴대폰에서 재생 가능: H.264, yuv420p, 짝수 치수

6. 일반적인 문제

문제해결책
iPhone/QuickTime에서 비디오가 재생되지 않음-pix_fmt yuv420p 추가
"width not divisible by 2"-1 대신 scale=1280:-2 사용
-c copy 자르기 후 시작 부분에 검은 프레임재인코딩하거나 -ss를 -i 앞에 두고 재인코딩
concat 후 오디오 동기화 불일치결합 전에 fps와 오디오 샘플 레이트(-ar 48000) 정규화
xfade 오류 "inputs differ"모든 입력의 크기, fps, setsar=1, 픽셀 형식이 동일해야 함
drawtext가 ' 또는 :에서 깨짐이스케이프하거나 textfile= / Pillow로 렌더링된 PNG 오버레이 사용
영어가 아닌 텍스트가 네모로 표시됨해당 스크립트를 지원하는 글꼴 사용(예: Noto Sans Devanagari)
파일 크기가 너무 큼CRF를 높이고(26~28), fps 또는 해상도를 낮춤
렌더링이 너무 느림-preset veryfast 또는 ultrafast 사용, 초안 작성 중에는 해상도 낮춤

7. 워크플로 요약

  1. 계획 — 화면 비율, fps, 길이, 쇼트 리스트, 오디오.
  2. 에셋 수집 — 이미지, 클립, 음악, 글꼴; ffprobe로 확인.
  3. 빠른 초안 — 낮은 해상도 / ultrafast 프리셋으로 타이밍 확인.
  4. 최종 제작 — 표준 인코딩 설정(섹션 3).
  5. 검증 — ffprobe + 접촉 시트 + 체크리스트(섹션 5).
  6. 전달 — 최종 파일과 함께 한 줄 요약(지속 시간, 해상도, 포함 내용) 전송.

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

관련 스킬