docs/
Outline
---
title: کات زدن یه ریل فریم به فریم با FFmpeg
slug: ghost-reel-ffmpeg
lang: fa
published: 2026-10-31
words: 487
lines: 84
size: 4.0 KB
read: 3 min read
reel: فتوشوت ارواح
---
واسه هالووین توی شرکت یه فتوشوت ارواح گرفتیم. ریل ۱۵ ثانیهست و پشتش هیچ پروژهی ادیتوری نیست، فقط یه اسکریپت bash دور FFmpeg. هدف این بود که موزیک یه ریل مرجع دستنخورده بمونه و هر کات دقیقاً روی همون فریم مرجع بیفته.
خروجی مورد نظر
1080x1920, 30 fps, 448 frames, 14.93 s
H.264 High, 14 Mbps, 2 pass, BT.709
AAC 44.1 kHz stereo, copied from the reference
-14.1 LUFS integrated
۱. کاتها رو از مرجع دربیار
ffmpeg -hide_banner -i ref.mp4 -vf "select='gt(scene,0.3)',showinfo" \
-an -f null - 2>&1 | grep -o 'pts_time:[0-9.]*'
1.2 2.8 5.5667 6.6667 8.1 9.1 10.0667 11.1333 11.9 13.0333 14.0667
این ۱۱ تا کات میشن ۱۲ تا شات. ضرب در ۳۰ میشه تعداد فریم و جمعشون باید ۴۴۸ بشه:
36 48 83 33 43 30 29 32 23 34 31 26
۲. هر شات رو دقیقاً به تعداد فریمش ببر
اول سه تا ویدیو، بعد هفت تا عکس، یه فریم از ویدیو و یه عکس آخر، هرکدوم به اندازهی فریم خودش. ویدیوهای iPhone، HDR هستن و اول باید tone map بشن:
HDR="zscale=t=linear:npl=203,tonemap=hable:desat=0,zscale=p=bt709:t=bt709:m=bt709:r=tv,format=yuv444p10le,"
FRAME="scale=1080:1920:force_original_aspect_ratio=increase:flags=lanczos,crop=1080:1920,setsar=1,fps=30,"
ffmpeg -ss 5.0 -i footage/IMG_0224.MOV -map 0:v:0 -an -frames:v 48 \
-vf "setpts=PTS-STARTPTS,$HDR$FRAME$GRADE" \
-c:v prores_ks -profile:v 4 seg02.mov
مستر ProRes 4444 هست تا قبل از خروجی نهایی هیچی دوبار فشرده نشه.
۳. گرید رنگ
یه زنجیرهی ثابت روی همهی شاتها میره تا عکس و ویدیو یکی بشن: کنتراست بیشتر، سایهی سردتر، هایلایت گرمتر، vignette و یه کم grain.
GRADE="eq=contrast=1.18:brightness=-0.07:saturation=1.12:gamma=0.92,\
colorbalance=rs=-0.06:gs=-0.01:bs=0.10:rm=0.05:gm=0:bm=-0.04:rh=0.12:gh=0.04:bh=-0.10,\
curves=all='0/0.02 0.25/0.16 0.6/0.6 1/0.95',vignette=PI/4.5,noise=alls=6:allf=t"
۴. موزیک رو کپی کن، encode نکن
ffmpeg -i master.mov -i ref.mp4 -map 0:v:0 -c:v libx264 -b:v 14M -pass 2 \
-map 1:a:0 -c:a copy -movflags +faststart final.mp4
کل ترفند همین -c:a copy هست. منبع فقط 61 kbps AAC بود و encode دوباره بدترش میکرد. یه hash ثابت میکنه صدا یکیه:
ffmpeg -i final.mp4 -map 0:a -c copy -f md5 -
ffmpeg -i ref.mp4 -map 0:a -c copy -f md5 -
MD5=83a5ab8a4bdbe164b11af5a516e95e44
MD5=83a5ab8a4bdbe164b11af5a516e95e44
چیزایی که خراب شد
یه فریم دیرتر. ویدیوی سوم به جای 0 از PTS 0.0333 شروع میشد. همین کاتهای ۴ تا ۱۱ رو یه فریم عقب انداخت و فریم آخر عکس آخر رو هم برد. setpts=PTS-STARTPTS اول زنجیره درستش کرد.
رنج رنگ اشتباه. overlay تیتر که RGBA بود کل تصویر رو برد روی full range و فایل yuvj420p تگ میخورد. خروجی نهایی به زور limited range BT.709 میشه.
کاتی که انگار نبود. scene detection با 0.3 فقط ۱۰ تا از ۱۱ کات رو پیدا کرد. کات آخر بین دو تا شات شبیه به همه و امتیازش کمتر شد. با 0.05 پیدا میشه و اختلاف فریمها هم نشون میده کات دقیقاً سر جاشه.
چرا با اسکریپت
خود اسکریپت همون ادیته. اگه یه شات عوض بشه، یه خط رو عوض میکنم و دوباره رندر میگیرم و هر بار همون چکها اجرا میشن: زمان کاتها، تعداد فریم، hash صدا و loudness.
| واسه هالووین توی شرکت یه فتوشوت ارواح گرفتیم. ریل ۱۵ ثانیهست و پشتش هیچ پروژهی ادیتوری نیست، فقط یه اسکریپت bash دور FFmpeg. هدف این بود که موزیک یه ریل مرجع دستنخورده بمونه و هر کات دقیقاً روی همون فریم مرجع بیفته. |
| ## خروجی مورد نظر |
| ```text |
| 1080x1920, 30 fps, 448 frames, 14.93 s |
| H.264 High, 14 Mbps, 2 pass, BT.709 |
| AAC 44.1 kHz stereo, copied from the reference |
| -14.1 LUFS integrated |
| ``` |
| ## ۱. کاتها رو از مرجع دربیار |
| ```bash |
| ffmpeg -hide_banner -i ref.mp4 -vf "select='gt(scene,0.3)',showinfo" \ |
| -an -f null - 2>&1 | grep -o 'pts_time:[0-9.]*' |
| ``` |
| ```text |
| 1.2 2.8 5.5667 6.6667 8.1 9.1 10.0667 11.1333 11.9 13.0333 14.0667 |
| ``` |
| این ۱۱ تا کات میشن ۱۲ تا شات. ضرب در ۳۰ میشه تعداد فریم و جمعشون باید ۴۴۸ بشه: |
| ```text |
| 36 48 83 33 43 30 29 32 23 34 31 26 |
| ``` |
| ## ۲. هر شات رو دقیقاً به تعداد فریمش ببر |
| اول سه تا ویدیو، بعد هفت تا عکس، یه فریم از ویدیو و یه عکس آخر، هرکدوم به اندازهی فریم خودش. ویدیوهای iPhone، HDR هستن و اول باید tone map بشن: |
| ```bash |
| HDR="zscale=t=linear:npl=203,tonemap=hable:desat=0,zscale=p=bt709:t=bt709:m=bt709:r=tv,format=yuv444p10le," |
| FRAME="scale=1080:1920:force_original_aspect_ratio=increase:flags=lanczos,crop=1080:1920,setsar=1,fps=30," |
| ffmpeg -ss 5.0 -i footage/IMG_0224.MOV -map 0:v:0 -an -frames:v 48 \ |
| -vf "setpts=PTS-STARTPTS,$HDR$FRAME$GRADE" \ |
| -c:v prores_ks -profile:v 4 seg02.mov |
| ``` |
| مستر ProRes 4444 هست تا قبل از خروجی نهایی هیچی دوبار فشرده نشه. |
| ## ۳. گرید رنگ |
| یه زنجیرهی ثابت روی همهی شاتها میره تا عکس و ویدیو یکی بشن: کنتراست بیشتر، سایهی سردتر، هایلایت گرمتر، vignette و یه کم grain. |
| ```bash |
| GRADE="eq=contrast=1.18:brightness=-0.07:saturation=1.12:gamma=0.92,\ |
| colorbalance=rs=-0.06:gs=-0.01:bs=0.10:rm=0.05:gm=0:bm=-0.04:rh=0.12:gh=0.04:bh=-0.10,\ |
| curves=all='0/0.02 0.25/0.16 0.6/0.6 1/0.95',vignette=PI/4.5,noise=alls=6:allf=t" |
| ``` |
| ## ۴. موزیک رو کپی کن، encode نکن |
| ```bash |
| ffmpeg -i master.mov -i ref.mp4 -map 0:v:0 -c:v libx264 -b:v 14M -pass 2 \ |
| -map 1:a:0 -c:a copy -movflags +faststart final.mp4 |
| ``` |
| کل ترفند همین `-c:a copy` هست. منبع فقط 61 kbps AAC بود و encode دوباره بدترش میکرد. یه hash ثابت میکنه صدا یکیه: |
| ```bash |
| ffmpeg -i final.mp4 -map 0:a -c copy -f md5 - |
| ffmpeg -i ref.mp4 -map 0:a -c copy -f md5 - |
| ``` |
| ```text |
| MD5=83a5ab8a4bdbe164b11af5a516e95e44 |
| MD5=83a5ab8a4bdbe164b11af5a516e95e44 |
| ``` |
| ## چیزایی که خراب شد |
| **یه فریم دیرتر.** ویدیوی سوم به جای 0 از PTS 0.0333 شروع میشد. همین کاتهای ۴ تا ۱۱ رو یه فریم عقب انداخت و فریم آخر عکس آخر رو هم برد. `setpts=PTS-STARTPTS` اول زنجیره درستش کرد. |
| **رنج رنگ اشتباه.** overlay تیتر که RGBA بود کل تصویر رو برد روی full range و فایل `yuvj420p` تگ میخورد. خروجی نهایی به زور limited range BT.709 میشه. |
| **کاتی که انگار نبود.** scene detection با 0.3 فقط ۱۰ تا از ۱۱ کات رو پیدا کرد. کات آخر بین دو تا شات شبیه به همه و امتیازش کمتر شد. با 0.05 پیدا میشه و اختلاف فریمها هم نشون میده کات دقیقاً سر جاشه. |
| ## چرا با اسکریپت |
| خود اسکریپت همون ادیته. اگه یه شات عوض بشه، یه خط رو عوض میکنم و دوباره رندر میگیرم و هر بار همون چکها اجرا میشن: زمان کاتها، تعداد فریم، hash صدا و loudness. |





