From 677bd1dc33dc36d3274f55f04aa231dbc47b63bd Mon Sep 17 00:00:00 2001 From: John Andrews Date: Thu, 19 May 2022 18:24:56 +1200 Subject: [PATCH] improved ffmpeg builde encoder node and added unit tests --- Apprise/Apprise.csproj | Bin 1338 -> 2760 bytes BasicNodes/BasicNodes.csproj | Bin 1839 -> 3778 bytes ChecksumNodes/ChecksumNodes.csproj | Bin 1399 -> 2872 bytes CollectionNodes/CollectionNodes.csproj | Bin 1585 -> 3256 bytes DiscordNodes/DiscordNodes.csproj | Bin 1393 -> 2870 bytes EmailNodes/EmailNodes.csproj | Bin 1646 -> 3386 bytes Emby/Emby.csproj | Bin 1380 -> 2844 bytes FileFlows.Plugin.dll | Bin 41472 -> 42496 bytes FileFlows.Plugin.pdb | Bin 22276 -> 22896 bytes Gotify/Gotify.csproj | Bin 1334 -> 2752 bytes ImageNodes/ImageNodes.csproj | Bin 1570 -> 3232 bytes MetaNodes/MetaNodes.csproj | Bin 2197 -> 4504 bytes MusicNodes/MusicNodes.csproj | Bin 2060 -> 4228 bytes Plex/Plex.csproj | Bin 1380 -> 2844 bytes .../FfmpegBuilderNodes/FfmpegBuilderNode.cs | 3 +- .../FfmpegBuilderNodes/FfmpegBuilderStart.cs | 1 + .../Video/FfmpegBuilderVideoEncode.cs | 95 +- .../FfmpegBuilder_BasicTests.cs | 1899 ++++++++--------- .../FfmpegBuilder_VideoEncodeTests.cs | 83 + VideoNodes/Tests/_TestBase.cs | 4 + VideoNodes/VideoNodes.csproj | Bin 1999 -> 4098 bytes VideoNodes/VideoNodes.en.json | 1105 +++++----- .../PluginInfoGenerator/FileFlows.Plugin.dll | Bin 41472 -> 42496 bytes .../PluginInfoGenerator/FileFlows.Plugin.pdb | Bin 22132 -> 22896 bytes .../FileFlows.ServerShared.dll | Bin 56320 -> 56832 bytes .../FileFlows.ServerShared.pdb | Bin 24804 -> 24864 bytes .../PluginInfoGenerator/FileFlows.Shared.dll | Bin 72704 -> 74240 bytes .../PluginInfoGenerator/FileFlows.Shared.pdb | Bin 33852 -> 34492 bytes .../PluginInfoGenerator/FileFlows.Shared.xml | 102 +- .../PluginInfoGenerator.dll | Bin 15872 -> 15872 bytes .../PluginInfoGenerator.pdb | Bin 13552 -> 13552 bytes 31 files changed, 1760 insertions(+), 1532 deletions(-) create mode 100644 VideoNodes/Tests/FfmpegBuilderTests/FfmpegBuilder_VideoEncodeTests.cs diff --git a/Apprise/Apprise.csproj b/Apprise/Apprise.csproj index 850537e7ddeb9836080881972898c7df8364b648..3b05cfba437d68fffe4c35e271bf155da4dddcf3 100644 GIT binary patch literal 2760 zcmcJRZ%-3J5XR>%CVqztF%c5e0x@cgG^rwj!P-Fam5C{|v0& zg;Q&ua|+WgmF~lAAC_XZ&wWZYQu2Rd8}#DD-V#}}y@j3yoSGfusjNNP20e_pp1J!s zMw|Rp%ViA2bq%Y)Mnpatm45YHvFqiuT;OI_xRwgID9`v#r~Kjo!L zD*B>D?kV+M!Chd##b>ho9+V}|&9L``8J zt_e|MaHQKK-e=52RCG#(BA1Ekp}O49E^?idW_%9v$?%Ez@4aUB9kiL_RuxZt{7x5Y zRlO_bwueNLQmgmPmdmFPwpRO?f8wJ3x|l_cw-eUrC3&a<>v+_uLmsPcRnc;rDvNxl zl~yN?weAs^6RJO=!o3xF<(!JBTGbuUKRZ1q?!HGqrC;qL(zjMelV~^e=9Wyux>(gW zWEwhE%qC|h+^Sj#Lpx@9K5{#YG#10xD^Z<_?5W$;eKe_mKz2F^$!mYwSzd{S8CCw#Q9TZ{j;y~IK%!B#<6|HA2n zUWeFW)TDAQ+2C#AOE-x?cTPCgm@bKV$Qde!Tw53d$AeEmrGrIF0XrMYP?T z9H2Gr1w~wsec(*SmAH3av($^hKl`%NUC*teip4<)JERzIdW|-(SC& Bz%l>; literal 1338 zcmb7E?{C^L5dB>K3M;BaktT;$Q#Vb)5-aQ0s$~f1K24fTa)66tTmDhRf4_5*0tM7* zUo7R_yLY~K=VT+RpCR{TQmlH(qsXmxdhY4)+ms@duvUwZ3`qv8-+Z?^7={R9Q*IaF zZ!Irjt?h~_@Yl4PrH6RUzAKFsx$sX;sD)#o_)J2U9>6ts7^IBhEo%$Z@v+u^h-IDO zIj~zH;a2LkqvscoldnO@qUkAe=opMd+C@T=4&GR34LCZ-R-dWoZM9Z4BiAk5EjkRcEkE|%{S=o=_po=cW8q}LXqR>?hu#;O zRLSw^7u?Hyp&$?~B?zLBh>aAz@n-15t}91bp8}9$F8&W zWk-U31X>%8WUb zrg5@76zw%OsirC*oq$;d$D@pDW>F$mT(MR;?KR`7I>VN0EWE_tEw zL!U!1#7oY3Ujpqu%(M*$&QjHEgI&7Z)fciJHHRJr>@V(u3EYP+@?|Vm%mY_TJv>t{ z37m~h@FVvw`8m%qXNqWbprtI44FOloWWdT6U)t>50!!=)BW9yR{;QJZ*)$8hRf_O8 zvY-J{&Fwkeqj=Z2!-S6EX^d%a-=}heSWfS0iLQ_OB+bB-$>K%bDCyTr_RO9SWb*$4 zZ`2E8on`y!G)iQMzIy*|Y}uCR(L3Db!8xlg&{W>{K`YVkmgw-lJ11RH+58!tTl9+b zmo0kEn!Or4<$2ntvv1Rd*0?8cUMrTZ(w)+>^~~Ew>Me_sw--a%7JFphwuUml`*rGl z6+6`nv-T&v|LZaONQ~6+RU@_kaia2d@=co$lDHnBQ=@~Vr--;SBw3y9lH$7V@cjf- zqmGZr_X-i{xn8b0>6ltm2h*gKJuM|&cTyzvJFa>k0wYdtYBzVt;i2=_WlOsrm)C=VQ2;HTRWaqXQqw1UQL5br!J~&!S?> zvmhQGXVWQXLA-bTv`0K6chV`JCdV?56}q;Ear+yVj8Cu+vu0NQWbn==4MW3254H!d4bnRutSx)#i*Tqw|4!(ln#{0rjLaSktFw3Qcr- zRNNi$>4PZ$WY@fF6{DoW{aShBeVV`a9?IQ(-9x8wJPl3e>D{2eDAzTk7RkWSzD%67 z(r6*k(7y}uHI9*H#mD2+^-}%E(ezLm>1CR#BhYl}2=PAcG`{r5*+_Ci@@cs!9Lcj& HuwVNJ literal 1839 zcmd5+!EO^V5Ir|vVXctT9_mffl2nj23N3|JqC{;97cS23BysDt7u!pT)Q@LuZ<91c zAS4c4cID^inKz#C8@~BbO7b0y6|?6BKU-mu}==sUBrC}FJ@A)Zu$am)8c*A+tqu?aVGaOZ}X@Sx2-Q{eivGfcPf$i65m zDRSX%E#|ij6rV~Mrdx32Ue!|i?GlZ^Ds?vWq%*JGfgr ztvz34J(a>PCPtJc6wH|#1#W?Xc&f{at0nUZ&!v8_!}JLX`=i<|w6W|`FBBQ6!hokd zp)prf#@=!(a&n~$Kt>~qMF!9B`5X}Q?YT9QEu5?Dt2CWq+L=#Fb6uu*>=$MTa0WIv zqH@^&CXMoG$V?luQcek(EQBSMtmi_JTr044v5IpIpgbve9UD&2j_U3ST469y44?x53sji27@)0>li_ayuf@~Z~y z9L3e~CZ+e%uLk|*H)!@`q~hc?@&A1_*C2sg_>bzrhGTy&9F)-u!rFH%4&gP-z@W_l zxlp;R3&@g7pfSU?(F%$Wdub*>i(W=Xcrm?3Z0x-y*xVmW^#H{ou@}_!SKwU+LJlY z$SF!~W}n>7sg33sq3V|KeFs!($Gjy((y|-)$DCS0saAGe6lE*ji}$CC`2?mBu1Iqa zjx*u3HxfH%y#=;(4?3`(+LS&0`QBxwWklG0;_jdiN0W2+9n%4^4$vn>@<5T- z_^Xe@N8D`cT+v-r-1~H{SoisOuAr)l9y!s&nJ#Dh{E#!pyz9Am@+SDeo^kwuC*)>@ ztc=~gDnqyJ9XY6bxC$n1d($r;WGlEZgvey(fJiURr^w<&MeYT@7DP{_ztekud+*BMvg7^E}gz^9@N<*m%?O-3bpE| z(|gz1vl&(59>Yy9=EbI(YRri2?CfnH=MtAKib=jL_6=#-c6}(e4{rT`DOsLz4^!i3 zRWUy@*H-0DwiXd}*;R>VYGm^B%GE~8P4{9?2pu5?Il!F@Zd6$)#lfF{Rpc{U5o!Ld z%Cm6n&;&VMUYJ9_G+$>ZU1ig=pDYX$%#*r@a{GCb&3ucYEC_ru#;Y(G+=T4%^KHupqI_LtpLZC*YIfUifO=eI>^#PJaDh;MoA&@uJz6> z1I-r-vh)BB%!yMfZ02KRWP@*uAz8o-+_TQ zGIhiCngz45GLLPRc2L+JI$RptvKzD1WT*=ZfzhFRRk6_$#Hw{QnV14RXIoQj=9G&S zuV5R5JFD0dv1z}iY3XgtU`vImQ-A6eGk9D=E39nL=Zr;pf=iC1vF1S*;1@vnLMn-C zf`(Y92`8efhgV$c7CjWqXqN7)`Rs*CUxY8aMyO*FiO)eHgKeIW{=4^nS<1>;9-t3> zlINs<2@6;CLyCRdH`U)l3D!>nkZo2DV?T!$WA@3mnSOdc(?J-Z^ev%TJRCm5f;R{@ zc@{aNXY|W|Y3v5@EE((o5$ GCw~B9N7bGH diff --git a/CollectionNodes/CollectionNodes.csproj b/CollectionNodes/CollectionNodes.csproj index 2785f805363f98ac12650b8b987015d45185ac09..6171b60078f5613c40dc5d162a5e7d5703ae24bf 100644 GIT binary patch literal 3256 zcmcJRTTc^F6ovOICjN&BF+m@kDhe7?N*WQxC{_zT`BGX6h2BD^T>iZJt$moDUbqy{ zG&6HLXYX~^zR#cEMO(LX>sZ?oJGFf~v4OR$XI)#fMSE$fz2KR!)3rM98|-%Nz;}n1 zS<{{)wTjHTmF%%SvZ7T$>DduFbtDq2qIK*VU(v4n?f{7DtTC#}ealfgPs@usMov|*PcuvV*@>HA(i7nX^dwRL6EI5FbI&UuZ42gt}zs7yZ z`RyTbz&iH#(Ba23S8cQvXU(LWX2=dQ@?@MQ$y84ZQ|%2B>X>1+ z709xfhZXFIl`t=-DxD=iJ71MO_R3}1q$xVtU&Un^7P{X0{{Lb!I~VW9MmaQ_AGz1A z%AI^K!Rn&du;y@L@@I#-(6@%{S1+BexY)B&q`G+Lh^VR?h;{VQLs{wUu181rt8(qG z?8dDQmJ2~MaEIqNuid`iH>eurxu&jqh~|j8%Nf~sfwi*jF1jIq!wvrAU8%;ZYTx<(2tEJm>n zO}tkAS-z>)&DTjP qbV8L}RZg~iw%4cnmA-WJ6{jgCtlOk>WXaB2KTlRlbMjjxX#E8Q0~L$_ literal 1585 zcmb7E-*4J55PpWg!ipxbJrj!(_V~o0T0KHY^Rj}es@U=l+jju zN#yf)_uY^0oSfYin%#o)%9=sczemb_Gr=&~tdijf^5BNR=eFEj zSt&GrRupOIJrr}Tz^B1gnC5ecnyx~$U(TE=3druACXbB`Q&9@DNr~h_+qI|Ajft*@ zRajc*({FZZ*wADS2=QR8iJH37bE`GZ3#ZD)HUmW6*HsT@BIHUe08KR18>iD{2&MlN z$2k(`M9ifvV)Xh4Nh~Aq(y5Zdr*(K1mLjmy*;|zX9)O9t(kg6Nu*`wTm@pYzI~9QC z&K68=^Ygsj9%`awK3Ip-XEtY<2!ed+KNp^25&;d?2hZjZ)&Pc4stoQxR+Nk9NxYvL zijvBHq{`$nKv7GSom-PB@*6~~^XfGobG4|PAk&);8w^-y1oLXqA$g-@npRvx4i0w& z*rk!W%HVJxX5d4;6zpDIxK|%|msTr&DbTcbrq3`FWdIlLg7kTxfBdf)+s!*31-I*= z7ns+sF?e7s8CwJF8VY-h74GCzkDG(xf4ntKHqXbwwgxa^*R7{w)wD=VyEL;us! zq#O#=x=lLNYq6=<;n;1RF|JBYMa4W@+S8L9Ppq_i-8$j#c)zIwf z>CY>a`CbrwRe7&>!cSgoS1UQ9u8FP|%G4TcC0~^Z6A_jv=fAg)1aBZb(>jT_2-IvV hnU)|`uH?f*cOkUL_v+A0`i{5UhYhT^h+c}c{TD`~5o-Vd diff --git a/DiscordNodes/DiscordNodes.csproj b/DiscordNodes/DiscordNodes.csproj index 8866143c5e7e18a13bc1a885022332c858f4fd82..9fd966156de3b8a28d923db1662e7efdb70ad5cc 100644 GIT binary patch literal 2870 zcmb`JZBG+X5QXO}CjN&_V*(`FDlupblvEMLNNu3_$;8yYOW)Gniu`%?IrsK<*)A=h zhID)B%$zwh_uRSr``4Zw*iReUz#{u$ZJSzbeH+`z_N`#gtY}a9jB8l%d+e0*|QQ^*ZYe{ihc~* zgdVAaJ~-#DOX@=mwtCaBZ`j*#F4=nTEOOOm#0?hld9=Jo7U7f{$8f67YmQ;sfM*+K zN3a#EBc5Zr5mWyo+p-fn{+i6PwwCrR;1unYNLB68www+M_L#mD>?@yb{#5Te2I9Jb zS77oP%v57#)Kzr5BBkxvbF?JHRo(&3tE@!@QrX=w*T)3pH}q+O(mwLtr1HUhb+O=7 zp^Gt94Bd|RSxEy4Rn1t7{oi5)4mFUZras6$lsaWKbb4+rWm@kU@We;@ZJ^Vu8&wfl zU-t^p71$*3&`DCIA6WH3imbx3#jiSNv8#O9H(+FYU$#S6o94+B1Z7|LNF$}b3%KiS zd#^BE&WRqts0Y7<`eJ(pQi<8(Ro}rHRIgk^Y(CfRm?8h6+h5JCJ{c08nvG>@*QxdB z5nUbAr3m|&r_`a&L~hTd7SBFjcr;jLd*Gv{^BG)pJXhrwH$U}4-&Rk^)b|*6Qtj#) zT6MLx!Pdzi@}F)5-2+*!@@rwyG*P8R=DlY6$W4e6-AS`*8s3~Y^;zYS&R;2bCojjkM-Y4#~JXj$To7I5&5V4K;_|%hr`L z6Yi?62tyM!Z;#yMk@EWRO>gnYHr>?s*>pO(RHr*Kcx~em(Z_wBo9uR*`7^_7lO6S} zHeAjcG3jZPN;-VhA?=5hli!(j_kNw27#8UpK(sW?{aeTjJakj|cafm5f8lh-UWeRa zRiSeYcgj_h-g>e(i@5B-LZ6ozt^aQ(`8SyRvAIn@UVnK7r3&;OciZ7`TVH?6sJYYG zMQfT0SzM3(-q{jnx^&pXr^w%z#XY+Ut;jBE_NvA_#_|cvSCDeKtxK|JZyX={2eBQ} ANdN!< literal 1393 zcmb7E+invv5PfdG!m=u*mB5=;s35fKDl`;|XsFVZCnV&qCy9yIUis3Hzh|7?CTSXq zcv)%BoH^sU=I6gFO&-8`Wlcd(SdS7grIpG|3mU`Z^~o7M=lPAZzn~1{R?Z80tx9LT zodh=gIA#b@-supMNHw^y{N!w`IU?cxpls;adrRk-sQ z-*YhHUPGSkzzug8wNBVy1@C*$5<*lJ4OT&v}xAEL3bYV>Z6Udb*b(DV-YxV%;QYXjuTMTs!1Ld$- z)-5sTg;-*>_ggV+dPp1T`Kt~#*%2g3mFief(mg!F--((=ClYkrB}GBH1GtaVE^h0= zx^E+xfWwW4O&U+vdkj9TcAT^mjaT9=>!m}1WqMiYcIBKteJSbyj&4Lw*(rPXUmEKp zvR~z&{o0diTDj&b+~_z}21}DFjy3#zU4D)~!+cBPfJU!aFQ)AU0a_*{q<+H)xw&k#!&p=VFU{wKSfO>V99!&lJ}L6Q&9ic<+f+r% zEAkd1OS?y?&OfaJn*tGzs5e!DD*8RECP)z#)1`6-sHqMljI3?In2bA5C3Rq zoZ_cQo}1TXJwyR@s4?tRr4c;UUHqvLO83}{@ayrd&LFj9C0q3guRw%)!c&dw_e(yB z)7;m-JR)-Dkz*IdJZ56P#;(n%D#P9?VLyy@(WY|Tv>-y@{-89dbw zg4G5V5wmfJ?==(4Q>V`wQ^ilh6*o0X_@tTDJZkV!C21y0hsl1T$-QXWR`40ZBAvTY z=0^J2|H93o@CK0k2b{`OLpVFE3Mf}~6{DE+t})pi#AVaxA%9nIcN={7_~7p7?5sYWQ|-4u zwT!arhNtMM{AfO(v8t1|*&LqF;cz$Il#%7SMv3f)4xO!{cd%DRrN1Uz9o=W@t7D>n7`fEZgbmm#s*7PtH>B`3pA0 BF9-kt literal 1646 zcmb7F?{C^L5d92)g%wqzl{SZVTQ^O?6>H1ZZDpv?eVR0x&k>ba*|X7>ZcCO-KNhVBG4n(Y|CD!PuSFZpaI;B~O73goJ_AOG}TAZ^xg!kXg+f zF!T;eiLm2{M6XEnJ32W@;->`dRx;sc25w-mV5!Z5DRAeso5Z_ugx(aT6sd6c7RRv+ z6rV~+;+-%8hhEB%+dwt}OkV18^czS@lFgkf?Z-IIan`(Azf>177Cl2^`4!mIh|-}U*kmp& zDW#tYMYs%=WTicEnpjX7;fg>wo-F6cOyB`h?@)EZN!W6l#M@-SBB9T1kKlPX4vNY# z1g||4;oM$CI!DL&GZ!;&cnF!w`Mv6v~ywg}!e1c%ycC41T#Rl8g3@u* pnn`rg27z+4l5q*C$VK|-`T>^~U%TCKCEe!iXW~^mAO1X8`yX35Dzg9p diff --git a/Emby/Emby.csproj b/Emby/Emby.csproj index 2ba1e5563aa1d6a5993a7007341b500aa220088a..976bf3b6d34dc170a98843c6c177a7ff0fcf09ef 100644 GIT binary patch literal 2844 zcmb`JZBG+H6ov0sO#Ba<#so;TRbtQ>D5)Zdk=j7Y4Yx2H@b!1&< zomyfYdxqCGK6_TS9jk#bwhR25SR*@S#-;N~)oi&nMwR_E!x3LreTNA8N4 z8_*_>S7I|ebn~Y+nS091d)BRit&3-32aFoT)V6C@x?=q@oMqW|@$6WMRag6qM~Z#~ z+Jqb_f<8EBE=$To47PI9uygEfIG1d-cNV#7Q|1kB=I7D!9$ADFVjRP%I*&PqX#<{Z zm>s}YtPZ%3$wo~4Pi(`E$@p7VmbJC8X91^ZC(KmT9&N+vpkPnQOToTzZSqsRs~Cvu z8eW0P7cf(el~GsG?TVDPWiQc^5SMueG_SH25lCeZ!(2TlAipC|6O{IeXOqYW^U>uE zrwUn&iDKw>yw6A)NQi36SnU56BXFpJBsKLx?xEBxMnk9P*1}4wJp-QjNWTqqI=fR9 zf%R>#FuMYq1Rkm+Mf#CZ52VN{+*`a=oy9KlMc;st&3&1wSN3LZ&Y~@yBi&uXT2<}6 zLSH#!)d5_3FiVImwm0OxL|5^8?_dpjSJxV1Q;apI<<*#B{e8Ey>R5eNNVuyjrraam z4#-Uxi?X2{HMmE-Rj-K|&6qRgsgBih);9k_^bvVeH|g=t?@dI+LQ!XtuEcp65ApQ9 zPjRX1F7K16?-A=syUROi)x{~Es{bMXbS~&L2)v8@A5pItFjP)-K9tBzx{7+>-Rq=2 z%RJJqE8UJ9j_whdI)jw+*1e2UHd#E?b{*W$ph!8o@3RY1v3iMAt{SPZ&NVwRo9{xX z>4(e>F^1jA#*s49?k>xMFw{5m_Q>@YRbC&y=~*4wy6f$JHB~~F=yVbWuT4B6c5;{d zy3^G;9$m)aBs9Yub@&AOfV<}ns4EFVD{<9%6@J$t(N GxxWD%Z_N+@ literal 1380 zcmb7ETWi}e6n<`gg%E|bu*qo|-59n?*2~thW+lz`G#H9~604CVqf0aY`yJV7lBS_! zF9v_-JKwo0J^xcF@(9*RqceKK29$u#O(FF>qruPKo}AHhp59sW0J$gk#Ui7(GPlN= znP;P`2}6kTUXPGSs=@l^vo)dSh#)o*b`Jj9iVBv-F1QAN#s+D!i+Ajss#Y?W{)fZ( zj)N9c1!=Macid4>Dw@}c@ zLl&dIxFL_}R6J57-$yVW;n~lx-MUC|iWw?;-A3kb7b3=9|fd!p|b= z44s2&sw6n>ZNSoBW5i$q$*!DOSyfQ1e0IP#PE`xtY`PGII|!}A;7em2|7uE2hPtq@ zbZPR0#wcA${HmHZY4Y?J4I*ENIUo|Zwh44UPaI%!XBv=W_OQGk0X>M!a;M?@Jw=iNi9;)r7 z92pH{43&9=j7D7snmst9DM{kq;>K+}_6b}V?Lm8TqjMFCU6F3}Q6>&=V!j7o2Y)Fo zw#e9q57kmMnE8GyhKmWTBD~DzU{ei2QXymaGD`Y~NBBFF^I%1Uj{79bNdFS1Vcy3B zJy=g`3^TBJefTep z^}DfO<)3rfQ);}j?jg8qmknDJJB~g7BDKF0zT}Mk+GVjqsWe$LRzq6LzZ_G$hw&(Q F?=OCn$ov2R diff --git a/FileFlows.Plugin.dll b/FileFlows.Plugin.dll index de5e5245a8e882f86be9c00ec1a4f404877508bf..ea43043c6bbe62adec549297124c14bc7ec31a17 100644 GIT binary patch delta 14330 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 delta 13122 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 D8-V~> diff --git a/FileFlows.Plugin.pdb b/FileFlows.Plugin.pdb index 26165175f38ca3d26b775d645ca2ee1ed3cd2eae..9a831ec6ac0263229524a04f525168c1fc9f5858 100644 GIT binary patch delta 5311 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 Y9C)2)&~OT;$Gc#0L-v|rCGRQuFA+Z&8~^|S delta 4665 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 I-0SG^KdV}@EC2ui diff --git a/Gotify/Gotify.csproj b/Gotify/Gotify.csproj index 6ddb5ec0ddc0d8d6f7f4b4337fb00fff4f23ed5b..aabeb41fb677bea822c083155e09f025f3da1034 100644 GIT binary patch literal 2752 zcmcJRZ%-3J5XR>%CVqztF%c5e0x@cgG^rwj!P-Fam5C{|l!N}u^^o+-tG{QL<$68u zs2W4=x^!ord1mI>+5Y_T#@d$H#ICGw=ayPzC)TrT+qHH3WHH}qcgAzUZp~Wu-a34G zt95JGV|(PD2;YD<1uemTZXcZgjZNx74$MQ?p|{m9 z-PP2Ji6F*awMTrP5;21Rg!)9RH3fRC7ITYS*Q6Jpfjm+?BL4S2iG9a2am>o1iH)Cf zVy_8WJ`pq9Ln29~r^y}bxU973%?Vy8D9FCKeGL-F3Fo z*BKTAz72Qnnv0n~6H>zkk1C`dNFl{;RNdztd}gr7ZuV$tN{j!ty~IK{z*bIG|HA2n zUWeFW)ueJ=cYc+V>XyGT#AOE-dS3lkCdFSSf5zq^{doNq6_hE^TddaMa0@T~dT6^7 zIY4Wg1bJMKec<*|H)nNkG^lFLzTV%TWoR|Jq+deHv52vJ!ipJWTpp^D_Vag%_x%Mu C8NR9j literal 1334 zcmb7EVQbqk5dGZz3SkOqV9041-58D_YuB!$%}Sc?(_pCfB~c?wMmjb4-|u9nNt%R? zeKF|WyLY;GCujH0K0}V|p;!!(JC!@@?G*Xw+k_L8h)##Gj7SwYtgoF7l^}$$iF7l- zDTDK4e@SOLvbQf>gH)W+&uJF+-GxGwBeA1AmJ8;V#1+8Ov%~}I(d~7X_sI0GK z4&q8_xYBm%`SHo!!`Gm6vFa&u_!ufpw3CD-A6W7y>GiVotw84}iyFVcd1a00^K*X6 z&puKs+c2?6wg@>MAnrtndts~k*5*>vXAyOV-b4AM6?lOzQ0wn8VzEGEKc6^NmQbv6 zcEF}iSxHlGT!_LgMA2cuxpiLruyezPrf{(IS^A2`Ds4;R+M=4)S^9d8A(=1a33fEjNs71^ za9O&YM$>L?w7q%}yFnV8FVU@DyfUdYMP-A&p@Q4onW42Hrm933zPYGh1!%AUXZS`@G*6^uEwT zlN>+8LRJVa*@&F+GyeI%G}b?i!z%xr)PYvx^J@P9_d3j!A#0-J%CVqztF#!_23NdI5lvEML2sTiBWnyYupwNHe4uLPP{+?ZyV|(^M zG^D+wJM+vlv(L=#ub*qSVV5?vfhG3CdUj@+^=)h;Teo>zw$z^UOjsFNhu^!bj_k;- zo?C8*_6)04Y&NWJYt{r|Y$w=vSWRpnk5gy8gJ;LBW>_4un%b_tvldTpH4nmLd*nU| zz5#9Gc;$9w@16g-O|C6ve+_rdYlT*(wh;&B$I-Iq#>hf8$8d0n5#iKyq z25mx(ltCYy16L*0Ap={rY1?gJ~O{ zJ(z95R;;%89#f5s{GZsO?NISIMAm9|YR>{rYI}GpYmc_*bTDsEsmr{5b~AH`3dRy+BdIon;+kdc}3gMvA*1aZ3$d#1v7R|gNYd+%Lm@$h@$5vCXPn?`@ zP1gFYOcJ81Y6zt4q2Qr1RP>4fa%r!%ZZ<%@`#)5@(Jv#^Ne8CCxb~)A8 z-WpV{?WTuvl8)muPFz-Cq0g&G=l`2Y`Cj#RZ0^#J*I!vdg#x|B{dPFq9&X=#nzyE8 z&`{_%kNp81O8e53PP95zP3`N=Sw9OcWtVi1Q;ubf=?*JrP~`Z(s`QYq*eCl-?l-#4 k`m;QxcfxetryjaBPbyTX8{BfFLSNVF$)TL%GuqeVH-Rq*CjbBd literal 1570 zcmb7E+invv5PfdH!dg{ID}gtuP(f(pDzp@W+7KlvPe{nwog}7S+w!Gp{+{vfHn)Z% zURK)U<1;g7#*m6AMybwaCd(xL5yfXa0t)V!MnKYQD`NG@46wE8#Xo{Wo!ZgMAb ztDT;CI`}-H2qoP<$#OOZVWKI|x$7<27py)aN6u{Q$!{!*gIaLc)#IOGi&m@5Y~kkVR8d*yM(p`aCG|K#_-C}KeK|A#P9aggq*F+RALhcW6_fBg1l{TweopXtw zhp5(b4$7$%;Fz}oJ$Q}Lgbc`ci-{Fw2}N^lxC=fjY#C0D`($vre0G)uRmVf?C`?TL<9-$S`Q-~+9IjG)wy&`l~Ysyrzu`rB!hkTjZs zGrYNXNahNY1?5R!Kr zZ7L&3Dn#_Wn~>JYDgMsHJXju~vli)gN$VP>Vcx=re{_^J%^SfCEG`e&6tTN0Cg6Ov zE=cn%aN)eC?YMK$q}PSU)#do<72J5R$wuUyp3@KirLo>ehgJUBtplaTM_VtLVKshe zO>`VR|0o^Tf1?g64(@<9=Sj2@JZj3(?6UUCc8`7ZucHntu zJRYyTcHI;tE|BH@nlta5^PZ16^VgpT_T1jtl?^Si->qj8%WYs|8`(44vbv?V!#!bS zWF5YD86DZV8@;i@`t}u4Pmpey z+Qir$2!Z2ctQ(Vaxnq7&D$G8_u7cQ5WGZ{!@N@xELIjV{Xo6k=V^KC>l)2CBggFKJ zBvcgDC~+w7FUrOFZM<>G3{?y-6>8R7G#H}S1&9S!=JpLpHS)*DZ+~WG3Wk`dP1pJ` zW?28oX{c&AV1a3(OEQAziyu66r%`n1c_OKSU5>TR8C zeDhLaY==5LKlZrvwm0`yM%lHmXJh-UQGVN>jrrAwbMHIosk|@iA9??;`{+k}q&>3j za`k^dRb@!*5q%G&Ugv7AGhCHH$p$&JO)e{2BpdT3X2=8AcQx@(+&$#8K7Z|7>Y-FS z8ty4{Q_A0U-EWIIIXN5q;AEi(@xAyy66$h%M_!v|?WgE;Mr{piho?j8VB76VvS|xz z%KeaZ*+mQepStmXOOxe3{^PXqz4&5$#99~YLId{8Q52A} zl`YEfb24}G(kW&&Cjm=mkkwLtrTb)y-=nL&9s2xo7HF;euNOM07x3)+t3UAD34Tyt z(4pUm->bFSLtdKIOBwNLTAkwkTj%|eiy(hyelv@vs?4m@+pN;$pUj8Ns-C)$(92dw z|7-YF@2DtIubZKLYQI#RDNl!PcKK#7D0mCTI*#H0l literal 2197 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 diff --git a/Plex/Plex.csproj b/Plex/Plex.csproj index 76d3489a456ac69e3f854c9fdde181d7335f62c2..f952c008b7d489e99e3e97c5ff8a0db93f456268 100644 GIT binary patch literal 2844 zcmb`J>rWF=5XI*!CjJjM!~{sRRbtQ>D5(z=Bb7k$lZh#PLtkNAfq!28oqKy(wrdxB zq}lDZGxyAyxo76?&mY^iYgab3fjRqbZM(3<`Zl(a?bxb4vywgK+hG}5lmA;-N7nV$ znN6)@Pw?8pXV)sWZHFL??F|1WR%geoIQQNMtZaH~f=35y$!hk_>U;;URS+K91AjTz zMzo3NHMMJd@7K?4GWV2M@T^+{TNlr%?eWwgr?y=Z>4NwbILor-^VzmCQH%Y>BSqf_ zZ9xs*#ZYBU`rvD*l?tvbGlXEaH^xh?UAZpsjlytlDGhvTEPBHuxytA_n5R zf>&hn1Gf|_ z5n12%imR)znZiSzq)b2Z)C0*`m3xbS)n|#%e9<>zWNTkRaZ=@#U$baS*GPBguvS+G zuQ*puh&q5v4`x#`OY9YOFEdqw-aA;M-Ziy`*p%a;*K#ptjQ^IX2@F*I2~omSOu0M$ z9Z;Jt7F9zvYH)Wxw<&8K)gI&FxF%Fe);7Ol_Kvz~n)LWD?2RLyP&8Q-U7VNk5YI6C zl$WON@;RCM?t2cyf=OBfNz>B#{vYy7=Ymdy$h*Yv5&e1wL;31_D6<=B6wN^8nvawE zEb~aGu5>%{IJ!G9bq1;CtveZ|Y_fRj?K-%hL6LHFf6FdN#hN8jxq75ZoJ)4%dcF&> zr|+{i<`{P;n@7q_ySuCk!qD8z+nt{;>byRD)3e&ynxE|rRDUTWzY|5Ld!022EYfq{EzIojuJHm7od@BKBP!}& zI32UsF?M{a`c70wD<^3;dwz(^CMflHQAyV;*C%!}1xVIo?$z*|Voh GSo;fRI?YS~ literal 1380 zcmb7ET~FIE6n&<@!m^MG(&iL2v1v+-Iv5+%=&DloG-)!)ZQ|9jBY#l(?{}S)wv>u# zFOhQYx#xa6J%6kfc>wFA(HT8q14=;WrjWYKXz;VQCuj7Wr($HG0*6Y%&l=| z=Go};lp#cUuSZBEHDLYni#4I)h#)oa_?jW=dgRhKr{F|vX8S28q z!llU*8l!Y2@v(x(G{+_;U$K7k9PJ!ns^b*@6OE7Gk#%EaMK&5z)l;4h`c z78$$bL$we~%zVEU!^H$v5ng6|PY F{sJA~$v6N2 diff --git a/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderNode.cs b/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderNode.cs index e534f40d..ba21d410 100644 --- a/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderNode.cs +++ b/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderNode.cs @@ -19,8 +19,9 @@ namespace FileFlows.VideoNodes.FfmpegBuilderNodes if (base.PreExecute(args) == false) return false; - if (Model == null) + if(this is FfmpegBuilderStart == false && Model == null) throw new Exception("FFMPEG Builder Model not set, use the \"FFMPEG Builder Start\" node to first"); + return true; } diff --git a/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderStart.cs b/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderStart.cs index 6a31ecbf..a53a81a0 100644 --- a/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderStart.cs +++ b/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderStart.cs @@ -9,6 +9,7 @@ namespace FileFlows.VideoNodes.FfmpegBuilderNodes public override string Icon => "far fa-file-video"; public override FlowElementType Type => FlowElementType.BuildStart; + public override int Execute(NodeParameters args) { VideoInfo videoInfo = GetVideoInfo(args); diff --git a/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoEncode.cs b/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoEncode.cs index b7418f1a..7d5d4ae7 100644 --- a/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoEncode.cs +++ b/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoEncode.cs @@ -9,12 +9,18 @@ public class FfmpegBuilderVideoEncode:FfmpegBuilderNode { public override int Outputs => 1; - private const string CODEC_H264 = "h264"; - private const string CODEC_H265 = "h265"; + internal const string CODEC_H264 = "h264"; + internal const string CODEC_H264_10BIT = "h264 10BIT"; + internal const string CODEC_H265 = "h265"; + internal const string CODEC_H265_10BIT = "h265 10BIT"; public override string HelpUrl => "https://github.com/revenz/FileFlows/wiki/FFMPEG-Builder:-Video-Encode"; [DefaultValue("h265")] + [ChangeValue(nameof(Quality), 23, CODEC_H264)] + [ChangeValue(nameof(Quality), 23, CODEC_H265_10BIT)] + [ChangeValue(nameof(Quality), 28, CODEC_H265)] + [ChangeValue(nameof(Quality), 28, CODEC_H265_10BIT)] [Select(nameof(CodecOptions), 1)] public string Codec { get; set; } @@ -27,8 +33,10 @@ public class FfmpegBuilderVideoEncode:FfmpegBuilderNode { _CodecOptions = new List { - new () { Label = "h264", Value = CODEC_H264 }, - new () { Label = "h265", Value = CODEC_H265 } + new () { Label = "H.264", Value = CODEC_H264 }, + new () { Label = "H.264 (10-Bit)", Value = CODEC_H264_10BIT }, + new () { Label = "H.265", Value = CODEC_H265 }, + new () { Label = "H.265 (10-Bit)", Value = CODEC_H265_10BIT }, }; } return _CodecOptions; @@ -39,42 +47,58 @@ public class FfmpegBuilderVideoEncode:FfmpegBuilderNode [Boolean(2)] public bool HardwareEncoding { get; set; } - [Slider(3)] + [Slider(3, inverse: true)] [Range(0, 51)] [DefaultValue(23)] public int Quality { get; set; } + private string bit10Filter = "yuv420p10le"; + public override int Execute(NodeParameters args) { var stream = Model.VideoStreams.Where(x => x.Deleted == false).First(); - if (Codec == CODEC_H264) - H264(stream); - else if (Codec == CODEC_H264) - H265(stream); + if (Codec == CODEC_H264 || Codec == CODEC_H264_10BIT) + H264(stream, Codec == CODEC_H264_10BIT); + else if (Codec == CODEC_H265 || Codec == CODEC_H265_10BIT) + H265(stream, Codec == CODEC_H265_10BIT); + else + return 2; + + stream.ForcedChange = true; bool encoding = false; return encoding ? 1 : 2; } - private void H264(FfmpegVideoStream stream) + private void H264(FfmpegVideoStream stream, bool tenBit) { if (HardwareEncoding == false) H26x_CPU(stream); else if (SupportsHardwareNvidia264()) - H264_Nvidia(stream); + H26x_Nvidia(stream, false); + else if (SupportsHardwareQsv264()) + H26x_Qsv(stream, false); else H26x_CPU(stream); + + if (tenBit) + stream.EncodingParameters.AddRange(new[] { "-pix_fmt:v:{index}", bit10Filter }); } - private void H265(FfmpegVideoStream stream) + private void H265(FfmpegVideoStream stream, bool tenBit) { // hevc_qsv -load_plugin hevc_hw -pix_fmt p010le -profile:v main10 -global_quality 21 -g 24 -look_ahead 1 -look_ahead_depth 60 if (HardwareEncoding == false) H26x_CPU(stream); else if (SupportsHardwareNvidia265()) - H265_Nvidia(stream); + H26x_Nvidia(stream, true); + else if (SupportsHardwareQsv265()) + H26x_Qsv(stream, true); else H26x_CPU(stream); + + if (tenBit) + stream.EncodingParameters.AddRange(new[] { "-pix_fmt:v:{index}", bit10Filter }); } @@ -89,23 +113,12 @@ public class FfmpegBuilderVideoEncode:FfmpegBuilderNode }); } - private void H264_Nvidia(FfmpegVideoStream stream) + private void H26x_Nvidia(FfmpegVideoStream stream, bool h265) { stream.EncodingParameters.Clear(); stream.EncodingParameters.AddRange(new [] { - "h264_nvenc", - "-rc", "vbr_hq", - // 0 == auto, so we set to 1 - "-cq", Quality <= 0 ? "1" : Quality.ToString(), - }); - } - private void H265_Nvidia(FfmpegVideoStream stream) - { - stream.EncodingParameters.Clear(); - stream.EncodingParameters.AddRange(new [] - { - "hevc_nvenc", + h265 ? "hevc_nvenc" : "h264_nvenc", "-rc", "constqp", "-qp", Quality.ToString(), //"-b:v", "0K", // this would do a two-pass... slower @@ -113,6 +126,36 @@ public class FfmpegBuilderVideoEncode:FfmpegBuilderNode // https://www.reddit.com/r/ffmpeg/comments/gg5szi/what_is_spatial_aq_and_temporal_aq_with_nvenc/ "-spatial-aq", "1" }); + + if (Codec == CODEC_H264_10BIT) + bit10Filter = "yuv420p"; + } + + private void H26x_Qsv(FfmpegVideoStream stream, bool h265) + { + //hevc_qsv -load_plugin hevc_hw -pix_fmt p010le -profile:v main10 -global_quality 21 -g 24 -look_ahead 1 -look_ahead_depth 60 + stream.EncodingParameters.Clear(); + if (h265) + { + stream.EncodingParameters.AddRange(new[] + { + "hevc_qsv", + "-load_plugin", "hevc_hw" + }); + } + else + { + stream.EncodingParameters.AddRange(new[] + { + "h264_qsv" + }); + + } + stream.EncodingParameters.AddRange(new[] + { + "-qp", Quality.ToString(), + "-preset", "p6", + }); } } diff --git a/VideoNodes/Tests/FfmpegBuilderTests/FfmpegBuilder_BasicTests.cs b/VideoNodes/Tests/FfmpegBuilderTests/FfmpegBuilder_BasicTests.cs index 8bb2920d..53f23731 100644 --- a/VideoNodes/Tests/FfmpegBuilderTests/FfmpegBuilder_BasicTests.cs +++ b/VideoNodes/Tests/FfmpegBuilderTests/FfmpegBuilder_BasicTests.cs @@ -4,967 +4,966 @@ using FileFlows.VideoNodes.FfmpegBuilderNodes; using Microsoft.VisualStudio.TestTools.UnitTesting; using VideoNodes.Tests; -namespace FileFlows.VideoNodes.Tests.FfmpegBuilderTests +namespace FileFlows.VideoNodes.Tests.FfmpegBuilderTests; + +[TestClass] +public class FfmpegBuilder_BasicTests { - [TestClass] - public class FfmpegBuilder_BasicTests + [TestMethod] + public void FfmpegBuilder_AddAc3Aac() { - [TestMethod] - public void FfmpegBuilder_AddAc3Aac() - { - const string file = @"D:\videos\unprocessed\basic.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); + const string file = @"D:\videos\unprocessed\basic.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); - FfmpegBuilderStart ffStart = new (); - Assert.AreEqual(1, ffStart.Execute(args)); + FfmpegBuilderStart ffStart = new (); + Assert.AreEqual(1, ffStart.Execute(args)); - FfmpegBuilderVideoCodec ffEncode = new (); - ffEncode.VideoCodec = "h264"; - ffEncode.Execute(args); + FfmpegBuilderVideoCodec ffEncode = new (); + ffEncode.VideoCodec = "h264"; + ffEncode.Execute(args); - FfmpegBuilderAudioAddTrack ffAddAudio = new (); - ffAddAudio.Codec = "ac3"; - ffAddAudio.Index = 0; - ffAddAudio.Execute(args); + FfmpegBuilderAudioAddTrack ffAddAudio = new (); + ffAddAudio.Codec = "ac3"; + ffAddAudio.Index = 0; + ffAddAudio.Execute(args); - FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); - ffAddAudio2.Codec = "aac"; - ffAddAudio2.Index = 1; - ffAddAudio2.Execute(args); + FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); + ffAddAudio2.Codec = "aac"; + ffAddAudio2.Index = 1; + ffAddAudio2.Execute(args); - FfmpegBuilderExecutor ffExecutor = new(); - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - [TestMethod] - public void FfmpegBuilder_AddAudioTracks() - { - const string file = @"D:\videos\unprocessed\bigbuckbunny_480p_30s.mp4"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - var model = ffStart.GetModel(); - if (model.AudioStreams[0].Stream.Channels < 5.1f) - Assert.Fail(); - - FfmpegBuilderVideoCodec ffEncode = new(); - ffEncode.VideoCodec = "h264"; - ffEncode.Execute(args); - - int index = 0; - FfmpegBuilderAudioAddTrack ffAddAudioMono = new(); - ffAddAudioMono.Codec = "mp3"; - ffAddAudioMono.Index = index; - ffAddAudioMono.Channels = 1; - ffAddAudioMono.Execute(args); - model.AudioStreams[index].Title = "MP3 Mono"; - ++index; - - FfmpegBuilderAudioAddTrack ffAddAudioStereoAac = new(); - ffAddAudioStereoAac.Codec = "aac"; - ffAddAudioStereoAac.Index = index; - ffAddAudioStereoAac.Channels = 2; - ffAddAudioStereoAac.Execute(args); - model.AudioStreams[index].Title = "AAC Stereo"; - ++index; - - FfmpegBuilderAudioAddTrack ffAddAudioStereoMp3French = new(); - ffAddAudioStereoMp3French.Codec = "mp3"; - ffAddAudioStereoMp3French.Index = index; - ffAddAudioStereoMp3French.Channels = 2; - ffAddAudioStereoMp3French.Execute(args); - model.AudioStreams[index].Language = "fre"; - model.AudioStreams[index].Title = "MP3 Stereo"; - ++index; - - FfmpegBuilderAudioAddTrack ffAddAudioStereoMp3 = new(); - ffAddAudioStereoMp3.Codec = "mp3"; - ffAddAudioStereoMp3.Index = index; - ffAddAudioStereoMp3.Channels = 2; - ffAddAudioStereoMp3.Execute(args); - model.AudioStreams[index].Title = "MP3 Stereo"; - ++index; - - FfmpegBuilderAudioAddTrack ffAddAudioAc3German = new(); - ffAddAudioAc3German.Codec = "ac3"; - ffAddAudioAc3German.Index = index; - ffAddAudioAc3German.Execute(args); - model.AudioStreams[index].Title = "AC3 5.1"; - model.AudioStreams[index].Language = "deu"; - ++index; - - FfmpegBuilderAudioAddTrack ffAddAudioAc3 = new(); - ffAddAudioAc3.Codec = "ac3"; - ffAddAudioAc3.Index = index; - ffAddAudioAc3.Execute(args); - model.AudioStreams[index].Title = "AC3 5.1"; - ++index; - - FfmpegBuilderAudioAddTrack ffAddAudioAac = new(); - ffAddAudioAac.Codec = "aac"; - ffAddAudioAac.Index = index; - ffAddAudioAac.Execute(args); - model.AudioStreams[index].Title = "AAC 5.1"; - ++index; - - FfmpegBuilderExecutor ffExecutor = new(); - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - [TestMethod] - public void FfmpegBuilder_AddAc3Aac_Normalize() - { - const string file = @"D:\videos\unprocessed\dummy.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - - FfmpegBuilderVideoCodec ffEncode = new(); - ffEncode.VideoCodec = "h264"; - ffEncode.Execute(args); - - FfmpegBuilderAudioTrackRemover ffAudioRemover = new(); - ffAudioRemover.RemoveAll = true; - ffAudioRemover.Execute(args); - - FfmpegBuilderAudioAddTrack ffAddAudio = new(); - ffAddAudio.Codec = "ac3"; - ffAddAudio.Index = 1; - ffAddAudio.Execute(args); - - FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); - ffAddAudio2.Codec = "aac"; - ffAddAudio2.Index = 2; - ffAddAudio2.Execute(args); - - FfmpegBuilderAudioNormalization ffAudioNormalize = new(); - ffAudioNormalize.TwoPass = false; - ffAudioNormalize.AllAudio = true; - ffAudioNormalize.Execute(args); - - FfmpegBuilderExecutor ffExecutor = new(); - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - [TestMethod] - public void FfmpegBuilder_AddAc3Aac_AdjustVolume() - { - const string file = @"D:\videos\unprocessed\dummy.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - - FfmpegBuilderVideoCodec ffEncode = new(); - ffEncode.VideoCodec = "h264"; - ffEncode.Execute(args); - - FfmpegBuilderAudioTrackRemover ffAudioRemover = new(); - ffAudioRemover.RemoveAll = true; - ffAudioRemover.Execute(args); - - FfmpegBuilderAudioAddTrack ffAddAudio = new(); - ffAddAudio.Codec = "ac3"; - ffAddAudio.Index = 1; - ffAddAudio.Execute(args); - - FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); - ffAddAudio2.Codec = "aac"; - ffAddAudio2.Index = 2; - ffAddAudio2.Execute(args); - - FfmpegBuilderAudioAdjustVolume ffAudioAdjust= new(); - ffAudioAdjust.VolumePercent = 1000; - ffAudioAdjust.Pattern = ">1"; - ffAudioAdjust.Execute(args); - - FfmpegBuilderExecutor ffExecutor = new(); - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - [TestMethod] - public void FfmpegBuilder_AddAc3AacMp4NoSubs() - { - const string file = @"D:\videos\unprocessed\basic.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - - FfmpegBuilderVideoCodec ffEncode = new(); - ffEncode.VideoCodec = "h264"; - ffEncode.Execute(args); - - FfmpegBuilderRemuxToMP4 ffMp4 = new(); - ffMp4.Execute(args); - - - FfmpegBuilderSubtitleFormatRemover ffSubRemover = new(); - ffSubRemover.RemoveAll = true; - ffSubRemover.Execute(args); - - - FfmpegBuilderAudioAddTrack ffAddAudio = new(); - ffAddAudio.Codec = "ac3"; - ffAddAudio.Index = 1; - ffAddAudio.Execute(args); - - FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); - ffAddAudio2.Codec = "aac"; - ffAddAudio2.Index = 2; - ffAddAudio2.Execute(args); - - FfmpegBuilderExecutor ffExecutor = new(); - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - [TestMethod] - public void FfmpegBuilder_AddAc3AacMp4NoSubs_BlackBars() - { - const string file = @"D:\videos\unprocessed\blackbars.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - - FfmpegBuilderVideoCodec ffEncode = new(); - ffEncode.VideoCodec = "h265"; - ffEncode.Execute(args); - - FfmpegBuilderRemuxToMP4 ffMp4 = new(); - ffMp4.Execute(args); - - FfmpegBuilderCropBlackBars ffCropBlackBars = new(); - ffCropBlackBars.CroppingThreshold = 10; - ffCropBlackBars.Execute(args); - - FfmpegBuilderSubtitleFormatRemover ffSubRemover = new(); - ffSubRemover.RemoveAll = true; - ffSubRemover.Execute(args); - - - FfmpegBuilderAudioAddTrack ffAddAudio = new(); - ffAddAudio.Codec = "ac3"; - ffAddAudio.Index = 1; - ffAddAudio.Execute(args); - - FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); - ffAddAudio2.Codec = "aac"; - ffAddAudio2.Index = 2; - ffAddAudio2.Execute(args); - - FfmpegBuilderExecutor ffExecutor = new(); - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - [TestMethod] - public void FfmpegBuilder_AddAc3AacMp4NoSubs_BlackBars_Scaled480p() - { - const string file = @"D:\videos\unprocessed\blackbars.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - - FfmpegBuilderVideoCodec ffEncode = new(); - ffEncode.VideoCodec = "h265"; - ffEncode.Execute(args); - - FfmpegBuilderRemuxToMP4 ffMp4 = new(); - ffMp4.Execute(args); - - FfmpegBuilderCropBlackBars ffCropBlackBars = new(); - ffCropBlackBars.CroppingThreshold = 10; - ffCropBlackBars.Execute(args); - - FfmpegBuilderScaler ffScaler = new(); - ffScaler.Resolution = "640:-2"; - ffScaler.Execute(args); - - FfmpegBuilderSubtitleFormatRemover ffSubRemover = new(); - ffSubRemover.RemoveAll = true; - ffSubRemover.Execute(args); - - - FfmpegBuilderAudioAddTrack ffAddAudio = new(); - ffAddAudio.Codec = "ac3"; - ffAddAudio.Index = 1; - ffAddAudio.Execute(args); - - FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); - ffAddAudio2.Codec = "aac"; - ffAddAudio2.Index = 2; - ffAddAudio2.Execute(args); - - FfmpegBuilderExecutor ffExecutor = new(); - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - - [TestMethod] - public void FfmpegBuilder_AddAc3AacMp4NoSubs_BlackBars_Scaled4k() - { - const string file = @"D:\videos\unprocessed\blackbars.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - - FfmpegBuilderVideoCodec ffEncode = new(); - ffEncode.VideoCodec = "h265"; - ffEncode.Execute(args); - - FfmpegBuilderRemuxToMP4 ffMp4 = new(); - ffMp4.Execute(args); - - FfmpegBuilderCropBlackBars ffCropBlackBars = new(); - ffCropBlackBars.CroppingThreshold = 10; - ffCropBlackBars.Execute(args); - - FfmpegBuilderScaler ffScaler = new(); - ffScaler.Resolution = "3840:-2"; - ffScaler.Execute(args); - - FfmpegBuilderSubtitleFormatRemover ffSubRemover = new(); - ffSubRemover.RemoveAll = true; - ffSubRemover.Execute(args); - - - FfmpegBuilderAudioAddTrack ffAddAudio = new(); - ffAddAudio.Codec = "ac3"; - ffAddAudio.Index = 1; - ffAddAudio.Execute(args); - - FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); - ffAddAudio2.Codec = "aac"; - ffAddAudio2.Index = 2; - ffAddAudio2.Execute(args); - - FfmpegBuilderExecutor ffExecutor = new(); - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - [TestMethod] - public void FfmpegBuilder_AddAc3AacMp4NoSubs_BlackBars_Scaled480p2() - { - const string file = @"D:\videos\unprocessed\basic.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - - FfmpegBuilderVideoCodec ffEncode = new(); - ffEncode.VideoCodec = "h265"; - ffEncode.Execute(args); - - FfmpegBuilderRemuxToMP4 ffMp4 = new(); - ffMp4.Execute(args); - - FfmpegBuilderCropBlackBars ffCropBlackBars = new(); - ffCropBlackBars.CroppingThreshold = 10; - ffCropBlackBars.Execute(args); - - FfmpegBuilderScaler ffScaler = new(); - ffScaler.Resolution = "640:-2"; - ffScaler.Execute(args); - - FfmpegBuilderSubtitleFormatRemover ffSubRemover = new(); - ffSubRemover.RemoveAll = true; - ffSubRemover.Execute(args); - - - FfmpegBuilderAudioAddTrack ffAddAudio = new(); - ffAddAudio.Codec = "ac3"; - ffAddAudio.Index = 1; - ffAddAudio.Execute(args); - - FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); - ffAddAudio2.Codec = "aac"; - ffAddAudio2.Index = 2; - ffAddAudio2.Execute(args); - - FfmpegBuilderExecutor ffExecutor = new(); - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - - [TestMethod] - public void FfmpegBuilder_AddAc3Aac_AutoChapters() - { - const string file = @"D:\videos\unprocessed\sitcom.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - - FfmpegBuilderVideoCodec ffEncode = new(); - ffEncode.VideoCodec = "h264"; - ffEncode.Execute(args); - - FfmpegBuilderAudioAddTrack ffAddAudio = new(); - ffAddAudio.Codec = "ac3"; - ffAddAudio.Index = 1; - ffAddAudio.Execute(args); - - FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); - ffAddAudio2.Codec = "aac"; - ffAddAudio2.Index = 2; - ffAddAudio2.Execute(args); - - FfmpegBuilderAutoChapters ffAutoChapters = new(); - ffAutoChapters.Percent = 45; - ffAutoChapters.MinimumLength = 60; - Assert.AreEqual(1, ffAutoChapters.Execute(args)); - - FfmpegBuilderExecutor ffExecutor = new(); - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - [TestMethod] - public void FfmpegBuilder_AddAc3Aac_ComskipChapters() - { - const string file = @"D:\videos\recordings\Rescue My Renovation (2001).ts"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - - FfmpegBuilderVideoCodec ffEncode = new(); - ffEncode.VideoCodec = "h264"; - ffEncode.Execute(args); - - FfmpegBuilderAudioAddTrack ffAddAudio = new(); - ffAddAudio.Codec = "ac3"; - ffAddAudio.Index = 1; - ffAddAudio.Execute(args); - - FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); - ffAddAudio2.Codec = "aac"; - ffAddAudio2.Index = 2; - ffAddAudio2.Execute(args); - - FfmpegBuilderAudioSetLanguage ffSetLanguage = new(); - ffSetLanguage.Language = "deu"; - ffSetLanguage.Execute(args); - - FfmpegBuilderComskipChapters ffComskipChapters = new(); - Assert.AreEqual(1, ffComskipChapters.Execute(args)); - - FfmpegBuilderExecutor ffExecutor = new(); - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - [TestMethod] - public void FfmpegBuilder_AddAc3Aac_AudioTrackReorder() - { - const string file = @"D:\videos\unprocessed\multi_audio.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - - FfmpegBuilderAudioTrackReorder ffAudioReorder= new(); - ffAudioReorder.Channels = new List { "1.0", "5.1", "2.0" }; - ffAudioReorder.Languages = new List { "fre", "deu" }; - ffAudioReorder.Execute(args); - - FfmpegBuilderExecutor ffExecutor = new(); - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - - [TestMethod] - public void FfmpegBuilder_AddAc3AacMp4NoSubs_BlackBars_Normalize_AutoChapters_Upscale4k() - { - const string file = @"D:\videos\unprocessed\blackbars.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - var model = ffStart.GetModel(); - - FfmpegBuilderVideoCodec ffEncode = new(); - ffEncode.VideoCodec = "h265"; - ffEncode.Execute(args); - - FfmpegBuilderScaler ffScaler = new(); - ffScaler.Resolution = "3840:-2"; - ffScaler.Execute(args); - - FfmpegBuilderRemuxToMP4 ffMp4 = new(); - ffMp4.Execute(args); - - FfmpegBuilderCropBlackBars ffCropBlackBars = new(); - ffCropBlackBars.CroppingThreshold = 10; - ffCropBlackBars.Execute(args); - - FfmpegBuilderSubtitleFormatRemover ffSubRemover = new(); - ffSubRemover.RemoveAll = true; - ffSubRemover.Execute(args); - FfmpegBuilderAudioAddTrack ffAddAudio = new(); - ffAddAudio.Codec = "ac3"; - ffAddAudio.Index = 0; - ffAddAudio.Execute(args); - model.AudioStreams[0].Language = "mao"; - model.AudioStreams[0].Title = "AC3"; - - FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); - ffAddAudio2.Codec = "aac"; - ffAddAudio2.Index = 1; - ffAddAudio2.Execute(args); - model.AudioStreams[1].Language = "fre"; - model.AudioStreams[1].Title = "AAC"; - - FfmpegBuilderAudioNormalization ffAudioNormalize = new(); - ffAudioNormalize.TwoPass = false; - ffAudioNormalize.AllAudio = true; - ffAudioNormalize.Execute(args); - - - FfmpegBuilderAutoChapters ffaAutoChapters = new(); - ffaAutoChapters.MinimumLength = 30; - ffaAutoChapters.Percent = 45; - ffaAutoChapters.Execute(args); - - FfmpegBuilderExecutor ffExecutor = new(); - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - - [TestMethod] - public void FfmpegBuilder_SetLanguage() - { - const string file = @"D:\videos\unprocessed\sitcom.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - - FfmpegBuilderAudioSetLanguage ffSetLanguage = new(); - ffSetLanguage.Language = "deu"; - ffSetLanguage.Execute(args); - - FfmpegBuilderExecutor ffExecutor = new(); - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - [TestMethod] - public void FfmpegBuilder_HdrToSdr() - { - const string file = @"D:\videos\unprocessed\hdr.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - - FfmpegBuilderHdrToSdr ffHdrToSdr= new(); - Assert.AreEqual(1, ffHdrToSdr.Execute(args)); - - FfmpegBuilderExecutor ffExecutor = new(); - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - - [TestMethod] - public void FfmpegBuilder_AudioMinusOne() - { - const string file = @"D:\videos\unprocessed\minus1.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - - //FfmpegBuilderVideoCodec ffEncode = new(); - //ffEncode.VideoCodec = "h264"; - //ffEncode.Execute(args); - - FfmpegBuilderAudioTrackRemover ffAudioRemover = new(); - ffAudioRemover.RemoveAll = true; - ffAudioRemover.Execute(args); - - FfmpegBuilderAudioAddTrack ffAddAudio = new(); - ffAddAudio.Codec = "ac3"; - ffAddAudio.Index = 0; - ffAddAudio.Execute(args); - - //FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); - //ffAddAudio2.Codec = "aac"; - //ffAddAudio2.Index = 2; - //ffAddAudio2.Execute(args); - - //FfmpegBuilderAudioNormalization ffAudioNormalize = new(); - //ffAudioNormalize.TwoPass = false; - //ffAudioNormalize.AllAudio = true; - //ffAudioNormalize.Execute(args); - - FfmpegBuilderExecutor ffExecutor = new(); - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - - [TestMethod] - public void FfmpegBuilder_HardwareDecoding() - { - const string file = @"D:\videos\unprocessed\basic.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - - FfmpegBuilderVideoCodec ffEncode = new(); - ffEncode.VideoCodec = "h264"; - ffEncode.Execute(args); - - - FfmpegBuilderAudioAddTrack ffAddAudio = new(); - ffAddAudio.Codec = "ac3"; - ffAddAudio.Index = 0; - ffAddAudio.Execute(args); - - FfmpegBuilderExecutor ffExecutor = new(); - ffExecutor.HardwareDecoding = true; - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - - [TestMethod] - public void FfmpegBuilder_VideoBitrate() - { - const string file = @"D:\videos\unprocessed\basic.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - - FfmpegBuilderVideoBitrate ffBitrate = new(); - ffBitrate.Bitrate = 1_000; - ffBitrate.Execute(args); - - FfmpegBuilderExecutor ffExecutor = new(); - ffExecutor.HardwareDecoding = true; - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - [TestMethod] - public void FfmpegBuilder_VideoCodecAndBitrate() - { - const string file = @"D:\videos\unprocessed\basic.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - - FfmpegBuilderVideoCodec ffEncode = new(); - ffEncode.VideoCodec = "h264"; - ffEncode.Force = true; - ffEncode.Execute(args); - - FfmpegBuilderVideoBitrate ffBitrate = new(); - ffBitrate.Bitrate = 50; - ffBitrate.Percent = true; - ffBitrate.Execute(args); - - FfmpegBuilderExecutor ffExecutor = new(); - ffExecutor.HardwareDecoding = true; - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - [TestMethod] - public void FfmpegBuilder_FF43() - { - const string file = @"D:\videos\testfiles\ff-43.ts"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - - FfmpegBuilderAudioTrackRemover ffRemoveAudio = new(); - ffRemoveAudio.RemoveAll = true; - ffRemoveAudio.Execute(args); - - FfmpegBuilderAudioAddTrack ffAddAudio = new(); - ffAddAudio.Codec = "ac3"; - ffAddAudio.Index = 0; - ffAddAudio.Execute(args); - - FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); - ffAddAudio2.Codec = "aac"; - ffAddAudio2.Index = 1; - ffAddAudio2.Execute(args); - - FfmpegBuilderExecutor ffExecutor = new(); - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - - [TestMethod] - public void FfmpegBuilder_AddAc3Aac_AV1() - { - const string file = @"D:\videos\testfiles\av1.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg5\ffmpeg.exe"; - VideoInfoHelper.ProbeSize = 1000; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - - FfmpegBuilderStart ffStart = new(); - - Assert.AreEqual(1, ffStart.Execute(args)); - - FfmpegBuilderAudioTrackRemover ffAudioRemove = new(); - ffAudioRemove.RemoveAll = true; - ffAudioRemove.Execute(args); - - //FfmpegBuilderAudioAddTrack ffAddAudio = new(); - //ffAddAudio.Codec = "ac3"; - //ffAddAudio.Language = "eng"; - //ffAddAudio.Index = 0; - //ffAddAudio.Execute(args); - - FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); - ffAddAudio2.Codec = "aac"; - ffAddAudio2.Language = "deu"; - ffAddAudio2.Index = 1; - ffAddAudio2.Execute(args); - - FfmpegBuilderSubtitleFormatRemover ffSubtitle= new(); - ffSubtitle.RemoveAll = true; - ffSubtitle.Execute(args); - - FfmpegBuilderExecutor ffExecutor = new(); - - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } + FfmpegBuilderExecutor ffExecutor = new(); + int result = ffExecutor.Execute(args); + string log = logger.ToString(); + Assert.AreEqual(1, result); } + + [TestMethod] + public void FfmpegBuilder_AddAudioTracks() + { + const string file = @"D:\videos\unprocessed\bigbuckbunny_480p_30s.mp4"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + var model = ffStart.GetModel(); + if (model.AudioStreams[0].Stream.Channels < 5.1f) + Assert.Fail(); + + FfmpegBuilderVideoCodec ffEncode = new(); + ffEncode.VideoCodec = "h264"; + ffEncode.Execute(args); + + int index = 0; + FfmpegBuilderAudioAddTrack ffAddAudioMono = new(); + ffAddAudioMono.Codec = "mp3"; + ffAddAudioMono.Index = index; + ffAddAudioMono.Channels = 1; + ffAddAudioMono.Execute(args); + model.AudioStreams[index].Title = "MP3 Mono"; + ++index; + + FfmpegBuilderAudioAddTrack ffAddAudioStereoAac = new(); + ffAddAudioStereoAac.Codec = "aac"; + ffAddAudioStereoAac.Index = index; + ffAddAudioStereoAac.Channels = 2; + ffAddAudioStereoAac.Execute(args); + model.AudioStreams[index].Title = "AAC Stereo"; + ++index; + + FfmpegBuilderAudioAddTrack ffAddAudioStereoMp3French = new(); + ffAddAudioStereoMp3French.Codec = "mp3"; + ffAddAudioStereoMp3French.Index = index; + ffAddAudioStereoMp3French.Channels = 2; + ffAddAudioStereoMp3French.Execute(args); + model.AudioStreams[index].Language = "fre"; + model.AudioStreams[index].Title = "MP3 Stereo"; + ++index; + + FfmpegBuilderAudioAddTrack ffAddAudioStereoMp3 = new(); + ffAddAudioStereoMp3.Codec = "mp3"; + ffAddAudioStereoMp3.Index = index; + ffAddAudioStereoMp3.Channels = 2; + ffAddAudioStereoMp3.Execute(args); + model.AudioStreams[index].Title = "MP3 Stereo"; + ++index; + + FfmpegBuilderAudioAddTrack ffAddAudioAc3German = new(); + ffAddAudioAc3German.Codec = "ac3"; + ffAddAudioAc3German.Index = index; + ffAddAudioAc3German.Execute(args); + model.AudioStreams[index].Title = "AC3 5.1"; + model.AudioStreams[index].Language = "deu"; + ++index; + + FfmpegBuilderAudioAddTrack ffAddAudioAc3 = new(); + ffAddAudioAc3.Codec = "ac3"; + ffAddAudioAc3.Index = index; + ffAddAudioAc3.Execute(args); + model.AudioStreams[index].Title = "AC3 5.1"; + ++index; + + FfmpegBuilderAudioAddTrack ffAddAudioAac = new(); + ffAddAudioAac.Codec = "aac"; + ffAddAudioAac.Index = index; + ffAddAudioAac.Execute(args); + model.AudioStreams[index].Title = "AAC 5.1"; + ++index; + + FfmpegBuilderExecutor ffExecutor = new(); + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + [TestMethod] + public void FfmpegBuilder_AddAc3Aac_Normalize() + { + const string file = @"D:\videos\unprocessed\dummy.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderVideoCodec ffEncode = new(); + ffEncode.VideoCodec = "h264"; + ffEncode.Execute(args); + + FfmpegBuilderAudioTrackRemover ffAudioRemover = new(); + ffAudioRemover.RemoveAll = true; + ffAudioRemover.Execute(args); + + FfmpegBuilderAudioAddTrack ffAddAudio = new(); + ffAddAudio.Codec = "ac3"; + ffAddAudio.Index = 1; + ffAddAudio.Execute(args); + + FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); + ffAddAudio2.Codec = "aac"; + ffAddAudio2.Index = 2; + ffAddAudio2.Execute(args); + + FfmpegBuilderAudioNormalization ffAudioNormalize = new(); + ffAudioNormalize.TwoPass = false; + ffAudioNormalize.AllAudio = true; + ffAudioNormalize.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + [TestMethod] + public void FfmpegBuilder_AddAc3Aac_AdjustVolume() + { + const string file = @"D:\videos\unprocessed\dummy.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderVideoCodec ffEncode = new(); + ffEncode.VideoCodec = "h264"; + ffEncode.Execute(args); + + FfmpegBuilderAudioTrackRemover ffAudioRemover = new(); + ffAudioRemover.RemoveAll = true; + ffAudioRemover.Execute(args); + + FfmpegBuilderAudioAddTrack ffAddAudio = new(); + ffAddAudio.Codec = "ac3"; + ffAddAudio.Index = 1; + ffAddAudio.Execute(args); + + FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); + ffAddAudio2.Codec = "aac"; + ffAddAudio2.Index = 2; + ffAddAudio2.Execute(args); + + FfmpegBuilderAudioAdjustVolume ffAudioAdjust= new(); + ffAudioAdjust.VolumePercent = 1000; + ffAudioAdjust.Pattern = ">1"; + ffAudioAdjust.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + [TestMethod] + public void FfmpegBuilder_AddAc3AacMp4NoSubs() + { + const string file = @"D:\videos\unprocessed\basic.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderVideoCodec ffEncode = new(); + ffEncode.VideoCodec = "h264"; + ffEncode.Execute(args); + + FfmpegBuilderRemuxToMP4 ffMp4 = new(); + ffMp4.Execute(args); + + + FfmpegBuilderSubtitleFormatRemover ffSubRemover = new(); + ffSubRemover.RemoveAll = true; + ffSubRemover.Execute(args); + + + FfmpegBuilderAudioAddTrack ffAddAudio = new(); + ffAddAudio.Codec = "ac3"; + ffAddAudio.Index = 1; + ffAddAudio.Execute(args); + + FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); + ffAddAudio2.Codec = "aac"; + ffAddAudio2.Index = 2; + ffAddAudio2.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + [TestMethod] + public void FfmpegBuilder_AddAc3AacMp4NoSubs_BlackBars() + { + const string file = @"D:\videos\unprocessed\blackbars.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderVideoCodec ffEncode = new(); + ffEncode.VideoCodec = "h265"; + ffEncode.Execute(args); + + FfmpegBuilderRemuxToMP4 ffMp4 = new(); + ffMp4.Execute(args); + + FfmpegBuilderCropBlackBars ffCropBlackBars = new(); + ffCropBlackBars.CroppingThreshold = 10; + ffCropBlackBars.Execute(args); + + FfmpegBuilderSubtitleFormatRemover ffSubRemover = new(); + ffSubRemover.RemoveAll = true; + ffSubRemover.Execute(args); + + + FfmpegBuilderAudioAddTrack ffAddAudio = new(); + ffAddAudio.Codec = "ac3"; + ffAddAudio.Index = 1; + ffAddAudio.Execute(args); + + FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); + ffAddAudio2.Codec = "aac"; + ffAddAudio2.Index = 2; + ffAddAudio2.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + [TestMethod] + public void FfmpegBuilder_AddAc3AacMp4NoSubs_BlackBars_Scaled480p() + { + const string file = @"D:\videos\unprocessed\blackbars.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderVideoCodec ffEncode = new(); + ffEncode.VideoCodec = "h265"; + ffEncode.Execute(args); + + FfmpegBuilderRemuxToMP4 ffMp4 = new(); + ffMp4.Execute(args); + + FfmpegBuilderCropBlackBars ffCropBlackBars = new(); + ffCropBlackBars.CroppingThreshold = 10; + ffCropBlackBars.Execute(args); + + FfmpegBuilderScaler ffScaler = new(); + ffScaler.Resolution = "640:-2"; + ffScaler.Execute(args); + + FfmpegBuilderSubtitleFormatRemover ffSubRemover = new(); + ffSubRemover.RemoveAll = true; + ffSubRemover.Execute(args); + + + FfmpegBuilderAudioAddTrack ffAddAudio = new(); + ffAddAudio.Codec = "ac3"; + ffAddAudio.Index = 1; + ffAddAudio.Execute(args); + + FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); + ffAddAudio2.Codec = "aac"; + ffAddAudio2.Index = 2; + ffAddAudio2.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + + [TestMethod] + public void FfmpegBuilder_AddAc3AacMp4NoSubs_BlackBars_Scaled4k() + { + const string file = @"D:\videos\unprocessed\blackbars.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderVideoCodec ffEncode = new(); + ffEncode.VideoCodec = "h265"; + ffEncode.Execute(args); + + FfmpegBuilderRemuxToMP4 ffMp4 = new(); + ffMp4.Execute(args); + + FfmpegBuilderCropBlackBars ffCropBlackBars = new(); + ffCropBlackBars.CroppingThreshold = 10; + ffCropBlackBars.Execute(args); + + FfmpegBuilderScaler ffScaler = new(); + ffScaler.Resolution = "3840:-2"; + ffScaler.Execute(args); + + FfmpegBuilderSubtitleFormatRemover ffSubRemover = new(); + ffSubRemover.RemoveAll = true; + ffSubRemover.Execute(args); + + + FfmpegBuilderAudioAddTrack ffAddAudio = new(); + ffAddAudio.Codec = "ac3"; + ffAddAudio.Index = 1; + ffAddAudio.Execute(args); + + FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); + ffAddAudio2.Codec = "aac"; + ffAddAudio2.Index = 2; + ffAddAudio2.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + [TestMethod] + public void FfmpegBuilder_AddAc3AacMp4NoSubs_BlackBars_Scaled480p2() + { + const string file = @"D:\videos\unprocessed\basic.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderVideoCodec ffEncode = new(); + ffEncode.VideoCodec = "h265"; + ffEncode.Execute(args); + + FfmpegBuilderRemuxToMP4 ffMp4 = new(); + ffMp4.Execute(args); + + FfmpegBuilderCropBlackBars ffCropBlackBars = new(); + ffCropBlackBars.CroppingThreshold = 10; + ffCropBlackBars.Execute(args); + + FfmpegBuilderScaler ffScaler = new(); + ffScaler.Resolution = "640:-2"; + ffScaler.Execute(args); + + FfmpegBuilderSubtitleFormatRemover ffSubRemover = new(); + ffSubRemover.RemoveAll = true; + ffSubRemover.Execute(args); + + + FfmpegBuilderAudioAddTrack ffAddAudio = new(); + ffAddAudio.Codec = "ac3"; + ffAddAudio.Index = 1; + ffAddAudio.Execute(args); + + FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); + ffAddAudio2.Codec = "aac"; + ffAddAudio2.Index = 2; + ffAddAudio2.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + + [TestMethod] + public void FfmpegBuilder_AddAc3Aac_AutoChapters() + { + const string file = @"D:\videos\unprocessed\sitcom.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderVideoCodec ffEncode = new(); + ffEncode.VideoCodec = "h264"; + ffEncode.Execute(args); + + FfmpegBuilderAudioAddTrack ffAddAudio = new(); + ffAddAudio.Codec = "ac3"; + ffAddAudio.Index = 1; + ffAddAudio.Execute(args); + + FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); + ffAddAudio2.Codec = "aac"; + ffAddAudio2.Index = 2; + ffAddAudio2.Execute(args); + + FfmpegBuilderAutoChapters ffAutoChapters = new(); + ffAutoChapters.Percent = 45; + ffAutoChapters.MinimumLength = 60; + Assert.AreEqual(1, ffAutoChapters.Execute(args)); + + FfmpegBuilderExecutor ffExecutor = new(); + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + [TestMethod] + public void FfmpegBuilder_AddAc3Aac_ComskipChapters() + { + const string file = @"D:\videos\recordings\Rescue My Renovation (2001).ts"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderVideoCodec ffEncode = new(); + ffEncode.VideoCodec = "h264"; + ffEncode.Execute(args); + + FfmpegBuilderAudioAddTrack ffAddAudio = new(); + ffAddAudio.Codec = "ac3"; + ffAddAudio.Index = 1; + ffAddAudio.Execute(args); + + FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); + ffAddAudio2.Codec = "aac"; + ffAddAudio2.Index = 2; + ffAddAudio2.Execute(args); + + FfmpegBuilderAudioSetLanguage ffSetLanguage = new(); + ffSetLanguage.Language = "deu"; + ffSetLanguage.Execute(args); + + FfmpegBuilderComskipChapters ffComskipChapters = new(); + Assert.AreEqual(1, ffComskipChapters.Execute(args)); + + FfmpegBuilderExecutor ffExecutor = new(); + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + [TestMethod] + public void FfmpegBuilder_AddAc3Aac_AudioTrackReorder() + { + const string file = @"D:\videos\unprocessed\multi_audio.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderAudioTrackReorder ffAudioReorder= new(); + ffAudioReorder.Channels = new List { "1.0", "5.1", "2.0" }; + ffAudioReorder.Languages = new List { "fre", "deu" }; + ffAudioReorder.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + + [TestMethod] + public void FfmpegBuilder_AddAc3AacMp4NoSubs_BlackBars_Normalize_AutoChapters_Upscale4k() + { + const string file = @"D:\videos\unprocessed\blackbars.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + var model = ffStart.GetModel(); + + FfmpegBuilderVideoCodec ffEncode = new(); + ffEncode.VideoCodec = "h265"; + ffEncode.Execute(args); + + FfmpegBuilderScaler ffScaler = new(); + ffScaler.Resolution = "3840:-2"; + ffScaler.Execute(args); + + FfmpegBuilderRemuxToMP4 ffMp4 = new(); + ffMp4.Execute(args); + + FfmpegBuilderCropBlackBars ffCropBlackBars = new(); + ffCropBlackBars.CroppingThreshold = 10; + ffCropBlackBars.Execute(args); + + FfmpegBuilderSubtitleFormatRemover ffSubRemover = new(); + ffSubRemover.RemoveAll = true; + ffSubRemover.Execute(args); + FfmpegBuilderAudioAddTrack ffAddAudio = new(); + ffAddAudio.Codec = "ac3"; + ffAddAudio.Index = 0; + ffAddAudio.Execute(args); + model.AudioStreams[0].Language = "mao"; + model.AudioStreams[0].Title = "AC3"; + + FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); + ffAddAudio2.Codec = "aac"; + ffAddAudio2.Index = 1; + ffAddAudio2.Execute(args); + model.AudioStreams[1].Language = "fre"; + model.AudioStreams[1].Title = "AAC"; + + FfmpegBuilderAudioNormalization ffAudioNormalize = new(); + ffAudioNormalize.TwoPass = false; + ffAudioNormalize.AllAudio = true; + ffAudioNormalize.Execute(args); + + + FfmpegBuilderAutoChapters ffaAutoChapters = new(); + ffaAutoChapters.MinimumLength = 30; + ffaAutoChapters.Percent = 45; + ffaAutoChapters.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + + [TestMethod] + public void FfmpegBuilder_SetLanguage() + { + const string file = @"D:\videos\unprocessed\sitcom.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderAudioSetLanguage ffSetLanguage = new(); + ffSetLanguage.Language = "deu"; + ffSetLanguage.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + [TestMethod] + public void FfmpegBuilder_HdrToSdr() + { + const string file = @"D:\videos\unprocessed\hdr.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderHdrToSdr ffHdrToSdr= new(); + Assert.AreEqual(1, ffHdrToSdr.Execute(args)); + + FfmpegBuilderExecutor ffExecutor = new(); + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + + [TestMethod] + public void FfmpegBuilder_AudioMinusOne() + { + const string file = @"D:\videos\unprocessed\minus1.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + + //FfmpegBuilderVideoCodec ffEncode = new(); + //ffEncode.VideoCodec = "h264"; + //ffEncode.Execute(args); + + FfmpegBuilderAudioTrackRemover ffAudioRemover = new(); + ffAudioRemover.RemoveAll = true; + ffAudioRemover.Execute(args); + + FfmpegBuilderAudioAddTrack ffAddAudio = new(); + ffAddAudio.Codec = "ac3"; + ffAddAudio.Index = 0; + ffAddAudio.Execute(args); + + //FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); + //ffAddAudio2.Codec = "aac"; + //ffAddAudio2.Index = 2; + //ffAddAudio2.Execute(args); + + //FfmpegBuilderAudioNormalization ffAudioNormalize = new(); + //ffAudioNormalize.TwoPass = false; + //ffAudioNormalize.AllAudio = true; + //ffAudioNormalize.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + + [TestMethod] + public void FfmpegBuilder_HardwareDecoding() + { + const string file = @"D:\videos\unprocessed\basic.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderVideoCodec ffEncode = new(); + ffEncode.VideoCodec = "h264"; + ffEncode.Execute(args); + + + FfmpegBuilderAudioAddTrack ffAddAudio = new(); + ffAddAudio.Codec = "ac3"; + ffAddAudio.Index = 0; + ffAddAudio.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + ffExecutor.HardwareDecoding = true; + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + + [TestMethod] + public void FfmpegBuilder_VideoBitrate() + { + const string file = @"D:\videos\unprocessed\basic.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderVideoBitrate ffBitrate = new(); + ffBitrate.Bitrate = 1_000; + ffBitrate.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + ffExecutor.HardwareDecoding = true; + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + [TestMethod] + public void FfmpegBuilder_VideoCodecAndBitrate() + { + const string file = @"D:\videos\unprocessed\basic.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderVideoCodec ffEncode = new(); + ffEncode.VideoCodec = "h264"; + ffEncode.Force = true; + ffEncode.Execute(args); + + FfmpegBuilderVideoBitrate ffBitrate = new(); + ffBitrate.Bitrate = 50; + ffBitrate.Percent = true; + ffBitrate.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + ffExecutor.HardwareDecoding = true; + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + [TestMethod] + public void FfmpegBuilder_FF43() + { + const string file = @"D:\videos\testfiles\ff-43.ts"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderAudioTrackRemover ffRemoveAudio = new(); + ffRemoveAudio.RemoveAll = true; + ffRemoveAudio.Execute(args); + + FfmpegBuilderAudioAddTrack ffAddAudio = new(); + ffAddAudio.Codec = "ac3"; + ffAddAudio.Index = 0; + ffAddAudio.Execute(args); + + FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); + ffAddAudio2.Codec = "aac"; + ffAddAudio2.Index = 1; + ffAddAudio2.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + + [TestMethod] + public void FfmpegBuilder_AddAc3Aac_AV1() + { + const string file = @"D:\videos\testfiles\av1.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg5\ffmpeg.exe"; + VideoInfoHelper.ProbeSize = 1000; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderAudioTrackRemover ffAudioRemove = new(); + ffAudioRemove.RemoveAll = true; + ffAudioRemove.Execute(args); + + //FfmpegBuilderAudioAddTrack ffAddAudio = new(); + //ffAddAudio.Codec = "ac3"; + //ffAddAudio.Language = "eng"; + //ffAddAudio.Index = 0; + //ffAddAudio.Execute(args); + + FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); + ffAddAudio2.Codec = "aac"; + ffAddAudio2.Language = "deu"; + ffAddAudio2.Index = 1; + ffAddAudio2.Execute(args); + + FfmpegBuilderSubtitleFormatRemover ffSubtitle= new(); + ffSubtitle.RemoveAll = true; + ffSubtitle.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + } #endif \ No newline at end of file diff --git a/VideoNodes/Tests/FfmpegBuilderTests/FfmpegBuilder_VideoEncodeTests.cs b/VideoNodes/Tests/FfmpegBuilderTests/FfmpegBuilder_VideoEncodeTests.cs new file mode 100644 index 00000000..c27cd63e --- /dev/null +++ b/VideoNodes/Tests/FfmpegBuilderTests/FfmpegBuilder_VideoEncodeTests.cs @@ -0,0 +1,83 @@ +#if(DEBUG) + +using FileFlows.VideoNodes.FfmpegBuilderNodes; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using VideoNodes.Tests; + +namespace FileFlows.VideoNodes.Tests.FfmpegBuilderTests; + +[TestClass] +public class FfmpegBuilder_VideoEncode_VideoEncodeTests: TestBase +{ + private (int output, string log) Encode(string codec, int quality, bool hardwareEncoding, string file, string outfile) + { + if (File.Exists(file) == false) + throw new FileNotFoundException(file); + + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + ffStart.PreExecute(args); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderVideoEncode ffEncode = new(); + ffEncode.Codec = codec; + ffEncode.Quality = quality; + ffEncode.HardwareEncoding = hardwareEncoding; + ffEncode.PreExecute(args); + ffEncode.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + ffExecutor.PreExecute(args); + int result = ffExecutor.Execute(args); + string log = logger.ToString(); + if(args.WorkingFile.StartsWith(args.TempPath)) + File.Move(args.WorkingFile, Path.Combine(args.TempPath, outfile), true); + Assert.AreEqual(1, result); + return (result, log); + } + + private void TestEncode(bool h265, bool bit10, bool hardware) + { + foreach (var quality in new int[] { 18, 20, 23, 28, 35, 50 }) + { + string codec = h265 && bit10 ? FfmpegBuilderVideoEncode.CODEC_H265_10BIT : + h265 ? FfmpegBuilderVideoEncode.CODEC_H265 : + bit10 ? FfmpegBuilderVideoEncode.CODEC_H264_10BIT : + FfmpegBuilderVideoEncode.CODEC_H264; + + var result = Encode(codec, quality, hardware, TestFile_120_mbps_4k_uhd_hevc_10bit, + $"{(hardware ? "nvidia" : "cpu")}_h26{(h265 ? "5" : "4")}{(bit10 ? "_10bit" : "")}_{quality}.mkv"); + } + + } + + [TestMethod] + public void FfmpegBuilder_VideoEncode_H265_10bit_Hardware() => TestEncode(true, true, true); + [TestMethod] + public void FfmpegBuilder_VideoEncode_H265_Hardware() => TestEncode(true, false, true); + [TestMethod] + public void FfmpegBuilder_VideoEncode_H265() => TestEncode(true, false, false); + [TestMethod] + public void FfmpegBuilder_VideoEncode_H265_10bit() => TestEncode(true, false, true); + + + [TestMethod] + public void FfmpegBuilder_VideoEncode_H264_10bit_Hardware() => TestEncode(false, true, true); + [TestMethod] + public void FfmpegBuilder_VideoEncode_H264_Hardware() => TestEncode(false, false, true); + [TestMethod] + public void FfmpegBuilder_VideoEncode_H264() => TestEncode(false, false, false); + [TestMethod] + public void FfmpegBuilder_VideoEncode_H264_10bit() => TestEncode(false, false, true); +} + +#endif \ No newline at end of file diff --git a/VideoNodes/Tests/_TestBase.cs b/VideoNodes/Tests/_TestBase.cs index d0b2777f..f29f2200 100644 --- a/VideoNodes/Tests/_TestBase.cs +++ b/VideoNodes/Tests/_TestBase.cs @@ -52,6 +52,10 @@ public abstract class TestBase protected string TestFile_BasicMkv => Path.Combine(TestPath, "basic.mkv"); protected string TestFile_Pgs => Path.Combine(TestPath, "pgs.mkv"); protected string TestFile_TwoPassNegInifinity => Path.Combine(TestPath, "audio_normal_neg_infinity.mkv"); + protected string TestFile_4k_h264mov => Path.Combine(TestPath, "4k_h264.mov"); + + protected string TestFile_50_mbps_hd_h264 => Path.Combine(TestPath, "50-mbps-hd-h264.mkv"); + protected string TestFile_120_mbps_4k_uhd_hevc_10bit => Path.Combine(TestPath, "120-mbps-4k-uhd-hevc-10bit.mkv"); private class TestSettings { diff --git a/VideoNodes/VideoNodes.csproj b/VideoNodes/VideoNodes.csproj index 1b68acfdd3a977a265f456de0fe7d4381b26de9f..5ae7800637ee79a90c4856cf1a8d0a88694a985a 100644 GIT binary patch literal 4098 zcmeH~S#J|j42As)68~XTAr&N;v}GxR5>%E#5tN7qctJu#leU30sj>i-`0c=Vd~-WX z7RvU9qGV=reUI&9U)%Hj+lJkIOYD=iZD2#|Sl@bf*OqM6Qd{Agu+p6`=M$-WOb!^tkP4{QRYG_?7 zFFSJdZP1S4NFH>+dF3pLhauSFCbRdfx3Rfqi>1rRJ2qxt_jLa>+O$L&VcR3q1*e7n zO-Flx-#zS-4?cpnX@4;-V^u;8Cv$S ziPaslN?F=k$VOGNh^aU$Gc)3R0!s9A3oiR)|Iod!N)-_{@peRvlp)IHr`#QamXJw3 zEE`~7#Hq>_amqZ@VXx!)*av9`Oyy>9DY{^%qJ$yiHXVM`Ya53zTI&qKRS zWNTz}$f*5OpHnczOU=D+fc7)Yq74t-QdO!BT1NcpEY%BMBMNRTD_#bcrKf)FlM@VOUqu;5=U>>JM-e0o2 zkH#JL>r@P3NRd;mNM>YqY8UO2J*T?dhezc=tCBGhDYciNi0^=R$vfJTT>*E=-toQ6 zM|EP64YDNIH&<9vjr&_L4L09e0&pomRz5u&OwTX%=5JKR4Mk#E*QEPAcFWQ_Pw zkDnFYd|rzESp8Y@DQ{DHW9m&+?@$4Sea!UNad#H+nG~E z5iKQ?^>!w%rZI|)1U0Pn<4zY#)u2*p({!F@vFZpRU@@}s6d3h)tt(WKN Gu=fWbdX6;! literal 1999 zcmd5--*4MC5PpvT3PK3r1n4N+Yn@<`S$Iypb!a^!cDk1V10$VmHWVq4R8j-|<9j6K zA8`T{1NzVxN%!&N-SO`DDSP{+lH>u56eGn*zpCPPB5M+*F$d$nxD6XL#Tk-*!2Qak}wq*F>Za1$H1QQDOQyA=#cj5;5DB35ROEwSJC9|1@6&G z=fqbxrm-}ls-Sq9!xjw0iLPp{Hp~Z{O8scFbPI*`apTt7SoW7*D>7Dv0Z-YYF;>is zeG&y|GSdYhqfLrM2G8&L3J~*iacd-7J6GG^(zL{|r4LJUU8T6~88bMz2AdmEJDfWf z0+3Q0QX8Fv_1z~AA-4BsDIv?Xu%wpFN+^ zEZVYo61{<1BJV6A$t#llmzuzg)zWohd%y7$hpZy(?RB*S@sV*mIf-hc#d;io_3N%r1B6(sSn zh2&WeyJR#Xv2(sumw1nYtflU7Pl$S-KmYkB%TM~kr8KgI>G z9hhYAWIzY>@_+f*>HN!HP;R%ih<}U&GmI!swO8u>L4yDVd7z-^XRB2^&3HW~y521H z-;JvqcP$LckTx4OmXCZBB=4owII5_JAr2!X4CX-^-aarxRxdPQ9+YUG%b!BIId^MD x>A!nDh%8!2nWZ~MNCBfPYRE+?@~!+&xwQC0I)>YfcRBdW{IrfiJG=_B&NowniMap( diff --git a/VideoNodes/VideoNodes.en.json b/VideoNodes/VideoNodes.en.json index 289a0168..4e9c1251 100644 --- a/VideoNodes/VideoNodes.en.json +++ b/VideoNodes/VideoNodes.en.json @@ -1,591 +1,596 @@ { - "Flow":{ - "Parts": { - "AudioAddTrack": { - "Outputs": { - "1": "Audio track added and saved to temporary file" - }, - "Description": "Adds a new audio track to the video file, all other audio tracks will remain. This will use the first audio track of the file as the source audio track to convert.", - "Fields": { - "Index": "Index", - "Index-Help": "The index where to insert the new audio track. 0 based, so to insert the new audio track as the first track set this to 0.", - "Channels": "Channels", - "Channels-Help": "The number of channels to convert this audio track to.", - "Bitrate": "Bitrate", - "Bitrate-Help": "Bitrate of the new audio track" - } + "H": { + "264": "H.264", + "265": "H.265" + }, + "Flow": { + "Parts": { + "AudioAddTrack": { + "Outputs": { + "1": "Audio track added and saved to temporary file" + }, + "Description": "Adds a new audio track to the video file, all other audio tracks will remain. This will use the first audio track of the file as the source audio track to convert.", + "Fields": { + "Index": "Index", + "Index-Help": "The index where to insert the new audio track. 0 based, so to insert the new audio track as the first track set this to 0.", + "Channels": "Channels", + "Channels-Help": "The number of channels to convert this audio track to.", + "Bitrate": "Bitrate", + "Bitrate-Help": "Bitrate of the new audio track" + } + }, + "AudioAdjustVolume": { + "Outputs": { + "1": "Audio tracks volume was adjusted and saved to temporary file", + "2": "Audio tracks were not adjusted" }, - "AudioAdjustVolume": { - "Outputs": { - "1": "Audio tracks volume was adjusted and saved to temporary file", - "2": "Audio tracks were not adjusted" - }, - "Description": "Adjusts audio tracks volume in a video file using FFMPEG", - "Fields": { - "VolumePercent": "Volume Percent", - "VolumePercent-Help": "The percent of the adjusted volume.\n100 means no adjustment\n50 means half volume\n0 means muted" - } + "Description": "Adjusts audio tracks volume in a video file using FFMPEG", + "Fields": { + "VolumePercent": "Volume Percent", + "VolumePercent-Help": "The percent of the adjusted volume.\n100 means no adjustment\n50 means half volume\n0 means muted" + } + }, + "AudioNormalization": { + "Outputs": { + "1": "Audio tracks were normalized and saved to temporary file", + "2": "No audio tracks were found to be normalized" }, - "AudioNormalization": { - "Outputs": { - "1": "Audio tracks were normalized and saved to temporary file", - "2": "No audio tracks were found to be normalized" - }, - "Description": "Normalizes all audio tracks in a video file using FFMPEGs loudnorm filter", - "Fields": { - "AllAudio": "All Audio Tracks", - "AllAudio-Help": "If all audio tracks should be normalized or if just the first track should be", - "TwoPass": "Two Pass", - "TwoPass-Help": "If the audio tracks should use two pass normalization. This improves the normalization but increases the processing time.", - "Pattern": "Pattern", - "Pattern-Help": "An optional regular expression to filter out audio tracks to normalize. Will match against the title, codec and language", - "NotMatching": "Not Matching", - "NotMatching-Help": "If the pattern should be used to exclude audio tracks from normalization, otherwise if the audio track matches they will be normalized." - } + "Description": "Normalizes all audio tracks in a video file using FFMPEGs loudnorm filter", + "Fields": { + "AllAudio": "All Audio Tracks", + "AllAudio-Help": "If all audio tracks should be normalized or if just the first track should be", + "TwoPass": "Two Pass", + "TwoPass-Help": "If the audio tracks should use two pass normalization. This improves the normalization but increases the processing time.", + "Pattern": "Pattern", + "Pattern-Help": "An optional regular expression to filter out audio tracks to normalize. Will match against the title, codec and language", + "NotMatching": "Not Matching", + "NotMatching-Help": "If the pattern should be used to exclude audio tracks from normalization, otherwise if the audio track matches they will be normalized." + } + }, + "AudioTrackRemover": { + "Outputs": { + "1": "Audio tracks were removed", + "2": "Audio tracks were NOT removed" }, - "AudioTrackRemover": { - "Outputs": { - "1": "Audio tracks were removed", - "2": "Audio tracks were NOT removed" - }, - "Description": "Allows you to remove audio tracks based on either their title or their language codes.\n\nAny title (or language code if set to \"Use Language Code\") that is blank will NOT be removed regardless of the pattern.", - "Fields": { - "Pattern": "Pattern", - "Pattern-Help": "A regular expression to match against, eg \"commentary\" to remove commentary tracks", - "NotMatching": "Not Matching", - "NotMatching-Help": "If audio tracks NOT matching the pattern should be removed", - "UseLanguageCode": "Use Language Code", - "UseLanguageCode-Help": "If the language code of the audio track should be used instead of the title" - } + "Description": "Allows you to remove audio tracks based on either their title or their language codes.\n\nAny title (or language code if set to \"Use Language Code\") that is blank will NOT be removed regardless of the pattern.", + "Fields": { + "Pattern": "Pattern", + "Pattern-Help": "A regular expression to match against, eg \"commentary\" to remove commentary tracks", + "NotMatching": "Not Matching", + "NotMatching-Help": "If audio tracks NOT matching the pattern should be removed", + "UseLanguageCode": "Use Language Code", + "UseLanguageCode-Help": "If the language code of the audio track should be used instead of the title" + } + }, + "AudioTrackReorder": { + "Outputs": { + "1": "Audio tracks re-ordered in new temporary file", + "2": "Audio tracks NOT re-ordered" }, - "AudioTrackReorder": { - "Outputs": { - "1": "Audio tracks re-ordered in new temporary file", - "2": "Audio tracks NOT re-ordered" - }, - "Description": "Allows you to reorder audio tracks in the preferred order.\n\nEnter the languages/audio codecs/channels in the order you want. Any not listed will be ordered after the ones entered in their original order.\nIf there are multiple tracks with same language/codec/channels, they will be ordered first by the order you entered, then in their original order.\n\nOutput 1: Audio tracks were reordered\nOutput 2: Audio tracks did not need reordering", - "Fields": { - "OrderedTracks": "Ordered Audio Codecs", - "OrderedTracks-Help": "The order of audio codecs to the audio tracks by. This is done after the languages (if any)", - "Languages": "Languages", - "Languages-Help": "The order of languages to sort the audio tracks by. This sorting is done before the codec.", - "Channels": "Channels", - "Channels-Help": "The order of audio channels to sort the audio tracks by. This sorting is done before languages.\nFor example \"5.1\",\"7.1\",\"6.2\",\"2\"" - } + "Description": "Allows you to reorder audio tracks in the preferred order.\n\nEnter the languages/audio codecs/channels in the order you want. Any not listed will be ordered after the ones entered in their original order.\nIf there are multiple tracks with same language/codec/channels, they will be ordered first by the order you entered, then in their original order.\n\nOutput 1: Audio tracks were reordered\nOutput 2: Audio tracks did not need reordering", + "Fields": { + "OrderedTracks": "Ordered Audio Codecs", + "OrderedTracks-Help": "The order of audio codecs to the audio tracks by. This is done after the languages (if any)", + "Languages": "Languages", + "Languages-Help": "The order of languages to sort the audio tracks by. This sorting is done before the codec.", + "Channels": "Channels", + "Channels-Help": "The order of audio channels to sort the audio tracks by. This sorting is done before languages.\nFor example \"5.1\",\"7.1\",\"6.2\",\"2\"" + } + }, + "AudioTrackSetLanguage": { + "Label": "Audio Set Language", + "Outputs": { + "1": "Audio tracks updated to new temporary file", + "2": "Audio tracks NOT updated" }, - "AudioTrackSetLanguage": { - "Label": "Audio Set Language", - "Outputs": { - "1": "Audio tracks updated to new temporary file", - "2": "Audio tracks NOT updated" - }, - "Description": "Allows you to set the language for any audio tracks that have no language set. If the audio track does have a language set, it will be skipped.\n\nOutput 1: Audio Tracks were updated\nOutput 2: No audio tracks were needing to be updated", - "Fields": { - "Language": "Language", - "Language-Help": "The ISO 639-2 language code to use. \nhttps://en.wikipedia.org/wiki/List_of_ISO_639-2_codes" - } + "Description": "Allows you to set the language for any audio tracks that have no language set. If the audio track does have a language set, it will be skipped.\n\nOutput 1: Audio Tracks were updated\nOutput 2: No audio tracks were needing to be updated", + "Fields": { + "Language": "Language", + "Language-Help": "The ISO 639-2 language code to use. \nhttps://en.wikipedia.org/wiki/List_of_ISO_639-2_codes" + } + }, + "AutoChapters": { + "Description": "Automatically detect scene changes in the video to generate chapters.", + "Outputs": { + "1": "Chapters generated and saved to temporary file", + "2": "No chapters detected or video already had chapters" }, - "AutoChapters": { - "Description": "Automatically detect scene changes in the video to generate chapters.", - "Outputs": { - "1": "Chapters generated and saved to temporary file", - "2": "No chapters detected or video already had chapters" - }, - "Fields": { - "MinimumLength": "Minimum Length", - "MinimumLength-Suffix": "seconds", - "MinimumLength-Help": "The minimum length of a chapter in seconds", - "Percent": "Percent", - "Percent-Suffix": "%", - "Percent-Help": "The threshold percentage value to use for scene detection changes. A good value is 45%" - } + "Fields": { + "MinimumLength": "Minimum Length", + "MinimumLength-Suffix": "seconds", + "MinimumLength-Help": "The minimum length of a chapter in seconds", + "Percent": "Percent", + "Percent-Suffix": "%", + "Percent-Help": "The threshold percentage value to use for scene detection changes. A good value is 45%" + } + }, + "ComskipChapters": { + "Description": "Uses a comskip EDL file and will create chapters given that EDL comskip file.", + "Outputs": { + "1": "Commercials chapters created, saved to temporary file", + "2": "No commercials detected" + } + }, + "ComskipRemoveAds": { + "Description": "Uses a comskip EDL file and will remove commercials using that file.", + "Outputs": { + "1": "Commercials removed, saved to temporary file", + "2": "No commercials detected" + } + }, + "VideoFile": { + "Description": "An input video file that has had its VideoInformation read and can be processed", + "Outputs": { + "1": "Video file from library" }, - "ComskipChapters": { - "Description": "Uses a comskip EDL file and will create chapters given that EDL comskip file.", - "Outputs": { - "1": "Commercials chapters created, saved to temporary file", - "2": "No commercials detected" - } + "Fields": { + "ProbeSize": "Probe Size", + "ProbeSize-Suffix": "MB", + "ProbeSize-Help": "The probe size to use in FFMPEG when executing." + } + }, + "DetectBlackBars": { + "Description": "Processes a video file and scans for black bars in the video.\n\nIf found a parameter \"VideoCrop\" will be added.\n\nOutput 1: Black bars detected\nOutput 2: Not detected", + "Outputs": { + "1": "Black bars detected", + "2": "No black bars detected" }, - "ComskipRemoveAds": { - "Description": "Uses a comskip EDL file and will remove commercials using that file.", - "Outputs": { - "1": "Commercials removed, saved to temporary file", - "2": "No commercials detected" - } + "Fields": { + "CroppingThreshold": "Threshold", + "CroppingThreshold-Help": "The amount of pixels that must be greater than to crop. E.g. if there's only 5 pixels detected as black space, you may consider this too small to crop." + } + }, + "FFMPEG": { + "Description": "The node lets you run any FFMPEG command you like. Giving you full control over what it can do.\n\nFor more information refer to the FFMPEG documentation", + "Outputs": { + "1": "Video processed" }, - "VideoFile": { - "Description": "An input video file that has had its VideoInformation read and can be processed", - "Outputs": { - "1": "Video file from library" - }, - "Fields": { - "ProbeSize": "Probe Size", - "ProbeSize-Suffix": "MB", - "ProbeSize-Help": "The probe size to use in FFMPEG when executing." - } + "Fields": { + "Extension": "Extension", + "Extension-Help": "The file extension to use on the newly created file", + "CommandLine": "Command Line", + "CommandLine-Help": "The command line to run with FFMPEG.\n'{WorkingFile}': the working file of the flow\n'{Output}': The output file that will be passed as the last parameter to FFMPEG including the extension defined above." + } + }, + "FfmpegBuilderStart": { + "Label": "FFMPEG Builder: Start", + "Outputs": { + "1": "FFMPEG Builder created and ready to add FFMPEG Builder nodes to" }, - "DetectBlackBars": { - "Description": "Processes a video file and scans for black bars in the video.\n\nIf found a parameter \"VideoCrop\" will be added.\n\nOutput 1: Black bars detected\nOutput 2: Not detected", - "Outputs": { - "1": "Black bars detected", - "2": "No black bars detected" - }, - "Fields": { - "CroppingThreshold": "Threshold", - "CroppingThreshold-Help": "The amount of pixels that must be greater than to crop. E.g. if there's only 5 pixels detected as black space, you may consider this too small to crop." - } + "Description": "Creates an instance of the FFMPEG Builder which can build a FFMPEG argument to then execute with the FFMPEG Executor." + }, + "FfmpegBuilderExecutor": { + "Label": "FFMPEG Builder: Executor", + "Outputs": { + "1": "FFMPEG Builder ran successfully and created new temporary file", + "2": "No changes detected in FFMPEG Builder, file not created" }, - "FFMPEG": { - "Description": "The node lets you run any FFMPEG command you like. Giving you full control over what it can do.\n\nFor more information refer to the FFMPEG documentation", - "Outputs": { - "1": "Video processed" - }, - "Fields": { - "Extension": "Extension", - "Extension-Help": "The file extension to use on the newly created file", - "CommandLine": "Command Line", - "CommandLine-Help": "The command line to run with FFMPEG.\n'{WorkingFile}': the working file of the flow\n'{Output}': The output file that will be passed as the last parameter to FFMPEG including the extension defined above." - } + "Description": "Executes a FFMPEG Builder command created by other FFMPEG Builder nodes.", + "Fields": { + "HardwareDecoding": "Hardware Decoding", + "HardwareDecoding-Help": "If the executor should attempt to use hardware decoding. If not available the execution will proceed just without hardware decoding enabled." + } + }, + "FfmpegBuilderAddInputFile": { + "Label": "FFMPEG Builder: Add Input File", + "Outputs": { + "1": "File found and added", + "2": "No file found" }, - "FfmpegBuilderStart": { - "Label": "FFMPEG Builder: Start", - "Outputs": { - "1": "FFMPEG Builder created and ready to add FFMPEG Builder nodes to" - }, - "Description": "Creates an instance of the FFMPEG Builder which can build a FFMPEG argument to then execute with the FFMPEG Executor." + "Fields": { + "Pattern": "Pattern", + "Pattern-Help": "A regular expression used to search for input files", + "UseSourceDirectory": "Use Source Directory", + "UseSourceDirectory-Help": "If checked the original source directory will be searched, otherwise the working directory will be used." + } + }, + "FfmpegBuilderAudioAddTrack": { + "Label": "FFMPEG Builder: Audio Add Track", + "Outputs": { + "1": "Added audio track to FFMPEG Builder" }, - "FfmpegBuilderExecutor": { - "Label": "FFMPEG Builder: Executor", - "Outputs": { - "1": "FFMPEG Builder ran successfully and created new temporary file", - "2": "No changes detected in FFMPEG Builder, file not created" - }, - "Description": "Executes a FFMPEG Builder command created by other FFMPEG Builder nodes.", - "Fields": { - "HardwareDecoding": "Hardware Decoding", - "HardwareDecoding-Help": "If the executor should attempt to use hardware decoding. If not available the execution will proceed just without hardware decoding enabled." - } + "Description": "Adds a new audio track to FFMPEG Builder which will be added once the builder is executed.", + "Fields": { + "Index": "Index", + "Index-Help": "The index where to insert the new audio track. 0 based, so to insert the new audio track as the first track set this to 0.", + "Channels": "Channels", + "Channels-Help": "The number of channels this new audio track will be.\nIf you specify more channels than the source, FFMPEG will automatically upmix it.\nIf you specify fewer channels than the source, FFMPEG will automatically down mix it.", + "Bitrate": "Bitrate", + "Bitrate-Help": "Bitrate of the new audio track", + "Language": "Language", + "Language-Help": "Optional ISO 639-2 language code to use. Will attempt to find an audio track with this language code if not the best audio track will be used.\nhttps://en.wikipedia.org/wiki/List_of_ISO_639-2_codes" + } + }, + "FfmpegBuilderAudioAdjustVolume": { + "Label": "FFMPEG Builder: Audio Adjust Volume", + "Outputs": { + "1": "Audio tracks volume filter added to FFMPEG Builder", + "2": "Audio tracks were not adjusted" }, - "FfmpegBuilderAddInputFile": { - "Label": "FFMPEG Builder: Add Input File", - "Outputs": { - "1": "File found and added", - "2": "No file found" - }, - "Fields": { - "Pattern": "Pattern", - "Pattern-Help": "A regular expression used to search for input files", - "UseSourceDirectory": "Use Source Directory", - "UseSourceDirectory-Help": "If checked the original source directory will be searched, otherwise the working directory will be used." - } + "Description": "Adjusts audio tracks volume in a video file using FFMPEG", + "Fields": { + "AllAudio": "All Audio Tracks", + "AllAudio-Help": "If all audio tracks should be normalized or if just the first track should be", + "VolumePercent": "Volume Percent", + "VolumePercent-Help": "The percent of the adjusted volume.\n100 means no adjustment\n50 means half volume\n0 means muted", + "Pattern": "Pattern", + "Pattern-Help": "A regular expression to match against, eg \"commentary\" to remove commentary tracks", + "NotMatching": "Not Matching", + "NotMatching-Help": "If audio tracks NOT matching the pattern should be removed", + "UseLanguageCode": "Use Language Code", + "UseLanguageCode-Help": "If the language code of the audio track should be used instead of the title" + } + }, + "FfmpegBuilderAudioNormalization": { + "Label": "FFMPEG Builder: Audio Normalization", + "Outputs": { + "1": "Audio tracks were normalized and added to FFMPEG Builder", + "2": "No audio tracks were found to be normalized" }, - "FfmpegBuilderAudioAddTrack": { - "Label": "FFMPEG Builder: Audio Add Track", - "Outputs": { - "1": "Added audio track to FFMPEG Builder" - }, - "Description": "Adds a new audio track to FFMPEG Builder which will be added once the builder is executed.", - "Fields": { - "Index": "Index", - "Index-Help": "The index where to insert the new audio track. 0 based, so to insert the new audio track as the first track set this to 0.", - "Channels": "Channels", - "Channels-Help": "The number of channels this new audio track will be.\nIf you specify more channels than the source, FFMPEG will automatically upmix it.\nIf you specify fewer channels than the source, FFMPEG will automatically down mix it.", - "Bitrate": "Bitrate", - "Bitrate-Help": "Bitrate of the new audio track", - "Language": "Language", - "Language-Help": "Optional ISO 639-2 language code to use. Will attempt to find an audio track with this language code if not the best audio track will be used.\nhttps://en.wikipedia.org/wiki/List_of_ISO_639-2_codes" - } + "Description": "Normalizes all audio tracks in a video file using FFMPEGs loudnorm filter", + "Fields": { + "TwoPass": "Two Pass", + "TwoPass-Help": "If the audio tracks should use two pass normalization. This improves the normalization but increases the processing time.", + "AllAudio": "All Audio Tracks", + "AllAudio-Help": "If all audio tracks should be normalized or if just the first track should be", + "Pattern": "Pattern", + "Pattern-Help": "A regular expression to match against, eg \"commentary\" to remove commentary tracks", + "NotMatching": "Not Matching", + "NotMatching-Help": "If audio tracks NOT matching the pattern should be removed", + "UseLanguageCode": "Use Language Code", + "UseLanguageCode-Help": "If the language code of the audio track should be used instead of the title" + } + }, + "FfmpegBuilderAudioTrackRemover": { + "Label": "FFMPEG Builder: Audio Track Remover", + "Outputs": { + "1": "Audio tracks set to remove", + "2": "Audio tracks NOT set to removed" }, - "FfmpegBuilderAudioAdjustVolume": { - "Label": "FFMPEG Builder: Audio Adjust Volume", - "Outputs": { - "1": "Audio tracks volume filter added to FFMPEG Builder", - "2": "Audio tracks were not adjusted" - }, - "Description": "Adjusts audio tracks volume in a video file using FFMPEG", - "Fields": { - "AllAudio": "All Audio Tracks", - "AllAudio-Help": "If all audio tracks should be normalized or if just the first track should be", - "VolumePercent": "Volume Percent", - "VolumePercent-Help": "The percent of the adjusted volume.\n100 means no adjustment\n50 means half volume\n0 means muted", - "Pattern": "Pattern", - "Pattern-Help": "A regular expression to match against, eg \"commentary\" to remove commentary tracks", - "NotMatching": "Not Matching", - "NotMatching-Help": "If audio tracks NOT matching the pattern should be removed", - "UseLanguageCode": "Use Language Code", - "UseLanguageCode-Help": "If the language code of the audio track should be used instead of the title" - } + "Description": "Allows you to remove audio tracks based on either their title or their language codes.\n\nAny title (or language code if set to \"Use Language Code\") that is blank will NOT be removed regardless of the pattern.", + "Fields": { + "RemoveAll": "Remove All", + "RemoveAll-Help": "Remove all current tracks from the output file. You can use Add Audio Track afterwards to add tracks of specific codecs", + "Pattern": "Pattern", + "Pattern-Help": "A regular expression to match against, eg \"commentary\" to remove commentary tracks", + "NotMatching": "Not Matching", + "NotMatching-Help": "If audio tracks NOT matching the pattern should be removed", + "UseLanguageCode": "Use Language Code", + "UseLanguageCode-Help": "If the language code of the audio track should be used instead of the title", + "RemoveIndex": "Remove Index", + "RemoveIndex-Help": "The start index where to remove the audio tracks from. This allows you to remove all, or all matching, audio streams after the starting index.\nSet to zero to remove all matching the parameters.\nSet to 1 to keep the first audio track and remove any after the first matching the parameters" + } + }, + "FfmpegBuilderAudioTrackReorder": { + "Label": "FFMPEG Builder: Audio Track Reorder", + "Outputs": { + "1": "Audio tracks re-ordered in FFMPEG Builder", + "2": "Audio tracks NOT re-ordered" }, - "FfmpegBuilderAudioNormalization": { - "Label": "FFMPEG Builder: Audio Normalization", - "Outputs": { - "1": "Audio tracks were normalized and added to FFMPEG Builder", - "2": "No audio tracks were found to be normalized" - }, - "Description": "Normalizes all audio tracks in a video file using FFMPEGs loudnorm filter", - "Fields": { - "TwoPass": "Two Pass", - "TwoPass-Help": "If the audio tracks should use two pass normalization. This improves the normalization but increases the processing time.", - "AllAudio": "All Audio Tracks", - "AllAudio-Help": "If all audio tracks should be normalized or if just the first track should be", - "Pattern": "Pattern", - "Pattern-Help": "A regular expression to match against, eg \"commentary\" to remove commentary tracks", - "NotMatching": "Not Matching", - "NotMatching-Help": "If audio tracks NOT matching the pattern should be removed", - "UseLanguageCode": "Use Language Code", - "UseLanguageCode-Help": "If the language code of the audio track should be used instead of the title" - } + "Description": "Allows you to reorder audio tracks in the preferred order.\n\nEnter the languages/audio codecs/channels in the order you want. Any not listed will be ordered after the ones entered in their original order.\nIf there are multiple tracks with same language/codec/channels, they will be ordered first by the order you entered, then in their original order.\n\nOutput 1: Audio tracks were reordered\nOutput 2: Audio tracks did not need reordering", + "Fields": { + "OrderedTracks": "Ordered Audio Codecs", + "OrderedTracks-Help": "The order of audio codecs to the audio tracks by. This is done after the languages (if any)", + "Languages": "Languages", + "Languages-Help": "The order of languages to sort the audio tracks by. This sorting is done before the codec.", + "Channels": "Channels", + "Channels-Help": "The order of audio channels to sort the audio tracks by. This sorting is done before languages.\nFor example \"5.1\",\"7.1\",\"6.2\",\"2\"" + } + }, + "FfmpegBuilderAudioSetLanguage": { + "Label": "FFMPEG Builder: Audio Set Language", + "Outputs": { + "1": "Audio tracks updated in FFMPEG Builder", + "2": "Audio tracks NOT updated" }, - "FfmpegBuilderAudioTrackRemover": { - "Label": "FFMPEG Builder: Audio Track Remover", - "Outputs": { - "1": "Audio tracks set to remove", - "2": "Audio tracks NOT set to removed" - }, - "Description": "Allows you to remove audio tracks based on either their title or their language codes.\n\nAny title (or language code if set to \"Use Language Code\") that is blank will NOT be removed regardless of the pattern.", - "Fields": { - "RemoveAll": "Remove All", - "RemoveAll-Help": "Remove all current tracks from the output file. You can use Add Audio Track afterwards to add tracks of specific codecs", - "Pattern": "Pattern", - "Pattern-Help": "A regular expression to match against, eg \"commentary\" to remove commentary tracks", - "NotMatching": "Not Matching", - "NotMatching-Help": "If audio tracks NOT matching the pattern should be removed", - "UseLanguageCode": "Use Language Code", - "UseLanguageCode-Help": "If the language code of the audio track should be used instead of the title", - "RemoveIndex": "Remove Index", - "RemoveIndex-Help": "The start index where to remove the audio tracks from. This allows you to remove all, or all matching, audio streams after the starting index.\nSet to zero to remove all matching the parameters.\nSet to 1 to keep the first audio track and remove any after the first matching the parameters" - } + "Description": "Allows you to set the language for any audio tracks that have no language set. If the audio track does have a language set, it will be skipped.\n\nOutput 1: Audio Tracks were updated\nOutput 2: No audio tracks were needing to be updated", + "Fields": { + "Language": "Language", + "Language-Help": "Optional ISO 639-2 language code to use. Will attempt to find an audio track with this language code if not the best audio track will be used.\nhttps://en.wikipedia.org/wiki/List_of_ISO_639-2_codes" + } + }, + "FfmpegBuilderAutoChapters": { + "Label": "FFMPEG Builder: Auto Chapters", + "Description": "Automatically detect scene changes in the video to generate chapters.", + "Outputs": { + "1": "Chapters generated and added to FFMPEG Builder", + "2": "No chapters detected or video already had chapters" }, - "FfmpegBuilderAudioTrackReorder": { - "Label": "FFMPEG Builder: Audio Track Reorder", - "Outputs": { - "1": "Audio tracks re-ordered in FFMPEG Builder", - "2": "Audio tracks NOT re-ordered" - }, - "Description": "Allows you to reorder audio tracks in the preferred order.\n\nEnter the languages/audio codecs/channels in the order you want. Any not listed will be ordered after the ones entered in their original order.\nIf there are multiple tracks with same language/codec/channels, they will be ordered first by the order you entered, then in their original order.\n\nOutput 1: Audio tracks were reordered\nOutput 2: Audio tracks did not need reordering", - "Fields": { - "OrderedTracks": "Ordered Audio Codecs", - "OrderedTracks-Help": "The order of audio codecs to the audio tracks by. This is done after the languages (if any)", - "Languages": "Languages", - "Languages-Help": "The order of languages to sort the audio tracks by. This sorting is done before the codec.", - "Channels": "Channels", - "Channels-Help": "The order of audio channels to sort the audio tracks by. This sorting is done before languages.\nFor example \"5.1\",\"7.1\",\"6.2\",\"2\"" - } + "Fields": { + "MinimumLength": "Minimum Length", + "MinimumLength-Suffix": "seconds", + "MinimumLength-Help": "The minimum length of a chapter in seconds", + "Percent": "Percent", + "Percent-Suffix": "%", + "Percent-Help": "The threshold percentage value to use for scene detection changes. A good value is 45%" + } + }, + "FfmpegBuilderComskipChapters": { + "Label": "FFMPEG Builder: Comskip Chapters", + "Description": "Uses a comskip EDL file and will create chapters given that EDL comskip file.", + "Outputs": { + "1": "Commercials chapters created, added to FFMPEG Builder", + "2": "No commercials detected" + } + }, + "FfmpegBuilderHdrToSdr": { + "Label": "FFMPEG Builder: HDR to SDR", + "Description": "Checks if a video stream is HDR and if it is updates the FFMPEG Builder to convert it to SDR", + "Outputs": { + "1": "HDR stream detected and updated FFMPEG Builder to convert", + "2": "No HDR stream found" + } + }, + "FfmpegBuilderSubtitleFormatRemover": { + "Label": "FFMPEG Builder: Subtitle Format Remover", + "Description": "Removes subtitles from a video file if found.", + "Outputs": { + "1": "Subtitles marked for removal in FFMPEG Builder", + "2": "No subtitles to remove" }, - "FfmpegBuilderAudioSetLanguage": { - "Label": "FFMPEG Builder: Audio Set Language", - "Outputs": { - "1": "Audio tracks updated in FFMPEG Builder", - "2": "Audio tracks NOT updated" - }, - "Description": "Allows you to set the language for any audio tracks that have no language set. If the audio track does have a language set, it will be skipped.\n\nOutput 1: Audio Tracks were updated\nOutput 2: No audio tracks were needing to be updated", - "Fields": { - "Language": "Language", - "Language-Help": "Optional ISO 639-2 language code to use. Will attempt to find an audio track with this language code if not the best audio track will be used.\nhttps://en.wikipedia.org/wiki/List_of_ISO_639-2_codes" - } + "Fields": { + "SubtitlesToRemove": "Subtitles To Remove", + "RemoveAll": "Remove All", + "RemoveAll-Help": "When checked, all subtitles will be removed from the file, otherwise only those selected below will be" + } + }, + "FfmpegBuilderSubtitleTrackRemover": { + "Label": "FFMPEG Builder: Subtitle Track Remover", + "Outputs": { + "1": "Subtitles marked for removal in FFMPEG Builder", + "2": "No subtitles to remove" }, - "FfmpegBuilderAutoChapters": { - "Label": "FFMPEG Builder: Auto Chapters", - "Description": "Automatically detect scene changes in the video to generate chapters.", - "Outputs": { - "1": "Chapters generated and added to FFMPEG Builder", - "2": "No chapters detected or video already had chapters" - }, - "Fields": { - "MinimumLength": "Minimum Length", - "MinimumLength-Suffix": "seconds", - "MinimumLength-Help": "The minimum length of a chapter in seconds", - "Percent": "Percent", - "Percent-Suffix": "%", - "Percent-Help": "The threshold percentage value to use for scene detection changes. A good value is 45%" - } + "Description": "Allows you to remove subtitles based on either their title or their language codes.\n\nAny language (or title if set to \"Use Title\") that is blank will NOT be removed regardless of the pattern.", + "Fields": { + "Pattern": "Pattern", + "Pattern-Help": "A regular expression to match against, eg \"eng\" to remove English tracks", + "NotMatching": "Not Matching", + "NotMatching-Help": "If subtitles NOT matching the pattern should be removed", + "UseLanguageCode": "Use Language Code", + "UseLanguageCode-Help": "If the language code of the audio track should be used instead of the title" + } + }, + "FfmpegBuilderSubtitleTrackMerge": { + "Label": "FFMPEG Builder: Subtitle Track Merge", + "Outputs": { + "1": "Subtitles found and added", + "2": "No subtitles found" }, - "FfmpegBuilderComskipChapters": { - "Label": "FFMPEG Builder: Comskip Chapters", - "Description": "Uses a comskip EDL file and will create chapters given that EDL comskip file.", - "Outputs": { - "1": "Commercials chapters created, added to FFMPEG Builder", - "2": "No commercials detected" - } + "Fields": { + "Subtitles": "Subtitles", + "Subtitles-Help": "Select which subtitles to search for to add", + "UseSourceDirectory": "Use Source Directory", + "UseSourceDirectory-Help": "If checked the original source directory will be searched, otherwise the working directory will be used." + } + }, + "FfmpegBuilderCropBlackBars": { + "Label": "FFMPEG Builder: Crop Black Bars", + "Description": "Updated FFMPEG Builder to crop black bars if detected", + "Outputs": { + "1": "FFMPEG Builder updated to crop black bars", + "2": "No black bars detected, not cropping" }, - "FfmpegBuilderHdrToSdr": { - "Label": "FFMPEG Builder: HDR to SDR", - "Description": "Checks if a video stream is HDR and if it is updates the FFMPEG Builder to convert it to SDR", - "Outputs": { - "1": "HDR stream detected and updated FFMPEG Builder to convert", - "2": "No HDR stream found" - } + "Fields": { + "CroppingThreshold": "Threshold", + "CroppingThreshold-Help": "The amount of pixels that must be greater than to crop. E.g. if there's only 5 pixels detected as black space, you may consider this too small to crop." + } + }, + "FfmpegBuilderRemuxToMkv": { + "Label": "FFMPEG Builder: Remux to MKV", + "Descritption": "Remuxes a video file into a MKV container.", + "Outputs": { + "1": "FFMPEG Builder set to remux to MKV" + } + }, + "FfmpegBuilderRemuxToMP4": { + "Label": "FFMPEG Builder: Remux to MP4", + "Descritption": "Remuxes a video file into a MP4 container.", + "Outputs": { + "1": "FFMPEG Builder set to remux to MP4" + } + }, + "FfmpegBuilderScaler": { + "Label": "FFMPEG Builder: Video Scaler", + "Description": "This allows you to scale a video to the specified dimensions. It will retain the aspect ratio of the video so if the video was 1920x1000 it would scale to 1280x668 if you select 720P.", + "Outputs": { + "1": "FFMPEG Builder scale filter added", + "2": "Video was already in/near the scaled resolution" }, - "FfmpegBuilderSubtitleFormatRemover": { - "Label": "FFMPEG Builder: Subtitle Format Remover", - "Description": "Removes subtitles from a video file if found.", - "Outputs": { - "1": "Subtitles marked for removal in FFMPEG Builder", - "2": "No subtitles to remove" - }, - "Fields": { - "SubtitlesToRemove": "Subtitles To Remove", - "RemoveAll": "Remove All", - "RemoveAll-Help": "When checked, all subtitles will be removed from the file, otherwise only those selected below will be" - } + "Fields": { + "Force": "Force", + "Force-Help": "When checked the video will be force scaled even if the working file is already in this resolution (or near this resolution).", + "Resolution": "Resolution" + } + }, + "FfmpegBuilderVideo10Bit": { + "Label": "FFMPEG Builder: Video 10 Bit", + "Description": "Sets FFMPEG Builder to encode the video streams in 10 Bit", + "Outputs": { + "1": "FFMPEG Builder video streams set to encode in 10 Bit" + } + }, + "FfmpegBuilderVideoBitrate": { + "Label": "FFMPEG Builder: Video Bitrate", + "Description": "Sets FFMPEG Builder to encode the video given the bitrate", + "Outputs": { + "1": "FFMPEG Builder video streams updated" }, - "FfmpegBuilderSubtitleTrackRemover": { - "Label": "FFMPEG Builder: Subtitle Track Remover", - "Outputs": { - "1": "Subtitles marked for removal in FFMPEG Builder", - "2": "No subtitles to remove" - }, - "Description": "Allows you to remove subtitles based on either their title or their language codes.\n\nAny language (or title if set to \"Use Title\") that is blank will NOT be removed regardless of the pattern.", - "Fields": { - "Pattern": "Pattern", - "Pattern-Help": "A regular expression to match against, eg \"eng\" to remove English tracks", - "NotMatching": "Not Matching", - "NotMatching-Help": "If subtitles NOT matching the pattern should be removed", - "UseLanguageCode": "Use Language Code", - "UseLanguageCode-Help": "If the language code of the audio track should be used instead of the title" - } + "Fields": { + "Bitrate": "Bitrate", + "Bitrate-Suffix": "KB / %", + "Bitrate-Help": "The target bitrate of the video in kilobytes", + "Percent": "Percent", + "Percent-Help": "When selected the bitrate will be calculated as a percentage of the current bitrate." + } + }, + "FfmpegBuilderVideoCodec": { + "Label": "FFMPEG Builder: Video Codec", + "Description": "Sets FFMPEG Builder to encode the video streams in the specified codec", + "Outputs": { + "1": "FFMPEG Builder video streams set to encode", + "2": "Video already in target codec, will not re-encode" }, - "FfmpegBuilderSubtitleTrackMerge": { - "Label": "FFMPEG Builder: Subtitle Track Merge", - "Outputs": { - "1": "Subtitles found and added", - "2": "No subtitles found" - }, - "Fields": { - "Subtitles": "Subtitles", - "Subtitles-Help": "Select which subtitles to search for to add", - "UseSourceDirectory": "Use Source Directory", - "UseSourceDirectory-Help": "If checked the original source directory will be searched, otherwise the working directory will be used." - } + "Fields": { + "VideoCodec": "Video Codec", + "VideoCodec-Help": "The video codec the video should be in, for example hevc, h264.\nIf left empty all original video tracks will be copied.", + "VideoCodecParameters": "Video Codec Parameters", + "VideoCodecParameters-Help": "The parameters to use to encode the video, eg. \"hevc_nvenc -preset hq -crf 23\" to encode into hevc using the HQ preset a constant rate factor of 23 and using NVIDIA hardware acceleration.", + "Force": "Force Encode", + "Force-Help": "Will force a encode of the video even if it is already in the target Video Codec", + "DisableOtherVideoStreams": "Only First", + "DisableOtherVideoStreams-Help": "When checked if there are multiple video streams in the file, this will remove all but the first video stream from the file once executed." + } + }, + "FfmpegBuilderVideoEncode": { + "Label": "FFMPEG Builder: Video Encode", + "Description": "Sets the FFMPEG Builder to encode the video with simple to use presets", + "Outputs": { + "1": "FFMPEG Builder video streams set to encode" }, - "FfmpegBuilderCropBlackBars": { - "Label": "FFMPEG Builder: Crop Black Bars", - "Description": "Updated FFMPEG Builder to crop black bars if detected", - "Outputs": { - "1": "FFMPEG Builder updated to crop black bars", - "2": "No black bars detected, not cropping" - }, - "Fields": { - "CroppingThreshold": "Threshold", - "CroppingThreshold-Help": "The amount of pixels that must be greater than to crop. E.g. if there's only 5 pixels detected as black space, you may consider this too small to crop." - } + "Fields": { + "Codec": "Codec", + "HardwareEncoding": "Hardware Encode", + "HardwareEncoding-Help": "When checked, will test to see if hardware encoders are found on the Processing Node, and if found will use hardware encoding, otherwise will fallback to CPU encoding.", + "Quality": "Quality", + "Quality-Help": "A logarithmic quality scale, so small changes in the this slider cause large changes in file size/quality.\nThe lower the number the higher the quality.\nSee Help for more information", + "Quality-Suffix": "(Higher Quality, larger file)" + } + }, + "RemuxToMKV": { + "Descritption": "Remuxes a video file into a MKV container. All streams will be copied to the new container", + "Outputs": { + "1": "File remuxed to temporary file", + "2": "File was already in a MKV container" }, - "FfmpegBuilderRemuxToMkv": { - "Label": "FFMPEG Builder: Remux to MKV", - "Descritption": "Remuxes a video file into a MKV container.", - "Outputs": { - "1": "FFMPEG Builder set to remux to MKV" - } + "Fields": { + "Force": "Force", + "Force-Help": "If the file should be always remuxed into a MKV container even when it already is in a MKV container.\ni.e. a new temporary file will always be created." + } + }, + "ReadVideoInfo": { + "Descritption": "Reads the video information from the current working file and updates the vi variables.", + "Outputs": { + "1": "File was a video file and information read into flow", + "2": "File was not a video file or failed to be read" + } + }, + "RemuxToMP4": { + "Descritption": "Remuxes a video file into a MP4 container. All streams will be copied to the new container", + "Outputs": { + "1": "File remuxed to temporary file", + "2": "File was already in a MP4 container" }, - "FfmpegBuilderRemuxToMP4": { - "Label": "FFMPEG Builder: Remux to MP4", - "Descritption": "Remuxes a video file into a MP4 container.", - "Outputs": { - "1": "FFMPEG Builder set to remux to MP4" - } + "Fields": { + "Force": "Force", + "Force-Help": "If the file should be always remuxed into a MP4 container even when it already is in a MP4 container.\ni.e. a new temporary file will always be created." + } + }, + "SubtitleRemover": { + "Description": "Removes subtitles from a video file if found.\n\nOutput 1: Subtitles were removed\nOutput 2: No subtitles found that needed to be removed", + "Outputs": { + "1": "Subtitles removed in new temporary file", + "2": "No subtitles to remove" }, - "FfmpegBuilderScaler": { - "Label": "FFMPEG Builder: Video Scaler", - "Description": "This allows you to scale a video to the specified dimensions. It will retain the aspect ratio of the video so if the video was 1920x1000 it would scale to 1280x668 if you select 720P.", - "Outputs": { - "1": "FFMPEG Builder scale filter added", - "2": "Video was already in/near the scaled resolution" - }, - "Fields": { - "Force": "Force", - "Force-Help": "When checked the video will be force scaled even if the working file is already in this resolution (or near this resolution).", - "Resolution": "Resolution" - } + "Fields": { + "SubtitlesToRemove": "Subtitles To Remove", + "RemoveAll": "Remove All", + "RemoveAll-Help": "When checked, all subtitles will be removed from the file, otherwise only those selected below will be" + } + }, + "SubtitleExtractor": { + "Description": "Extract a single subtitle tracks and saves it to the destination. Can extract srt, ass, and ssa format.\nThis will NOT update the working file, and will keep the working file the same as the input file.\n\nOutput 1: Subtitles were extracted\nOutput 2: No subtitles found to extract", + "Outputs": { + "1": "Subtitles extracted", + "2": "No subtitles extracted" }, - "FfmpegBuilderVideo10Bit": { - "Label": "FFMPEG Builder: Video 10 Bit", - "Description": "Sets FFMPEG Builder to encode the video streams in 10 Bit", - "Outputs": { - "1": "FFMPEG Builder video streams set to encode in 10 Bit" - } + "Fields": { + "Language": "Language", + "Language-Help": "The ISO 639-2 language code to use. \nhttps://en.wikipedia.org/wiki/List_of_ISO_639-2_codes", + "OutputFile": "Output File", + "OutputFile-Help": "Where to save the the output file to, e.g. \"'{folder.Orig.FullName}\\{file.Orig.FileName}.srt'\" to save it with the original file as a srt output.\nIf left blank an srt subtitle will be created in the same folder as the original input file.", + "SetWorkingFile": "Set as Working File", + "SetWorkingFile-Help": "When this is checked, if a subtitle is extracted, the working file will be changed to this extracted subtitle. The original working file will NOT be deleted." + } + }, + "SubtitleLanguageRemover": { + "Outputs": { + "1": "Subtitles were removed", + "2": "Subtitles were NOT removed" }, - "FfmpegBuilderVideoBitrate": { - "Label": "FFMPEG Builder: Video Bitrate", - "Description": "Sets FFMPEG Builder to encode the video given the bitrate", - "Outputs": { - "1": "FFMPEG Builder video streams updated" - }, - "Fields": { - "Bitrate": "Bitrate", - "Bitrate-Suffix": "KB / %", - "Bitrate-Help": "The target bitrate of the video in kilobytes", - "Percent": "Percent", - "Percent-Help": "When selected the bitrate will be calculated as a percentage of the current bitrate." - } + "Description": "Allows you to remove subtitles based on either their title or their language codes.\n\nAny language (or title if set to \"Use Title\") that is blank will NOT be removed regardless of the pattern.", + "Fields": { + "Pattern": "Pattern", + "Pattern-Help": "A regular expression to match against, eg \"eng\" to remove English tracks", + "NotMatching": "Not Matching", + "NotMatching-Help": "If subtitles NOT matching the pattern should be removed", + "UseTitle": "Use Title", + "UseTitle-Help": "If the title of the subtitle should be used for matching instead of the language" + } + }, + "VideoCodec": { + "Description": "This node will check the codecs in the input file, and trigger when matched.\n\nOutput 1: Matches\nOutput 2: Does not match", + "Fields": { + "Codecs": "Codecs", + "Codecs-Help": "Enter a list of case insensitive video or audio codecs.\nEg hevc, h265, mpeg4, ac3" + } + }, + "VideoEncode": { + "Description": "A generic video encoding node, this lets you customize how to encode a video file using ffmpeg.\n\nOutput 1: Video was processed\nOutput 2: No processing required", + "Outputs": { + "1": "Video re-encoded to temporary file", + "2": "Video not re-encoded" }, - "FfmpegBuilderVideoCodec": { - "Label": "FFMPEG Builder: Video Codec", - "Description": "Sets FFMPEG Builder to encode the video streams in the specified codec", - "Outputs": { - "1": "FFMPEG Builder video streams set to encode", - "2": "Video already in target codec, will not re-encode" - }, - "Fields": { - "VideoCodec": "Video Codec", - "VideoCodec-Help": "The video codec the video should be in, for example hevc, h264.\nIf left empty all original video tracks will be copied.", - "VideoCodecParameters": "Video Codec Parameters", - "VideoCodecParameters-Help": "The parameters to use to encode the video, eg. \"hevc_nvenc -preset hq -crf 23\" to encode into hevc using the HQ preset a constant rate factor of 23 and using NVIDIA hardware acceleration.", - "Force": "Force Encode", - "Force-Help": "Will force a encode of the video even if it is already in the target Video Codec", - "DisableOtherVideoStreams": "Only First", - "DisableOtherVideoStreams-Help": "When checked if there are multiple video streams in the file, this will remove all but the first video stream from the file once executed." - } + "Fields": { + "Extension": "Extension", + "Extension-Help": "The file extension to use on the newly created file.", + "VideoCodec": "Video Codec", + "VideoCodec-Help": "The video codec the video should be in, for example hevc, h264.\nIf left empty all original video tracks will be copied.", + "VideoCodecParameters": "Video Codec Parameters", + "VideoCodecParameters-Help": "The parameters to use to encode the video, eg. \"hevc_nvenc -preset hq -crf 23\" to encode into hevc using the HQ preset a constant rate factor of 23 and using NVIDIA hardware acceleration.", + "AudioCodec": "Audio Codec", + "AudioCodec-Help": "The audio codec to encode the video with.\nIf left empty all original audio tracks will be copied.", + "Language": "Language", + "Language-Help": "Optional ISO 639-2 language code to use. Will attempt to find an audio track with this language code if not the best audio track will be used.\nhttps://en.wikipedia.org/wiki/List_of_ISO_639-2_codes" + } + }, + "VideoHasStream": { + "Description": "Tests if a video file contains a stream", + "Outputs": { + "1": "Contains the matching stream", + "2": "Does not contain the matching stream" }, - "FfmpegBuilderVideoEncode": { - "Label": "FFMPEG Builder: Video Encode", - "Description": "Sets the FFMPEG Builder to encode the video with simple to use presets", - "Outputs": { - "1": "FFMPEG Builder video streams set to encode" - }, - "Fields": { - "Codec": "Codec", - "HardwareEncoding": "Hardware Encode", - "HardwareEncoding-Help": "When checked, will test to see if hardware encoders are found on the Processing Node, and if found will use hardware encoding, otherwise will fallback to CPU encoding.", - "Quality": "Quality", - "Quality-Help": "Sets the quality of the video" - } + "Fields": { + "Stream": "Type", + "Stream-Help": "The type of stream to look for", + "Title": "Title", + "Title-Help": "A regular expression used to test the stream title", + "Codec": "Codec", + "Codec-Help": "A regular expression used to test the stream codec", + "Language": "Language", + "Language-Help": "A regular expression used to test the stream language", + "Channels": "Channels", + "Channels-Help": "The number of channels to test for. Set to 0 to ignore this check" + } + }, + "VideoScaler": { + "Description": "This allows you to scale a video to the specified dimensions. It will retain the aspect ratio of the video so if the video was 1920x1000 it would scale to 1280x668 if you select 720P.", + "Outputs": { + "1": "Video rescaled to temporary file", + "2": "Video was already in/near the scaled resolution" }, - "RemuxToMKV": { - "Descritption": "Remuxes a video file into a MKV container. All streams will be copied to the new container", - "Outputs": { - "1": "File remuxed to temporary file", - "2": "File was already in a MKV container" - }, - "Fields": { - "Force": "Force", - "Force-Help": "If the file should be always remuxed into a MKV container even when it already is in a MKV container.\ni.e. a new temporary file will always be created." - } - }, - "ReadVideoInfo": { - "Descritption": "Reads the video information from the current working file and updates the vi variables.", - "Outputs": { - "1": "File was a video file and information read into flow", - "2": "File was not a video file or failed to be read" - } - }, - "RemuxToMP4": { - "Descritption": "Remuxes a video file into a MP4 container. All streams will be copied to the new container", - "Outputs": { - "1": "File remuxed to temporary file", - "2": "File was already in a MP4 container" - }, - "Fields": { - "Force": "Force", - "Force-Help": "If the file should be always remuxed into a MP4 container even when it already is in a MP4 container.\ni.e. a new temporary file will always be created." - } - }, - "SubtitleRemover": { - "Description": "Removes subtitles from a video file if found.\n\nOutput 1: Subtitles were removed\nOutput 2: No subtitles found that needed to be removed", - "Outputs": { - "1": "Subtitles removed in new temporary file", - "2": "No subtitles to remove" - }, - "Fields": { - "SubtitlesToRemove": "Subtitles To Remove", - "RemoveAll": "Remove All", - "RemoveAll-Help": "When checked, all subtitles will be removed from the file, otherwise only those selected below will be" - } - }, - "SubtitleExtractor": { - "Description": "Extract a single subtitle tracks and saves it to the destination. Can extract srt, ass, and ssa format.\nThis will NOT update the working file, and will keep the working file the same as the input file.\n\nOutput 1: Subtitles were extracted\nOutput 2: No subtitles found to extract", - "Outputs": { - "1": "Subtitles extracted", - "2": "No subtitles extracted" - }, - "Fields": { - "Language": "Language", - "Language-Help": "The ISO 639-2 language code to use. \nhttps://en.wikipedia.org/wiki/List_of_ISO_639-2_codes", - "OutputFile": "Output File", - "OutputFile-Help": "Where to save the the output file to, e.g. \"'{folder.Orig.FullName}\\{file.Orig.FileName}.srt'\" to save it with the original file as a srt output.\nIf left blank an srt subtitle will be created in the same folder as the original input file.", - "SetWorkingFile": "Set as Working File", - "SetWorkingFile-Help": "When this is checked, if a subtitle is extracted, the working file will be changed to this extracted subtitle. The original working file will NOT be deleted." - } - }, - "SubtitleLanguageRemover": { - "Outputs": { - "1": "Subtitles were removed", - "2": "Subtitles were NOT removed" - }, - "Description": "Allows you to remove subtitles based on either their title or their language codes.\n\nAny language (or title if set to \"Use Title\") that is blank will NOT be removed regardless of the pattern.", - "Fields": { - "Pattern": "Pattern", - "Pattern-Help": "A regular expression to match against, eg \"eng\" to remove English tracks", - "NotMatching": "Not Matching", - "NotMatching-Help": "If subtitles NOT matching the pattern should be removed", - "UseTitle": "Use Title", - "UseTitle-Help": "If the title of the subtitle should be used for matching instead of the language" - } - }, - "VideoCodec": { - "Description": "This node will check the codecs in the input file, and trigger when matched.\n\nOutput 1: Matches\nOutput 2: Does not match", - "Fields": { - "Codecs": "Codecs", - "Codecs-Help": "Enter a list of case insensitive video or audio codecs.\nEg hevc, h265, mpeg4, ac3" - } - }, - "VideoEncode": { - "Description": "A generic video encoding node, this lets you customize how to encode a video file using ffmpeg.\n\nOutput 1: Video was processed\nOutput 2: No processing required", - "Outputs": { - "1": "Video re-encoded to temporary file", - "2": "Video not re-encoded" - }, - "Fields": { - "Extension": "Extension", - "Extension-Help": "The file extension to use on the newly created file.", - "VideoCodec": "Video Codec", - "VideoCodec-Help": "The video codec the video should be in, for example hevc, h264.\nIf left empty all original video tracks will be copied.", - "VideoCodecParameters": "Video Codec Parameters", - "VideoCodecParameters-Help": "The parameters to use to encode the video, eg. \"hevc_nvenc -preset hq -crf 23\" to encode into hevc using the HQ preset a constant rate factor of 23 and using NVIDIA hardware acceleration.", - "AudioCodec": "Audio Codec", - "AudioCodec-Help": "The audio codec to encode the video with.\nIf left empty all original audio tracks will be copied.", - "Language": "Language", - "Language-Help": "Optional ISO 639-2 language code to use. Will attempt to find an audio track with this language code if not the best audio track will be used.\nhttps://en.wikipedia.org/wiki/List_of_ISO_639-2_codes" - } - }, - "VideoHasStream": { - "Description": "Tests if a video file contains a stream", - "Outputs": { - "1": "Contains the matching stream", - "2": "Does not contain the matching stream" - }, - "Fields": { - "Stream": "Type", - "Stream-Help": "The type of stream to look for", - "Title": "Title", - "Title-Help": "A regular expression used to test the stream title", - "Codec": "Codec", - "Codec-Help": "A regular expression used to test the stream codec", - "Language": "Language", - "Language-Help": "A regular expression used to test the stream language", - "Channels": "Channels", - "Channels-Help": "The number of channels to test for. Set to 0 to ignore this check" - } - }, - "VideoScaler": { - "Description": "This allows you to scale a video to the specified dimensions. It will retain the aspect ratio of the video so if the video was 1920x1000 it would scale to 1280x668 if you select 720P.", - "Outputs": { - "1": "Video rescaled to temporary file", - "2": "Video was already in/near the scaled resolution" - }, - "Fields": { - "VideoCodec": "Video Codec", - "Language-Help": "The video codec to encode the scaled video in", - "Extension": "Extension", - "Extension-Help": "The file extension to use on the newly created file", - "Force": "Force", - "Force-Help": "When checked the video will be force scaled even if the working file is already in this resolution (or near this resolution).", - "Resolution": "Resolution", - "VideoCodecParameters": "Video Codec Parameters", - "VideoCodecParameters-Help": "The parameters to use to encode the video, eg. \"hevc_nvenc -preset hq -crf 23\" to encode into hevc using the HQ preset a constant rate factor of 23 and using NVIDIA hardware acceleration." - } + "Fields": { + "VideoCodec": "Video Codec", + "Language-Help": "The video codec to encode the scaled video in", + "Extension": "Extension", + "Extension-Help": "The file extension to use on the newly created file", + "Force": "Force", + "Force-Help": "When checked the video will be force scaled even if the working file is already in this resolution (or near this resolution).", + "Resolution": "Resolution", + "VideoCodecParameters": "Video Codec Parameters", + "VideoCodecParameters-Help": "The parameters to use to encode the video, eg. \"hevc_nvenc -preset hq -crf 23\" to encode into hevc using the HQ preset a constant rate factor of 23 and using NVIDIA hardware acceleration." } } } + } } \ No newline at end of file diff --git a/build/utils/PluginInfoGenerator/FileFlows.Plugin.dll b/build/utils/PluginInfoGenerator/FileFlows.Plugin.dll index e9f45cc213ccb6895966ccd73bfb3a17a7c9271f..5d71cabf1994741e1308df4f93887290f2fddaa4 100644 GIT binary patch delta 16677 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 P-qxo%(D;Q~Rq6geI%4l5 delta 15223 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

