जिस संख्या ने आखिर इस अनुकूलन को ठोस बनाया, वह बहुत सीधी थी: जिस वास्तविक संचालन वीडियो पर मैं नज़र रख रहा था, नई H.264 नीति के बाद वह लगभग 280 MB से 50 MB रह गया। यानी करीब 5.6× छोटा, लगभग 230 MB की बचत, या मूल फ़ाइल आकार से करीब 82% कम।
यह परिणाम AV1, HEVC या VP9 पर जाने से नहीं आया। वास्तविक संचालन परिणाम MP4 के अंदर H.264 ही रहा। बदली कोडेक के आसपास की नीति थी: गैरज़रूरी पिक्सेल कम, बेकार कालिक नमूने कम, काफ़ी कम सावधान गुणवत्ता लक्ष्य, एक बार होने वाले एन्कोडिंग चरण में अधिक CPU, और जानबूझकर सीमित डिकोडिंग आवश्यकताएँ।
यह बहुत विशिष्ट उपयोग-परिदृश्य था: छोटे चित्रित और एनिमेटेड वीडियो, लगभग 80% उपयोग मोबाइल उपकरणों से, बैंडविड्थ एक बार-बार आने वाली लागत, और पूर्व एन्कोडिंग जहाँ समय बार-बार अत्यधिक बड़ी फ़ाइलें प्रदान करने की लागत के सामने सस्ता है।
पुरानी और नई नीति लगभग ऐसी थीं:
पुराना विन्यास
H.264 Main @ Level 4.0
CRF 19
पूर्वनिर्धारित मान slow
1920x1080 / 1080x1920 तक
30 fps
refs = 3
B-फ्रेम = 3
GOP ≈ 2 सेकंड
VBV ≈ 10M / 20M
नया विन्यास
H.264 Main @ Level 3.1
CRF 28
पूर्वनिर्धारित मान veryslow
720p-श्रेणी की अधिकतम सीमा, कोई बढ़ाना नहीं
उपयोगी CFR, सामान्यतः <= 30 fps
refs = 4
B-फ्रेम = 5
GOP ≈ 5 सेकंड
VBV ≈ 4M / 8M
yuv420p / avc1 / faststart
मापा हुआ परिणाम: लगभग 280 MB से लगभग 50 MB
मेरे पास कई वास्तविक संचालन माप हैं, लेकिन वे सभी एक ही प्रयोग नहीं हैं। सबसे बड़ा प्रतिशत दिखाने के बजाय इन श्रेणियों को अलग रखना ज्यादा जरूरी है।
| माप | पहले | बाद में | कमी |
|---|---|---|---|
| वही ठोस वीडियो | ~280 MB | ~50 MB | ~5.6× छोटा / ~82% कम |
| उसी फ़ाइल का पुराना चरण | ~350 MB | ~238 MB | ~1.47× छोटा / 32% कम |
पहली पंक्ति शीर्षक का सबसे साफ प्रमाण है। वही वास्तविक वीडियो नई नीति से पहले और बाद में: लगभग 280 MB से लगभग 50 MB। उस ठीक उसी जोड़ी की बिट दर/अवधि पंक्ति पुनर्प्राप्त अभिलेख में नहीं मिली, इसलिए मैं उसे गढ़ता नहीं हूँ। आकार बदलाव अपने आप पर्याप्त है: यह विशिष्ट फ़ाइल करीब 5.6 गुना छोटी हुई।
~350→238 MB उदाहरण उसी फ़ाइल का पहले का अनुकूलन चरण था। परिणामी वीडियो लगभग 1264×720, 30 fps, करीब 500 सेकंड, बिना ध्वनि और लगभग 3.8 Mbps था। गणना देखे गए आकार से मेल खाती है: 3.8 Mbps × लगभग 500 सेकंड ≈ 238 MB। ~350 MB से 32% बचत पहले ही मिल चुकी थी, लेकिन मेरे बैंडविड्थ लक्ष्य के लिए 238 MB अभी भी बहुत बड़ा था।
पुराने संग्रह की जाँच ने भी दिखाया कि अत्यधिक बड़ी H.264 कोई एक अजीब अपवाद नहीं था। एक जाँच में 238 वास्तविक संचालन वीडियो फ़ाइलें कुल 6.37 GB थे: 117 H.264 और 121 AV1। इनमें 101 फ़ाइलें कम से कम 20 MB और 34 कम से कम 50 MB थीं। कुछ बड़े H.264 उदाहरण:
| आकार | अवधि | औसत बिट दर |
|---|---|---|
| 121.0 MB | 4:25 | 3.83 Mbps |
| 101.2 MB | 5:19 | 2.659 Mbps |
| 92.78 MB | 4:44 | 2.735 Mbps |
| 90.10 MB | 3:55 | 3.206 Mbps |
| 89.74 MB | 4:41 | 2.676 Mbps |
ये अलग-अलग सामग्री वाले वीडियो हैं, इसलिए यह तालिका संदर्भ देती है, सीधी पहले-बाद की तुलना परीक्षण नहीं। फिर भी इससे साफ है कि पुराना 3.8 Mbps उदाहरण कोई अकेला अपवाद नहीं था: पुरानी लाइब्रेरी की कई बड़ी H.264 फ़ाइलें वास्तव में लगभग 2.6–3.8 Mbps के दायरे में थीं।
सबसे महत्वपूर्ण अनुकूलन FFmpeg का कोई एक विकल्प नहीं था
सबसे बड़ा बदलाव लागत को देखने के मेरे तरीके में था।
एन्कोडिंग एक बार होती है। फ़ाइल हर बार भेजी जाती है जब कोई उसे माँगता है।
वास्तविक समय के वीडियो में थोड़ी बिट दर बचाने के लिए बहुत ज़्यादा CPU खर्च करना खराब सौदा हो सकता है। मेरी फ़ाइलें ऑफ़लाइन एन्कोड होती हैं और फिर बार-बार परोसी जाती हैं। इस मॉडल में एन्कोडिंग के दस मिनट बचाने का आर्थिक मतलब लगभग नहीं रह जाता, अगर तेज़ एन्कोडिंग भविष्य के हर अनुरोध को बड़ा कर दे।
इसीलिए -preset veryslow मेरे लिए सही है। अगर x264 अधिक CPU लगाकर ज़्यादा कुशल प्रतिनिधित्व ढूँढ सकता है, तो मैं वह खर्च एक बार करने को तैयार हूँ। ब्राउज़र एन्कोडर की खोज दोबारा नहीं करता; वह केवल तैयार बिटस्ट्रीम को डिकोड करता है।
नियम सरल हो गया: जो चरण केवल एक बार होता है उसमें गणना खर्च करो, और जो चरण बार-बार होता है उसमें बाइट बचाओ।
नए कोडेक के पीछे भागने के बजाय मैं H.264 पर क्यों रहा
मैं यह दावा नहीं कर रहा कि H.264 सबसे बेहतर संपीड़न देने वाला कोडेक है। ऐसा नहीं है। नए कोडेक तब बहुत उपयोगी हो सकते हैं जब वितरण प्रणाली कई संस्करण रख सके और हर उपकरण के लिए सबसे उपयुक्त विकल्प चुने।
मेरी सीमा अलग थी: एक URL, एक फ़ाइल, एक कोडेक, और मोबाइल-प्रधान दर्शकों के लिए जितनी कम संभव हो उतनी चलाने की समस्याएँ।
इस काम के लिए MP4 में H.264 अब भी बहुत सुरक्षित आधार है। Apple अभी वेबसाइट बनाने वालों को Safari में स्थिर वीडियो के लिए H.264 से एन्कोड की गई MP4 फ़ाइलें इस्तेमाल करने की सलाह देता है। Android की मौजूदा दस्तावेज़ी जानकारी MP4 में H.264 को सूचीबद्ध करती है और Android 6.0 तथा उसके बाद Main प्रोफ़ाइल डिकोडर आवश्यक बताती है; H.264 प्लेबैक सिफ़ारिशों में HD के लिए 1280×720 पर 30 fps भी दिया गया है, साथ ही यह नोट भी है कि हर डिवाइस पर HD उपलब्ध नहीं है। Android के समर्थित मीडिया प्रारूप देखें।
इसका मतलब यह नहीं कि आधुनिक डिवाइस केवल Main प्रोफ़ाइल या स्तर 3.1 तक सीमित हैं। उदाहरण के लिए Apple के HLS दिशानिर्देश सामान्यतः Main या Baseline प्रोफ़ाइल की तुलना में High प्रोफ़ाइल को प्राथमिकता देते हैं। मैंने Main@3.1 इसलिए चुना क्योंकि एक स्थिर MP4 के लिए जानबूझकर कम डिकोडर आवश्यकताएँ चाहता था, इसलिए नहीं कि Apple इसे अनिवार्य करता है।
मैंने उन पिक्सेल को एन्कोड करना बंद किया जिनकी ज़रूरत ही नहीं थी
रेज़ोल्यूशन सबसे बड़े प्रभावों में से एक था। मेरी सीमा लैंडस्केप के लिए लगभग 1280×720, पोर्ट्रेट के लिए 720×1280, और वर्गाकार या मिश्रित दिशा वाली सामग्री के लिए लगभग 960×960 बन गई।
ज़्यादा महत्वपूर्ण नियम यह है: सिर्फ सीमा तक पहुँचने के लिए कभी आकार मत बढ़ाओ।
अगर स्रोत 900×600 है, तो उसे 1280×720 करना विवरण वापस नहीं लाता। इससे केवल ज़्यादा नमूने बनते हैं जिन्हें एन्कोडर को वर्णन करना पड़ता है। 1920×1080 स्रोत को 720p श्रेणी तक घटाया जा सकता है, जबकि 900×600 स्रोत लगभग 900×600 ही रह सकता है। सीमा अधिकतम है, लक्ष्य नहीं।
यह सरल लगता है, लेकिन अनावश्यक पिक्सेल हटाना कई जटिल एन्कोडर बदलावों से ज़्यादा असर डाल सकता है।
यह अधिकतम सीमा केवल गोल संख्या होने के कारण नहीं चुनी गई। 1920×1080 के एक फ्रेम में 2,073,600 पिक्सेल होते हैं, जबकि 1280×720 में 921,600। इसलिए 1080p से 720p पर आने से एन्कोडर के संपीड़न निर्णय शुरू होने से पहले ही लगभग 55.6% स्थानिक नमूने हट जाते हैं।
मैंने 540p को भी सार्वभौमिक विकल्प बनाने पर विचार किया। लेकिन 960×540 में केवल 518,400 पिक्सेल होते हैं—1280×720 से 43.75% कम—अर्थात 720p के केवल 56.25% नमूने बचते हैं। चित्रित सामग्री में यही नमूने पतली रेखाएँ, आँखें, बाल, उँगलियाँ, चेहरे और तीखे किनारे बनाते हैं। यदि मुझे अभी भी कम बाइट चाहिए, तो मैं बिना माप के 43.75% और स्थानिक जानकारी हटाने से पहले थोड़ा अधिक CRF जाँचूँगा। क्वांटीकरण को अगली एन्कोडिंग में बदला जा सकता है; घटाई गई रेजोल्यूशन से मिटा विवरण पहले ही जा चुका होता है।
इसलिए 720p-श्रेणी मेरी सावधान सामान्य अधिकतम सीमा है; इसका अर्थ यह नहीं कि 540p खराब है। किसी खास फ़ाइल के लिए मापी गई 540p प्रति बेहतर हो सकती है। मैं बस प्रमाण के बिना इस अपरिवर्तनीय स्थानिक कटौती को पूरी लाइब्रेरी का नियम नहीं बनाता।
मैंने उन फ़्रेमों के लिए बैंडविड्थ देना बंद किया जो स्रोत में वास्तव में थे ही नहीं
फ़्रेम रेट भी एक गुणक है। अगर किसी एनिमेशन में प्रति सेकंड लगभग 16 उपयोगी दृश्य अवस्थाएँ हैं, तो उसे 30 या 60 fps पर सहेजना अपने-आप बेहतर गति नहीं बनाता। अक्सर इससे केवल दोहराए गए या कृत्रिम समय-नमूने बढ़ते हैं, जिन्हें फिर भी एन्कोड करना पड़ता है।
मेरी नीति स्रोत की उपयोगी लय को बचाए रखना और सामान्यतः 30 fps या उससे कम रहना है। इस तरह की सामग्री में 12, 15, 16, 18, 20, 24, 25 या 30 fps सभी सही हो सकते हैं, अगर वे सच में स्रोत को दर्शाते हैं।
तैयार फ़ाइल में मुझे साफ़ स्थिर फ़्रेम रेट भी पसंद है। VFR अपने-आप खराब नहीं है; CFR मेरी प्रसंस्करण प्रक्रिया में समय-मुद्राएँ, फ़्रेम गिनती, अवधि जाँच, आगे-पीछे जाना और बाद की जाँच को बस आसान बनाता है।
सामान्य सिद्धांत किसी एक FPS मान से अधिक उपयोगी है: स्रोत में मौजूद न होने वाली समय-संबंधी जानकारी के लिए बैंडविड्थ मत दो।
CRF 28 मेरे काम के लिए चुना गया मान है, कोई जादुई संख्या नहीं
मैं हर क्लिप को एक ही लक्ष्य बिटरेट की ओर धकेलना नहीं चाहता था। लगभग स्थिर चित्र और जटिल गति वाले दृश्य को स्वीकार्य दिखने के लिए समान संख्या में बिट नहीं चाहिए।
इसलिए मैं x264 का CRF मोड इस्तेमाल करता हूँ और बैंडविड्थ को प्राथमिकता देने वाली इस चित्रित सामग्री के लिए लगभग -crf 28 पर पहुँचा। FFmpeg, libx264 में CRF को स्थिर-गुणवत्ता आधारित बिट-दर नियंत्रण के रूप में दर्ज करता है; FFmpeg की कोडेक दस्तावेज़ी जानकारी देखें।
CRF 28 जानबूझकर आक्रामक है। मैं इसे फ़िल्म ग्रेन, शोर वाले कैमरा फुटेज, बहुत छोटे स्क्रीन टेक्स्ट, या ऐसे काम पर आँख बंद करके नहीं लगाऊँगा जहाँ चित्र-निष्ठा बैंडविड्थ से अधिक महत्वपूर्ण हो।
मेरे पास कोई सार्वभौमिक धारणा-आधारित स्कोर भी नहीं है जो साबित करे कि CRF 28 आँख को बिल्कुल पारदर्शी है। अपनी सामग्री के बारे में मैं इससे सीमित बात कह सकता हूँ: फ़ाइलें बहुत छोटी हुईं और सामान्य प्लेबैक में मुझे फिर भी सामान्य दिखीं। यह व्यावहारिक अवलोकन है, यह दावा नहीं कि CRF 28 दृश्य रूप से दोषरहित है।
veryslow एन्कोडर के लिए महँगा है, डिकोडर के लिए अपने-आप नहीं
मेरा प्रीसेट -preset veryslow है। धीमा प्रीसेट x264 को कुशल पूर्वानुमान और कोडिंग निर्णय खोजने का अधिक मौका देता है। कीमत एन्कोडर CPU और समय है।
महत्वपूर्ण अंतर यह है कि एन्कोडर की मेहनत और डिकोडर की जटिलता एक ही चीज़ नहीं हैं।
मैं x264 को बहुत मेहनत करने दे सकता हूँ और तैयार स्ट्रीम को अलग से सीमित कर सकता हूँ। मेरी संयमित परिणाम-सीमाएँ ये हैं:
H.264, Main प्रोफ़ाइल
Level 3.1
8-बिट yuv420p
avc1
refs = 4
B-फ्रेम = 5
B-pyramid = normal
खुला GOP = बंद
FFmpeg, CRF, प्रीसेट, सामग्री-विशिष्ट ट्यूनिंग, प्रोफ़ाइल सीमाएँ, संदर्भ फ़्रेम और B-फ्रेम को अलग-अलग नियंत्रित करने देता है। मैं भी इन्हें उसी तरह देखता हूँ: एन्कोडर को गहरी खोज करने दो, लेकिन प्लेबैक पक्ष साधारण रखो।
GOP और VBV सुरक्षा सीमाएँ हैं, मुख्य गुणवत्ता नियंत्रण नहीं
इन छोटे प्रोग्रेसिव वीडियो के लिए मैं लगभग पाँच सेकंड का अधिकतम GOP रखता हूँ: 30 fps पर लगभग -g 150, 24 fps पर -g 120, या 16 fps पर -g 80।
यह मेरे काम के लिए चयन है, सार्वभौमिक नियम नहीं। अनुकूली धारा-प्रेषण की सीमाएँ अलग हैं; उदाहरण के लिए Apple के HLS लेखन दिशानिर्देश हर दो सेकंड में IDR की सलाह देते हैं। मैं उस HLS नियम को छोटी स्थिर प्रोग्रेसिव MP4 फ़ाइलों पर आँख बंद करके लागू नहीं करता।
मैं लगभग ये मान भी इस्तेमाल करता हूँ:
-maxrate:v 4M
-bufsize:v 8M
ये मान असामान्य बिटरेट उछाल के खिलाफ सीमा हैं। इनका मतलब “हर चीज़ को 4 Mbps पर एन्कोड करो” नहीं है। सामान्य बिट आवंटन अभी भी CRF करता है, इसलिए सरल वीडियो बहुत छोटे रह सकते हैं।
मैंने MP4 कंटेनर को भी जानबूझकर साधारण रखा
मैं साफ़ तौर पर avc1 इस्तेमाल करता हूँ। Apple की मौजूदा HLS दस्तावेज़ी जानकारी avc3 की जगह avc1 जैसे नमूना प्रारूप की सलाह देती है। इससे मेरी फ़ाइलें छोटी नहीं हुईं, लेकिन यह पारंपरिक MP4 में H.264 आउटपुट के लक्ष्य से मेल खाता है।
मैं -movflags +faststart भी इस्तेमाल करता हूँ। FFmpeg की फ़ॉर्मेट दस्तावेज़ी जानकारी के अनुसार faststart MP4 के moov इंडेक्स को फ़ाइल की शुरुआत में ले जाता है। Android की HTTP धारा-प्रेषण आवश्यकताएँ भी MPEG-4 के लिए कहती हैं कि moov, ftyp के बाद और mdat से पहले होना चाहिए।
ftyp
moov
mdat
Faststart कम्प्रेशन बेहतर नहीं करता। यह प्रोग्रेसिव HTTP प्लेबैक को आसान बनाता है।
सामान्य SDR आउटपुट के लिए मैं 8-बिट yuv420p इस्तेमाल करता हूँ और BT.709 को सीमित वीडियो दायरा के साथ सिग्नल करता हूँ। अगर वीडियो में ध्वनि नहीं है तो मैं ध्वनि पट्टी नहीं बनाता। चित्रित सामग्री के लिए -tune animation भी इस्तेमाल करता हूँ; इसे सामग्री-विशिष्ट चयन मानता हूँ, सार्वभौमिक संगतता अनुबंध का हिस्सा नहीं।
मुख्य FFmpeg प्रोफ़ाइल
30 fps चित्रित स्रोत के लिए कमांड का मुख्य हिस्सा लगभग ऐसा दिखता है:
ffmpeg -i input \
-c:v libx264 \
-preset veryslow \
-tune animation \
-crf 28 \
-profile:v main \
-level:v 3.1 \
-pix_fmt yuv420p \
-tag:v avc1 \
-refs 4 \
-bf 5 \
-g 150 \
-maxrate:v 4M \
-bufsize:v 8M \
-x264-params "open-gop=0:b-pyramid=normal:nal-hrd=none" \
-color_range tv \
-color_primaries bt709 \
-color_trc bt709 \
-colorspace bt709 \
-an \
-movflags +faststart \
output.mp4
आकार बदलने और फ़्रेम-दर के चरण यहाँ जानबूझकर स्थायी रूप से तय नहीं किए गए हैं। 900×600 स्रोत को सिर्फ इसलिए बड़ा नहीं करना चाहिए कि सीमा 1280×720 है, और स्वाभाविक रूप से कम फ़्रेम-रेट वाली एनिमेशन को सिर्फ इसलिए 30 fps पर मजबूर नहीं करना चाहिए कि उदाहरण में -g 150 है।
कमांड नीति का कार्यान्वयन है; नीति खुद नहीं।
फ़ाइलें कई गुना छोटी क्यों हुईं
कोई जादुई विकल्प नहीं था।
कमी कई फैसलों के मेल से आई, जिनमें हर एक ने अलग तरह की बर्बादी हटाई: अनावश्यक पिक्सेल, अनावश्यक फ्रेम, जरूरत से ज्यादा सावधान गुणवत्ता लक्ष्य, दक्षता के बजाय गति को प्राथमिकता देने वाली एन्कोडर सेटिंग, बहुत बार आने वाले मुख्य फ़्रेम और वे डेटा-प्रवाह जिनकी मुझे जरूरत नहीं थी।
इसीलिए “यह फ़ाइल H.264 है” उसके आकार के बारे में बहुत कम बताता है। एक ही स्रोत के दो H.264 एन्कोड बहुत अलग हो सकते हैं, क्योंकि कोडेक का नाम रेज़ोल्यूशन, फ़्रेम रेट, बिट-दर नियंत्रण, प्रीसेट, GOP संरचना, प्रोफ़ाइल या स्रोत की तैयारी नहीं बताता।
मेरे मामले में कोडेक के आसपास के ये निर्णय बदलना कोडेक बदलने से ज़्यादा महत्वपूर्ण था।
यह नतीजा क्या साबित नहीं करता
मैंने हर सेटिंग को नियंत्रित प्रयोग में अलग-अलग नहीं परखा, इसलिए ईमानदारी से नहीं बता सकता कि बचत का सटीक प्रतिशत veryslow, CRF 28, रेज़ोल्यूशन में कमी या फ़्रेम-रेट में कमी से अलग-अलग कितना आया।
मैं यह भी दावा नहीं कर सकता कि हर CRF 28 आउटपुट धारणा के स्तर पर पूरी तरह पारदर्शी है। “कोई स्पष्ट गुणवत्ता गिरावट नहीं” सामान्य देखने के आकार पर इस चित्रित सामग्री के लिए मेरा अवलोकन है, किसी भी वीडियो के लिए वैज्ञानिक गारंटी नहीं।
और मैं यह नहीं कह रहा कि एक H.264 फ़ाइल हर साइट के लिए सही संरचना है। कई रेंडिशन, अनुकूली धारा-प्रेषण, HDR, 4K और कोडेक चयन समझौते बदलते हैं।
मैं वास्तव में इससे सीमित दावा कर सकता हूँ: बैंडविड्थ को प्राथमिकता देने वाली, मोबाइल-प्रधान, छोटे चित्रित और एनिमेटेड वीडियो की लाइब्रेरी में, जहाँ एन्कोडिंग समय सस्ता है और पूर्वानुमेय चलाना महत्वपूर्ण है, इस प्रोफ़ाइल ने मेरी फ़ाइलें कई गुना छोटी कीं और सामान्य प्लेबैक में वे फिर भी स्वाभाविक दिखीं।
इस परिणाम ने मेरी अनुकूलन रणनीति कैसे बदली
पहले मैं वीडियो अनुकूलन को मुख्यतः एन्कोडर विन्यास की समस्या मानता था। अब मैं इसे पूरे जीवनकाल की लागत की समस्या मानता हूँ।
एन्कोडर शायद एक बार चले। बाइट नेटवर्क पर हजारों या लाखों बार जा सकते हैं।
इससे “महँगा” का अर्थ बदल जाता है।
मैं CPU एक बार खर्च करने को तैयार हूँ। लेकिन हर भविष्य के अनुरोध में अपस्केल से बने पिक्सेल, उपयोगी गति न जोड़ने वाले फ़्रेम, या सामग्री को न चाहिए बिटरेट भेजने के लिए बहुत कम तैयार हूँ।
कोडेक साधारण ही रहा: MP4 में H.264। अनुकूलन उसके आसपास हुआ।
इस काम के लिए सबक किसी एक FFmpeg विकल्प से ज़्यादा स्पष्ट है: उस लागत को अनुकूलित करो जो बार-बार चुकानी पड़ती है, उस लागत को नहीं जो केवल एक बार चुकती है।