با سلام و احترام خدمت بازدیدکنندگان عزیز
آموزش و آشنایی با نرم افزار FFmpeg – قسمت هشتم – فیلترها یا Filtergraph (سه)
برای مشاهده قسمت اول به
این پست
مراجعه نمایید.
برای مشاهده قسمت دوم به
این پست
مراجعه نمایید.
برای مشاهده قسمت سوم به
این پست
مراجعه نمایید.
برای مشاهده قسمت چهارم به
این پست
مراجعه نمایید.
برای مشاهده قسمت پنجم به
این پست
مراجعه نمایید.
برای مشاهده قسمت ششم به
این پست
مراجعه نمایید.
برای مشاهده قسمت هفتم به
این پست
مراجعه نمایید.
فیلتر گذاری از نوع پیچیده (Complex Filtergraph):
فیلترگراف پیچیده چیزی مانند فیلترچِین که در دو قسمت گذشته مشاهده کردیم میباشد. با این تفاوت که برخلاف سوئیچ
-filter
، برای یک نوع استریم خاص و یک استریم با یک اندیس خاص تعریف نمیشود. بلکه یک سوئیچ کلی هست (
-filter_complex
یا مشابه اون که
-lavfi
هست) و تفاوتش این است که برای چند استریم بصورت همزمان استفاده میشود. یک سوئیچ برای همه. یعنی 1 یا بیش از 1 استریم میتواند ورودی بگیرد و 1 یا بیش از 1 استریم خروجی بدهد. صرف نظر از نوع استریم. مثلا یک استریم صدا به عنوان ورودی بگیرد و سه کپی از آن تولید کند و به هر یک از آنها فیلترهای جداگانهای اعمال کند و در نهایت، سه استریم صدا خروجی بدهد یا دوتایشان را باهم میکس کند و دو استریم خروجی بدهد و در همین زمان یک استریم ویدئویی بگیرد و فیلتر گذاری کند و خروجی بدهد. این سوئیچ حتی میتواند هیچ ورودی بواسطه سوئیچ
-i
دریافت نکند اما به تعداد دلخواه خروجی بدهد. به این ترتیب که از طریق خود فیلترها، ورودی مصنوعی تولید کند یا از روی فایل واقعی مستقیما بخواند. یعنی فیلترهای نوع
|->N و |->A و |->V
مانند movie و rgbtestsrc و sine و...
مدیریت استریمها در
-filter_complex
:
مدیریت استریمها در داخل آن بوسیله لیبل گذاری (تقریباً مانند همان مَپ کردن که در پستهای ابتدایی مبحث آموختیم) انجام میگیرد. برخی از فیلترهای FFmpeg حتما به دو ورودی نیاز دارند. مثلا فیلتر overlay یا فیلتر sidechaincompress هردو به دو استریم ورودی نیاز داشته و به ترتیب از نوع
VV->V
و
AA->A
هستند. و در فیلتر گذاری ساده (مانند قسمتهای ششم و هفتم مبحث) اصلا نمیتوانند استفاده بشوند. در فیلترگراف پیچیده هر Filterchain یک "مجموعه" ورودی دارد و یک "مجموعه" خروجی که به ترتیب input pad و output pad آن فیلترچِین نامیده میشود. هر لیبل نیز باید به یک pad ورودی و یک pad خروجی متصل بشود.
در زیر مثالی بسیار ساده از نحوه لیبل گذاری اجرا میکنیم که در اون، یک فایل صوتی ac3 باز میکنیم و دو خروجی جداگانه یکی با فرمت ac3 و یکی با فرمت opus ازش میگیریم بصورت همزمان:
FFmpeg -i ".\samples\audio 2ch 256k.ac3" -filter_complex [0:a:0]asplit[seda_out1][seda_out2] -map [seda_out1] -b:a 448K ".\sample1.ac3" -map [seda_out2] -b:a 160K ".\sample2.opus"
نکته:
در نام لیبل، فقط از کارکترهای a تا z (هم بزرگ و هم کوچک) و 0 تا 9 و خط ربط یا همان "_" استفاده میکنیم و باید بین دوتا
"]" و "["
قرار داده بشود.
نکته 2:
فیلتر asplit برای گرفتن کپی از استریمهای صوتی استفاده میشه و مشابه اون فیلتر split هست که برای کپی استریمهای ویدئویی استفاده میشه و هردو به ترتیب از نوع
A->N
و
V->N
هستند. در مثال بعدی متوجه خواهید شد که چرا با این دو شروع کردیم.
نکته 3:
در مثال بالا ما بجای نوشتن
-map
همیشگی خودمون بعد از فایل ورودی، مقداری که جلوی اون مینوشتیم را (یعنی همان 0:a:0 را) بجای لیبل ورودی فیلتر asplit نوشتیم که شد input pad اون فیلترچِین.
نکته 4:
با تعیین دو لیبل بعد از asplit، بهش فهموندیم که ازش میخواهیم از چیزی که بهش ورودی دادیم دو کپی بدهد با لیبلهای seda_out1 و seda_out2. و در ادامه دیدید که لیبلهای خروجی را در مکانهای دلخواه با سوئیچ
-map
فراخوانی کردیم و در اصل output pad فیلترچِین را تعیین تکلیف کردیم. گاهی که تعداد لیبلها و فیلترهای شما زیاد میشود و فیلترگرافتون واقعا پیچیده میشود اگر فراموش کنید برای input pad و output pad حتی یکی از فیلترچِینها تعیین تکلیف کنید با خطا مواجه خواهید شد که جلوتر مثال آن آورده میشود.
مثال بعدی همان مثال بالایی هست منتهی این سری به هر کدام از خروجیهای asplit باز فیلترهای جداگانهای اعمال میکنیم:
FFmpeg -i ".\samples\audio 2ch 256k.ac3" -filter_complex [0:a:0]asplit[s1][s2];[s1]earwax[out1];[s2]vibrato=6.0,volume=-6dB[out2] -map [out1] -b:a 448K ".\sample1.ac3" -map [out2] -b:a 160K ".\sample2.opus"
نکته:
اول یک مقداری فکر کنید ببینید دلیل وجود فیلترهای asplit و split چیست... چرا از همون 0:a:0 در چند جا استفاده نشد...
...فکر...
...فکر...
دلیل این هست که در فیلترگراف پیچیده از هر لیبل فقط یکبار میشود استفاده کرد. توانایی استفاده از یک لیبل با نام یکسان در دوجای متفاوت وجود ندارد. یک لیبل باید یکبار بوجود بیاید و یکبار استفاده بشود. تنها بعد از اینکه مصرف شد، دوباره میتوان با همان نام لیبل جدید تعریف کرد و دوباره مصرف کرد. مثلا در مثال بالا s1 بوجود آمد و استفاده شد. حالا اگر در انتهای کل فیلترگراف باز بخواهید از همان s1 استفاده کنید (بدون تعریف مجددش) و مثلا out3 بگیرید با خطای
matches no stream
مواجه خواهید شد زیرا آن s1 دیگر مصرف شده و وجود ندارد. همچنین در نکتههای مثال قبلی از تعیین و تکلیف کردن padها گفته شد. برای امتحان میتوانید در دستور بالا یک s0 هم از فیلتر asplit بگیرید ولی ازش استفاده نکنید یعنی
[0:a:0]asplit=[s1][s2];
را به
[0:a:0]asplit=3[s0][s1][s2];
تغییر بدید و اجرا کنید تا خطای
Filter asplit:output0 has an unconnected output...
را مشاهده کنید.
البته در مواردی که حدس زدن برای FFmpeg راحت باشد، عملیات را با خطا مواجه نمیکند. مثلا زمانی که فیلترچِین آخر، فقط یک استریم خروجی دارد، و برای آن پد خروجی لیبل دار تعیین نکردهایم، FFmpeg خودش تشخیص میدهد که چگونه متصل کند. مانند مثال زیر:
FFmpeg -i ".\samples\audio 2ch 256k.ac3" -filter_complex [0:a:0]vibrato=6.0[s1];[s1]earwax,volume=-6dB -b:a 448K -y ".\sample1.ac3"
که در اون دیگه چون فقط یک جریان خروجی داشتیم، پد خروجی برای زنجیره آخر تعیین نکردیم و از دستور
-map
استفاده نکردیم.
بسیار خب، با تعریف Filterchain در قسمت ششم مبحث آشنا شدیم. در بالا نیز با تعریف
Filtergraph description
آشنا شدیم که مجموعهای از Filterchain هاست که با سِمی کالِن یا همان ";" از هم جدا شدند.