$?6)?1Abl_10R7%(%hH`-TP=o| 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 b-nP6a7ieuMtv~6i?A*4%lmDwN>EZf+H@Nf2 diff --git a/build/utils/PluginInfoGenerator/FileFlows.Plugin.pdb b/build/utils/PluginInfoGenerator/FileFlows.Plugin.pdb index 628ccef2b1dd4fd449a25ffdfaf138c1e17803ab..61fead5c8bff3568b5f7de1e690632af674044f4 100644 GIT binary patch delta 7389 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 J8z#!f>3?|(Vu=6% diff --git a/build/utils/PluginInfoGenerator/FileFlows.ServerShared.dll b/build/utils/PluginInfoGenerator/FileFlows.ServerShared.dll index 7c182e3c421fc1e7cd3e3e9eca1c4fd21f4dfab7..b378903af83fba64e6681aa1e251c650e6cab162 100644 GIT binary patch delta 17912 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

  • ^h5k`a)5xPjJ8G71KqE!+$qG7@sv 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 diff --git a/build/utils/PluginInfoGenerator/FileFlows.Shared.pdb b/build/utils/PluginInfoGenerator/FileFlows.Shared.pdb index cd822efc0873011b6ab2db7d9d4d9169649a61ca..c40049a336ebf53b7524537efec90053168bd6d3 100644 GIT binary patch delta 12624 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 delta 12002 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 B=*9p5 diff --git a/build/utils/PluginInfoGenerator/FileFlows.Shared.xml b/build/utils/PluginInfoGenerator/FileFlows.Shared.xml index 95040533..8a19a934 100644 --- a/build/utils/PluginInfoGenerator/FileFlows.Shared.xml +++ b/build/utils/PluginInfoGenerator/FileFlows.Shared.xml @@ -75,6 +75,26 @@ A special flow that is executed when a flow fails during execution + + + The available processing libraries options + + + + + Only process the libraries specified + + + + + Process all libraries + + + + + Process all libraries except those specified + + Extension methods used by FileFlows @@ -503,6 +523,11 @@ Gets or sets the parameters of the field + + + Gets a list of change values for this field + + Gets or sets the validators for the field @@ -651,6 +676,62 @@ the value to test the condition against true if the condition is matches + + + Changes a value when the conditions are met + + + + + Get or sets the Field this condition is attached to + + + + + Gets or sets the property to change + + + + + Gets or sets the value to set in the property + + + + + Gets or sets when to change the value, when this value equals a value + + + + + Gets or sets if the value should be set when this value does not equal the WhenValue + + + + + Gets or sets the owner who owns this condition + + + + + Constructs a condition + + + + + Constructs a change value + + the property to change + the value to set in the property + when to change the value, when this value equals a value + the value should be set when this value does not equal the WhenValue + + + + Test if the change value condition matches the given object value + + the value of the field + true if the condition is matches + An item in the file browser @@ -1324,6 +1405,12 @@ When the library was last scanned + + + Gets or sets if recreated files (files with a different creation time) should be automatically reprocessed + This is helpful if you download the same file multiple times and want to reprocess it again + + The timespan of when this was last scanned @@ -1466,6 +1553,16 @@ Gets the total processing time of the library file + + + Gets or sets when the file was created + + + + + Gets or sets when the file was written to + + Possible status of library files @@ -1863,11 +1960,6 @@ Gets or sets if telemetry should be disabled - - - Gets or sets if the library file logs should be saved in a compressed format to reduce file size - - Gets or sets a list of available URLs to additional plugin repositories diff --git a/build/utils/PluginInfoGenerator/PluginInfoGenerator.dll b/build/utils/PluginInfoGenerator/PluginInfoGenerator.dll index 366a8df41ee027454738e12a07bf512c623f8c85..2b1d69bdc736aecec4536d66e02826507628e103 100644 GIT binary patch delta 105 zcmZpuX{edd!D8}i-oA}JTXY0cJviPb{@m<5HF#D{$-<`a%>lYQSXo}|Y z>&IC_7E|81?dOcWwOWGn^5h)jR0XJ@T0K+{s5 z`LlPzQ=F^38`e0V_wDDlot$HwssI(#c7O^3RkOPNQ_)!{UD~S{3DfAgfbF4>3mA9+5c>eY008q(8zS(< zqeQySH}DP|zrK^cFc*`*3pE&eCqJ(MAOQfGi){)PZAC|gaXQF$eJI|u3=HHb{=O(X delta 93 zcmV-j0HXi!Y4B-~d=#hV?h}+ldP{(;L(ff*3q4MGT7{vI3mE=M8O8v>006q=%qtI0 zfJcUYf5_z4y}*;cFc*`*3pE%P&HKIpAOQf>-Fw&3g$_rdRfP9T89k-53=HHb3=Jx^