Kuz=$q+9^m2Lyy^>x{uc5o> zZn}rwL~o`apm)*_(vQ*4&o7uu_XLd3VF%L6)nWve3%mLc>S*%&sNO<~8esca2f%hs{=Yy;cK>e=hrCUyeb%o^A>*37oEQ`zb440aAX zkG+{)$S!7=v8&lN>{|97c0Jq0Zen+`53;-1-Rv{$0rnvK9{WD~0sA5Q5&JRw344nD zls(OU#(u?q$NtP-;3y7p40jzjlndm7xG`KX7s7>dVO%&D!Kt`NPR%88X 19o#Bz9d|FchkKOU%RR TB{Js2ozMJ34KgjRmck>VNkMd9QPw`Ll&+{+vFY+(* zZ}G?ZclZzakNA)IFZr+dulY0lIsRAvPyV7n3ydHL4#IFjAvg=81aHAt2oypDm7oz~ zg+w7$NE0%IY@t9X6m&wlP$5haT7*`iO)v}X!c?I{un1P6Q _X_KU4Z=pDOV}aYFFYXZ67~zv3eO1#goDEK!Xe=$;Z@<7@V4-d z@VW4{a7H*Md?)-=5zyAz(sGO%N)4liQwnM% wA8}yUW~2`Xl`k;Sh^`E zYJ`YIx|?#QT!6OG3NcWx2#C*)%gTt#&Wgy)%u+{aw9!!!iBX!&h`8vO>@0OcR!m~L zTCZ@<%gm}WcTBOgH#HkG&CQ*y#x|?HWlzeV3cru?qDE2Pln*tUQc}K@pU8@w$cuvL zAUcXe#Ov;(0;oVL2tI?M2>cd@io?X=@Tq_z((iD+!bNJw)MhYG&$DF1;B?I$Mq^uJ z-_`7nrdFd~5djx+n=FN T8uXSli6f#(kp`c zDkyK7pl#}?YO++CEG8&aWwK7znc60`7~zgyF-|IIA17SNFt=Gd%q=a(4t-)`Y %v(R#&bs35)B3as)f)hIkJ^~G#%nb6dc zXYY$%;eP3!t)G3j1iivLL8FXSM#sj-E2E=g6O>W#KRP}p0lp=~Djn>Lkw|4w;oGPr zYAlsZrBLIjR4R>1r?jGzI6@pLI*Tr%tLP@Wiyqrx5wfUkDu>FY@~C`Rm;zV^Pcd0c z5z|Gjm >z{_cgu42y^TNr7EnZ7L(Ovv{ac4*2!|Q zyf#Za$O`6;OU3%0v=ytbG#RI78Ygs4ngr9V7+Gj+HFwO+>1b-7eCeva4}C2(Kyz6J zQ*XWY(N|LqRQM*UhN`9NsCv;$93^^-KAWgUN>5!+HHo9e2vH@*NTX6#H=7Mc6;w0c zWL5QbN!7P*FeII^1-foD^xXwnC#S>Q*)HDz$;hHt`1e&*WVV``jTT#dwm c7;cexIup(1Z!J@)?0pk`988#ju9N2xi~T bx8%l}QMY>{}2q@F+fd1&rKm$NM)px&a2QhF-ejFz1Bhgtk!xzRb~%=pm<<*MIy!XNaK&Ja7-zIMwMjCw ztsCm}=fB*W{q)<@6% b-c>&E4bLD}U@ysM>4v z=26Zr-aZ5BtGxtYjb+AWbB6(tuF_;Mnicd>UqAnAZ{w8~Xd_UuDQJvK@PH-;d?}Z9 z=h4ux@N2Jle+5*m8nP)8IzOPUqtP+yYp>=-6I2sBWJ{bh2k`?c0!+@x(7`gAnp$jQ z&oo)uTbgEGnwz7ENn@|QsiS4kREnZ&+<;b&rlo7Iy^bC4KpmNi?kwklmE`2+U3(>u z9JEo__@_*(x(kZC3yb`z-hcl41LVKDOG^FIX05h;@lRXkZu_H42aT6kZLWZ|tQ^oj zFqsmV8STvS4xr(Q#txVx(D?vkRThb66#^)BPQd6@z*)uvs5VoRsSZ%hW`bHKf-=@k z?Vuh2_3KgU0QClSf_k4i2MU&ehN6*3393{QN=E6Z95tgBP@Sfsn?Omr6RkxLpr_FD z=rDR6RG^R1kC?{SVJA>@0zs`Qz *(R0F;!s@E7=JP(~a; z6&X&u)4p^79YM#@33LjbL6^|&@-$#1|E8*YfA{{PJ7n0qomvhuLe`A-7FlvA?zFa; z+Kdukl2uv>hk7Bjhgw0cq{M43uUAaams@i(Dx>2vE6Xpn0Zbw$?$XzOO_tAWH(KI* zo6}e7^y=tK;14i67DbE0SXqspOrYR3&6?G@D&mvu6r&a3kCCKifR!N|J4Lr|| z*{i90sPJxT4YgK`6r;L ;R_Z_gCfeEEbU1 z{xja$L)|Cw&P~*2Y74bhREruhR*aK)=XM}FiFd|}3I7*(=U=cd`}92mI{;YT9x<_t z+AAjgEz5fnSl-ir$MVJ&JK+Zgvb?D1g#Vu9Z3l+u;xS4Y5F8GGFbJ#DE5fo(9mWYw z7Gt`$9OP;sx`->T=u0|G)0&!RDwzL-C&n(@Rt;Pfc%pOH$eK*!G!UGCo`6ldy18E~ z2F5OXNC8!ND!RPtv$eX+@fqe0sg|SOKBKR_j(w3(hp&H^U$uQ~3Vbv$Xw0?N5Fg-s z7t|0E))flknZ1s_83R@up^CiL%3_yo50!<6hpBtIV`972nn7SaF8)eb-#7r9D?$Ff z9;D0`YAv-6jAM@gBEJGguw!5Z`;hvW`i%MoaM=mDB6k!BX08-efGSWesz*jN3D9{S zS_Y=8bzr)B2t5J@t5?80^(p!W%u+v~-!Tj3C@1WB8M-D8L|5$PpVppcyJp`P&q6Q4 zyQt^Hab46wF;#*S-%g9Mqol(K+@`~5$N)KQ5=j49Gpt6N6qT20IcigH4^b~|6w_p& zdzpHru@C0bJ35+X_E0ZVuTmnYzqYS^vtw`g4eF@W@DVYiiwXiQ2O9R0R2oZhTg%K| zRZxO^S*W$xAA6g6M}ol<)JZW*% +w1D1@$HM74 &IE{Hm@LaY?4#A>mIAU#2o#VUfV1TB|FskEyw zmvki^NX^zfNun(Q*;cOz)fy+lzR57Rwl{T{Eao t&pC6d+HA`N|@+z!*@a#=rY{7hm5?H#68P#WyFZPsSPz{g>C*%d zb!cc^zx&;27$x? 21=ccYz9Jr%P(B(D5LSqaP%$b&rKn7=@G$fms$`l4kw|K?$Yw$E z1%=rt8HXfkOJ%Wk0B^gT+J;*s55^@i3NWM1W&-K0>GJYU1MW)g)Y*GbQC0v?+rM2x zw>}Y0oFXn1Zxttro5UV*fq2VtkdiA{Y-J)amdWA`Vw*Tsw2ITj8R9H)&M`CvwZJIHqc&u& zz0`VztzR%JEn+L6Ms00wMkf$ztE8V8?dk}Y_nrk=^@>rj?=K1K&<{yMmO;+c(TzGK z@%Jyw*n2V^%|K?+EVfGx|DEb+e`pShgNHhR%v-O}wC!c)+bZsqD(
dLSQlAPQ5{)X z7TMpVG4M;TNh9)-x*a*t6cPD1+Ii%lYcH?-2DA}09?+}o9kXwVZqy|$_+Yod#Dsd# zCbYS>9oU~tDB^sP=oNAQ-FW4$+=sT+K}YPHts89z2GH+ co^1%ulSV%x)Lt>g-jM0emqst#idAjLGJNQpO#H_Bak6z#1j(g84a zqepFX)!sRw#ndco`Vkg$XGgPSY46+jlC~$a2m55JN{o}5ES(met!xG`4Lc8b61_l$ zZwICRX|xYLgZ86m(R1hkI*6VZ7m16-CE`-?HgTDFySQ9jA+FqxUX&y&DgeC z`*je~?yyN(L&dwr_2LHjd!sD2d0uKw?u|;e yTtB(wN^}o8MwSYnDEx7w$7%Oa rH`ec}%Be(?cur}&__tB;dn z1r7slu}$1A@h_h~@U)peB^h5bfA<;mSUV5t$Mx)&`tdaTrG6~TeyJbdvR~@QuX-=x zOdE^ZeFcl^WlA_tVoKt}GW*%_|0nwybO!rDF3z*T>%(^9EW_Z7+KzR&99Q5 )I` _`ie%>>?{;tta!Q(IF@I=ITL zNloUYkSn2VJwVw;+yzk9gEs+`9R( )>?iTP%b{#5zON6;-Vxsz2xU7ZD0>j^ z!n?te|1f?8?-7rP$HX_qx5VS(+v15!P`2JCRUeh4YQXM3D3f)7Y%|y=p!4NTmMOB( zV#l9<8Ox5?u Y4A;wkY{@wE7v`1yAHbuXNq#pm#M0B1h{oPE&?XJ^Fk z#P8wnAN~ht|2&-02;hvy;+MT}Mza8CG)ME&kNB1Nwe4q);t54Y@7mJCXa&F-JzV^z zi*^#fy*4 9-OHqsO6N%UmeMBhM9p Sw~;%bl6nBKQ+h?bY@M=ws(USsy3Y1?bH^37ssUx} zG;*8<|6ULMHhqFVNl+L;;RHqW(C^ak(eD$aA}E2NM9FgzKHzcLDq#0p*v(;f+ap+I z1}hFe&S@rdr=`59W0KJ-SCJt_=IRw=2B}>yU(=Z;wSi$mE-ur?DTy{dB`8vy^CtZ{ zSaiXzOMgLsNq >XX)?3^+TVdzavOZ zkfxjdf&P)8SOPAf@Je|MmGbz(Hao}w2bi~QrWpD+`gdTh119M53Gbo*p#PMtGJjoc zaC7kB9qAnrgBUD(=mzxc2sNAmR+Vh)AtNvjl|{ND@QHOZ0wvlOi5UXEJO-H8IPh6B z!=b!_ae}~+=1%Z(xAm@mKeG}+sRT7#p>;_T4dcSN4wPu}2uiz(NW+X`yf29~xdi-X zy)GQNTmB%^Fab;;6U2;R0Hm}8We}7}P!>Vim$0UvTr-H&@*fE-%vc$>a<0HFJ6!b_ zSnTtj$rOW-z+^GmOb(OF Wd!DitI7!WrJl-I zKt5nP2&(F0AZ(%f+T;Uf1~VJ@J2Mk~Pf(4xwwvC7ev+hvbyvs-{?D9~g#&w&^BIUp z2D34 HRXmPs>T`%7qAO$eXnH85d zE6m#U12^m4(q>)FtYOwN_b?#&fNLLI{LKUz2r~XVoAp6?vrhbvHtS=|6A)a(JWi0Q zi+Pfu8zheD1ir7nC=HvdUq+y3sF%8#{S3%9QwW;c7wW(qWDZfTJ v7N6g2}C(J2=ItiLa z&~$=kY+_C`pP@G93xZ}6bfXAkx R&=naBY)5+(J`TVDi= zz1wG*AEnmLG2b!YGd~bCi=f#A%^_&+CcwS3=qE6;428v8C!?EJB}DW{v7j(X#_6`W zq_U>z@^Kk(+YG$h8xF5)Hn)S{Njc!A?QxK*GL7J&GPQ#P0mK&90Yz-JOVJeezFuSn zI2OcGEMhTBvkc3!9Lp0lk06mCLePAIZX##_oS7tOp>#Y*`Y#<2vi+AK8^$38T=fQB zg-MfR4>2`>OW9&>F-pr)V4Bb&MGv(}gSCeONvDJcEiG9-Z4U2& qFHjm9`LDE=B&>aMU{(2`tpugTt&}xF# z5VV${dk9*$gDqr>*kZN>`cTH|*mCMDTgg@tbT2`>2(}PB4Z4MICU_&kU19~nJp^yE zO @Yi~{(t9@mRtO?eeoybmNClj=upbZ3V>|t+Ur?3F0T?B0=Xq$x7KClU{m`-_c z7F+mQ>|h0?Nr4y_!@xdkXUY%So|BFaUQzMD@=^o#4tKCtX_r_C>h5BJ7xakX15}5j z>`ZDnJBytyg=a_>1)CD}NBCg?!%a46gPqIX2>OI{VyT;*3voMguple4^QD>rH@9@L zfSX${uNmsSg}s$sR0B0zZ1GP7-3QSlQSdJzS{)Suzcb>aGZLetGh(8mqBHcS_Q~cp zquHWw>S&GA$gMA7LDqo-{k?|>0JA{->|vL%Am_lTFZsK@Pq(vofd0%bXIHSWOSTiV zgP{9+*j4PEEbNpA2--=|gA%Ftb^;EULc^Na#JH&FtVC@Bd|uXxzM_BMU%evPFwJVP zg^ou6>o=81qXD~QvvD$b|BW3H_VFdPU%J@Wp1cz4*xAww)X&_reTlRJw&mF%U)=pi z_z`X2#cuiHMD5q7j>1Lz6l`Xndz&y#m(d f;JY!@P0-h_Bq)I^r&7j=j!&R>1{1w#J5C7%l|G56oYeh zk@o0$9q=u1Q4VrJ4rsaZMz0I7ce6atz5)6p`vUtSdx(9BJ z&|?IF zsQLs!AgVq^5R7XdLC+AhpP*;Avqxm e%p@o+c$Cps@Z3&Bj6`SI;f4C6e28oA+| zf^*_Va3eWq&V_U3+&FiFULojJf?gvCDDw@1jt~Usa*Uui33_Wg=P6So=YwrAA)KE? zjmPcOctVZ}A?UsTQR6>Pja(E^BNt83+r8AtX@DB9j0>@^@>nhfsF6!1=wuf+j-Yq0 z&5*%qxh$Y3E<>WmcYzx5Z9t8O2BSuMOXImBnF0$X3Va_Z5Z@-1zmk6KPn2_di2^IQ zO0J5l=4!ZFu8ync8n{M+J|yTPf<7kb6M{g2{gj~71bs%(=LCJRox8r50u7u|vZryA zB?|n~PJ!PL^u26P`=2XcX0-okWD++`B0(@Fd}SxWSwMo^Y;KP9L(ta*osmDm=QctS zZC~!2IO)he2deeAUED%~&R!!aF6M3n!b0D3OC_J%IWUZIw@W^^@2-G0r=Y`q=hE!0 z-pQ?&$?|TAEG3uz)t Ja?cWs>{NLW zsPf7P6Z *67{Q>&D+qQX zc*J(@TrUOwC_5Us3las6v{Rsq-O+$O{zroUJPGm~kRZdg9an?5(n?Z zLxQ9(egwhr=}fTOwUHt3&U@L&koT0x&|M-butETXzA_TQ-jpvd$2Rd0+eEPEwLB8a zM}lRS597o62wp|-D1v Cf#C3dF%10md=o!`{+i%Of?)?l*diDHd4iVgJ-dF`p0?h;Qj_=_28J#0 zQ}`BwqX@PoyclE zK-S$bka(3!VHdY5Aw|)AOy{ClQ=3S%?N(AN%t6pThqzYGm+=|A~bkEQG^8{)PN4{mwS?5G&TjFCiFC z?)C+(@XPqy`Q_4rk0UsRV9=Z(ROO#V7Fg`VKgYc1VGm>G@8nlsw%BWUfb~>@)1);R zY)AtPxc2dF;5QCj@E%@DPr^$}K7-#%aE5KoVZk#u@!ROC<=^Aqmu3xoJ>>-J{_O}X?a%Y< MoL-$3xx zfuhPEGWV_5D`I9u%#h* Gt}8q9yiEnnVy*tk*>*(i-7A1>X`Iwb$mu*|B86I zqU*1yC{B}+9h;Sr9-+-hPl(WHV$vfL<6|=-vNEG%vt!ko*lcZ9@6-s6!gb)C5rz;v zp-TW|p;?-4kE?>LjSC7+Ks^G;qXu!#TNIql7F^J3!BucW>!?`4Q}BYb{zfUCoWYil z%jS5OQ_)Gs`3W|Olt8eN;E7js{n{pz6MUdqQ5Y?yya1n1?|FIaWGOKM!IL1lh2TdG z7yN|)$z3IRwKM#~DS{{4d__W#Fs7l;QzSjp1DAp+QFdQ7$%R6NFbEX@FIqp(gI&t# z5yFKCDSqZE_XiKzv(I^?5G~C)@aZXCLJYwz*D~jE(wxT=+&b8trwG7_ ;Bv$L;n>%oGB&EHpgX-u)aQPwIXy!5v-bCkWa2ONy~SRV0*v79$iB zZ0!;Nw>lvx1}0Z>^2@%t!MK%BDO^vvZWF46YN1A`73zd~p+RUA^aM{Qcm}~Bpv)q8 zHo gyk41tB!Smr19D(C+!^OZ_lO?MK z4v|6h1-PKCwh&i2sT26)tdL#?&PTZRznljtLg7?8xOsrc HH(8~5 zm9l0IyiqBqXCLfVal4e{5@t8*il=(R0N}Q+vsFrgBNL9!ILVgEr9#_jYB5wr$7aMv zMNLqAC1cfX)Jr|WGU0Y%Il;>aUPbWgzOWAA4&iR#1HvldPT?+sZzmWEt>_U}3u^=* zm6ZhF0fUsrCVA5b4q-sskdnvTVT%=zB7Od%pcb;#=!}rBNKQu^^4F#1Hf&)}{%Laf z7FDXW@2GBJ%V3?~D%>Y*Blu2&VMuq2;r^+;QH0HuG7wWr85(yA0g#Dw$iTF09RJ^^ z&KDfYJ0NKb YXSCASZ sZfTliO9|T-3kKPyAse$TnJ<)+pvXThNS zTNNTNKqhE6AZ%5-6vVHy#V}RmNo{DsQGaY$SU6-z13gl1_fm{m9}Rn6ey866T}Oy$ z0V4|1$f9GtdScWX(Ux+$CoVogybcU HIX)V=UFhi&i{hsPjQ-1G3}hL>!a z-QI+hbzeZfvp Dx| zcrU^x{3s+EeGMOhv#wu)o8bq10p52Y$D>hwDMg!m@uc?`4Q8G`4!>J~z=|yZiw_Hr z2zLpO3VUtfxQ1ZRI9CvS55eoU2#=!~!jr;NkpBl5@x5X@!Rra$0EvLwCB*dmYiN@Q z=Wh#vXa Fju714n+;8P6HZXrN~XzAp6E>g2)XWs zcae5G9S!HuA!ddDk^i24R5&GkDuCaTfy3xh_zDKmrcOF}g*Oun+W0mpUb^pWv+$KH z^Kbc=4W`0bxg7|@`Ukb<{sZ|@ZeaWW 3YmrLNXz#Cl+p6Gh6k-MIoz!|uS+;n)Y#B6RZHxFJd z0bWe*7I?Wt7q^T12wn}5&$sZm@;zW;IS4OqILe>qKZln!e9eEupXI*;74#?mXGsqe zhQW&(M!>5YTm^T~qDBcmLbQ+xlJ68@9=vX$Ti64yRd_= 4O>|3WcD;jZvjj8^z6f)v4uP(`?+TrpFzL2 RUQxWJ zcti2I;x{K}r%0!Krz)pfr+O#7Q &WD|kI=}1uh4a_W-#DLh{@(dVmk} @N!T!LL9Tq0efUDPh) zU0PjcxvX%x!{ttwyIt0}+~abu%LbP&mmZhRE?Zspx$Jj&&gG!X3oeIT4!gYS@`lS% zm$zI_xV+=?hij;7vTKg(4X*QD?{j_1^<~$O-556~w?MZ9w yxoo>6_9&&rc?NPVK+@5!P(d{L-SKMB6JK}cC z?Jc*D+ zDX7{b`+uV1!Kj6O0 z{bBb#?#JD~_i*(H_Q>|A^_b|fz+<7utsaX#mU=AnSnjdXW0l7P9{W9B_xRl7S5H?@ zcTZ2xQJy}YN>4w}a?b|O7SA@%cFzt^tLHS&8J@E|=XfsiT;;jebDigU&yAjsc|PHJ z!1EK&&%HRWkzOudZeAW qO9bR+27JDuATIRLfYqi&A zudQC&ymoj!=JmYSi(W5zz3g?u>tnCayngVyILcwvkWoWN4IlN$sHaCA8+BsTx1)ac z#@>uK=bh@E>s{_$<8AbA^Iqe<-uor* 5f8~9~`&;jG-oJQX^kIBFee!*(d|G_k zeA<0Fe5^jxd}jE}@|ojvqmSrwr_bF!YkcnUxz}fdPnS=R&t{*kKHGeD_#E>2eDsjf z5u-~-Pal2H=qE;>9DRQDMI}};N=`Xk>8|utj#Bz4l}bNlfHFv_R>mn4lw*}C%2Z{& z(xhxtwktc7)0H!ovz2p|i z-=}={`R@09&iA123% NnhPl%J2E($CK?(l6Ri?HB8( z^~?0j_RICF@T>Bx@vHNj?017-i(i}HY` =LFsuC L4MOwhMMzXkmfba4zCGi;1v%!o10V|>T>j|m(zW{hS` z+?a$hNn>)xl#i(#Q$40Ocu25&uxIe7V4vWy;Iv?EaAt6JaBgsZa6xcUa7l1kaCxvP zcuH_ 6;Mu`*gXaaW3w|>A!w?h_7&1P@9I`Crfsn%?$3l*WoCtX* z fz8Cso=*OX_LO%=rGW6>(CX5er z2pbYMG;Da7Qod|m;yewQF-W1*(J~7-9erx!W@MYmE z!dHdg9lkdF-tdj#J>grzpA6p@zCZlA@Ppwmh93@pHT?DPqv3Cc9}oW_Vnjq-M0LcR zi0+6NB2KFqm9HvP6`_h!#i+)rGF3UMd{v>UL{+9LS5>N-RTEVvRg223nyOl+x<|E9 z)vemB+OE1^^`L6EYQO4$>J`;%s&`c%sXkGiR(+*9qdKelE|Q9jh%AaMjVzC>imZ*S zkJLv_h%`pt7)c@*L@tcHHF9y}ZIO3Hu8CY1xju47 a6L~1|t;iFR??k>A zrH)FA(t BQ=xxytMem7zEc%J) zm!sc`J`w$H^as%&$0Wq0#}virVk%>5Vj5$bVhk}8V_IXZF^gmFj@cNqKjy`l&tv{j zk5ntwzG^>pfI3 &S`o{ZZccOdThxWjR;#=RbQB<`cQ zFXPU~{TBB}JQdHz^YM=H*Ts9q2gE1Gr^naCPl;a;e@p!0_@(j7;+My-jK3#-OZ>L@ z`{N&se<*%W{NDJ3@h`+5ia#9xcKpfscjMoW|0@1W{I~Jv;{S-hn1B-K1VzHg1eXN2 zgn)$T1WiI*LPA1TLT (#=VCC9O_co3t)zebUCH?xamgTaxZeIzE;gs~$UH z>}_M89(y*~Cpj!xl^mU{NsdoWOfF2WOs-3AOm0eUPHs=0o;)jgZnBtsOY-96rOCG^ zuSi~-+>^X3d2jL)$xkQmPku4^aPlk3uO}Z#emD8k #eihoK_N=Qn0N@Pk* zN^D9(%Gi`~DHSQzDRn80DNQNODHBsnDJ>~&DN|FdDbrFGr)*7mB<1ClPsX{78#69* z+{AG+#@#V) 2dqVJvZ)Ds#j`eYH4bDYE^1&YD20%wI#JP zb#Cgy)J3T)Q`e-fPu-EaGj(_BBdL2+A5VQD_4U+~sqdxnX^J$zw2-uzwA8fhw7j%} zwBoeNw3@W~G<{lA+S0VWY3I`}rVHsq(w)=2)0OEV=`rcC>Du(X^n&!_^s@At^!jvt z`h;{t`l|HT(l2OPtwK9O>#TLtdT2*!$7n;f5!xuNS{tWL&}M0Kw0YVB?aSH|+HbVy zv_ELiYk$%HuDzInGuR9vV@QTF!#^W1V@yU!MtFuQBPt^%BQ^s(AsLk!of&H~p3L|# zlg$jt%*~vXxghhl%;lMPWZs#%K67j4w#*%w4`e==xjS=T=ChdxGhfU+ocT)Tmzn1? zf6M$ci^^iN_$ $1GE0 &7gSwIJ)3 zti@TkWi8LTBkQiLHCa2ec4s}DwI^$D))QGzW$nw_pLHPX`K%YSKFy}H$7JVaw`Sjw zy*K-K_D?w@a=dbUa(r|AbHa0CbK-LnbH?VR d2&Z9X`<~*IVKj- x!ZGJ$vv0nnwOMUlQ$#p&b;+` zU3r`Gw&XpS_gLPOdHeF7%{!R)Lf)ag!+CG#y_5HT-bZ<-@=oXD{Nee|`L6jM`9Ar| zeE {{HcAj6Yj2tRSpF zQxIQ}RFGVdRZvt=QczY XOa z5>qn2 z(KbHJlT2xwBYABsldP8YzX?y9+(mAE`O6Ql}TzX6C z-qO#?T*}6kRhPAvO)HyOHmB^yvfIm6mfcyly6m2^vt<`_tj PL{ubIjIBtn7*{dA zqP(K2qPC);;`$0xMN5UbqNAd-VtU2aiZ?30s<>DwR1T>eR;j4;tqiCfQyE$rQ8}yf zrpo1&cUG>hyr*(wWl!an%KIvxu6()jMCHlKcPihj{Ic>~ QvQdRbN#7Sv{oMw^~&l zSshg!Q=M9!U7c55P+eSISzS|IU#+ihs&1=pukNVstlnO|xBBtwC#&~W|4>8K;2Nfe zuSu@St0|}{t|_ajsHv*4)Xb@wS2Mq6LCu<)`)eMpdA#Pynx|@>sd=vE=US%LwbrB7 zt2UrEyf&& NMBT_b*E)~7qPn`e#=7h4Om!`F=DIm`^Xlf;-CTD|-J-h9br03;se7#M$+~@Y z`|Dn-d$;b3y5H*ltVi`sJzwuwKeS#^KeFDnKBPXZUR57euda`)PpnU_Ppwa{&!{h| zH`d=+zoP!W`lst(tpBk7LIY}uYe;U$YbbAMYPg}HwV}Pi(lD)IUc>x`n;ULzSkiD? z! kR7+8x7kG+YR>{_81NuUNyXKIAS m;S ${4d)FP48IwR mjrGPx JG4zH6d5g4c3CZ>rKOfqpk)+F%M^326Gaic zD2jq~hyt>#ESV}pK=zcqhl+r*6oK!ggTH)#pYM6T=E=>y_c`x--tl{X?|X0e-GbGV zXTE@;VAkM#|9tc*T7bSpOVKj49IZer(HgWCZ9p5*CbSi8LqDJ&(H?XN9Y&|nX> xHrNh3 z;0M?Vd*Bcph9htq&cInX2j}4m{0zUrO}Gbt!DD!W5$3Q0E3pcP;|OfRW*mzxI1bzJ zbGS8bgWF<%JDi5oaeLeWcfnn8Pn?5u@j#r1^YJh|9FN51cmn3}%lH-i4xWME#f$J_ zyaa!Vm*Qo3IbMNR;;(QW{u*z>oADO>E#8TD;oW#2K8TOt)A$TNi!b7<_-A|z-^O?F zWBi05A||0kLM$YXSp6iP*od7th?BU8n|MefX-QH^E0RXiNf*+UbR#`TPtuDFAUPzL z3?@U#Ffxu*kV-P1Odu1 zc|jk%Q pzZ>NNob}}*GWSbLpV$uJZ5CcxQc{?!+;4V(r8V>MrA8e ztvE~>Aw)?!nReaZeB!0!3Un|iSf!{6&&!%nGPI&sd0A<3QN_VXb(Anm74Hu$nnHZ( z+jc$3=>74qYMr4vT5my(f0iwA4QJKH7)x5^+WHGi+MD+JlPWV)9V@8{MZrjkqLCN1 zLETU<)EDKVA!sNXfkvTn^ctFt=CM+%MGH|KE3n<@1iFZRMK{s!=%E`pRy_*PLNu7_ zl_Crczv!tI4c8DWJe1vtIfSH0hU91tnv2}k=tJ}o_0ne5C bH zU5lzw4cq-Qnn;tVk0#fm(dY}b2#uz3v^h-?W`-0A&6F1TSLkb`u0nORMHN~_TMC6r zvuGWfj@AorC{2;6Jr!R)8*y=vED&-3f v#waxXykbcklU9Gx XDUMSy4E6WN~_VdEulQc5gSL{d;89Up_UeN#$O& zKcI3SO&4xNcw|S=@j#4^qGPlJ%@FL7nFVLjFUY+FokQo*1(wE3=rX#3uA*z`I{KM* zq@8GI+J$zd-Dr23Nqf+qwAT`r>l^4dmhW5WHp}@R=ngx-M|;yOnoaxCezZTGL+8=; z?0kc8JhEK4q&5kq>NH^w!)RBvDPd4%;lz?rC6kMXWK|Sa6c;Fz8O4JuhYc$(&tfG| z(XXUGr6 zTV`rINP~1}4;>%_o`;U?tTS{Gj%t?MC(`j0(IIpaok%O_grm?6x a{V7xacc zkOkS$S6Heom5ic8=@>eW7SoYJtgdD20fEhO=rB6s5adBVlNtmC@Ir2vA;qIBN`{sc zm-nqVjSi J*BHNJ6( z7AV3q`ekP{N_Q_SDy%3e8-0*zu7vS0A$JS|K~_b1$>?FUoQ^F}2)z;_m?nL*22GP; z%0MRHv1DX%16*EYaQVlLhE*?tUl?uh02MwlG)sM%DSw5<`ZXBI3d=jVa9lA%n76!m zB-?v@F^hO5WfriCglX_*-yT`ar)rpns4zbvTlSAY&471>L~|4i)J&n7S?g~|@_PZ~ z33LjpYWRR{H3vQ{P-u!O%gb4Ko*z -3FU*aVwl3w%qb(Kl)ETXc4y>3IZYcDOLF_mM={71(??olZv_ zhP@0c0mSTs{cr#d=8P*I$r>9=Hl0D=p>I>+A2?}gX=rdOKW{SNDE!2z4UWNa`YxSW z4JY6vokicH?tTp+?U!9xKCHMx_@bYs5o8zOqOc&zEQU*PndNRll1Z4GYY2y{a1FT^ zETHa&6#oLh3h6C0EQvRSb}hXAf0o!SxZPM{cj+he!^XgV+z{CN0pA|bkNy+bhxLJ- z`~L|n7U579SS-dtI2eb}`BC&!x`0;IVhIj|0xYA|^b4kNr7$A3T|AD&y1;5Rj=~zO zr8TscenuD8qBwK|8&EtWt1SAta5!~Jt9l!;6;c;4`x;s>w&O(P{sKF&6T7e*d$1Qb z!wGZ|T}+qIFX>Xcj4r1u>RxNL02DX_cVw*vKTp4^!kuWH(7R=H3hst>RO9YAlYULt zJ!Mwh3uhyB4epKm;4Hd|uBK~huo%VT{&YSYjn)c_S|<1{X;U=+?1p#{9{gWIK}@Ka z1wc-}p;k*8eWrin5?tDlxF&x_;j*VDj-eX^8D-Ru#|4b6z?F0p{kF+SzZ_4*FaFnt zQ`v@ox|wabg<5mEWIW#hCQI71Y0nt@DxUUVvTrik>GV4$`#rTX#%Iz^Z7#jMxX_Z8 zx8*-N{LHSI_!HKO@htov7VvERKK=mD!5`v}@Lc>c-A1?59rOpflkTFs>5p^|-Anf^ z!SnEZ{3%|*wyMT8xR#}PA^x21rx$tf@Q^^|JhbB>mxqBgi-&w31_dfm*{5=JhqBQX z#S<&~6c;ht8CUmK8wHr~D!eY>$7;L=ucZg*L3*eLe}mWK4fHTQLC* ?%!c;F%lM5nqj%|u`m!QPkXlQ8 zBsuV<_vrol?+ArTk=Pg~@*HWy26EDx{#ixZ(!T_y(-zg9Jdf1Xqyx#I59#04q$BA> zAJNCc6jN+6>0VDy%J^MRNAM<9y$Pd~YSM==RI_Jo{2##srYK=*&!A*7kPHfRgw7 BgjY| zf_Mn#A%us}S~8lHkuhW}4-y{2cwpg)e5S<}k;#EDP2oZIj~+)}B7Qa(9ppj5gPe6z zp|PJ??ln31DtUuhPhKOh^PuEGRZXUmH+cx>A>v f3MIt5vF$0AZgYMWXhBTVvnz=bb((Erng zCFDy|9B{$NgMo#w!H4@vr?e-Vd{{}o{$D< MVr z38lG8j{Hh)2>#rbDsq$D4wT0&9=uiLcOIGvn+C?^llvSX^&;|s{7L>I56R!;5qV6W zaEOOQ9+G(Q@sP|za~@K7V8*oMA$1Xo=SbkoiMb#ym -5m)OFalv~m(aFLkoZr+%1E}Anj$Z>kkz!^D~<}@DCd1%i=hg#0e#c~#og*t $YsHy)=*~kXQyb70FU&783U3XnNas3mo&HUxGuMS<(mi?T#Y1oEwzRud--S^T zGFdS))n}ONNiNm3D^PIV!PVqjA1;SI9x@xUxxQQru0J=R-V(+?*~}Oo`ts0kA(smU zTppLt2E76v`qL5~*s>fppp~%t+EQc|HWa<#4>Ut=SYvBg+wt^g^!T9cvLS_&OobJu zq=Z%p3H6N1jbIo?N{XLOXj~aLmVrHRuZk<@A+K?y;VRiPMg2 vThLE!vF z#> EMyGyDJ%MogjFf|o@`@fw3F;6dsxk!BNxb}0NTmV49~xjTMTqjTqkY}w~{-= z-4un2BqEQ Lbb)^%D&c<%;q|gG4Wg#)&FL6GW3lQ$$lmei1KvMf95J z4bfcDQqi}f!=h`VyJCshD0Yie#qGrz;*R3Z;;!N>abIzNagKPPIA2V~v&9R=KZ<`6 zUl3msUlCsu|1ADPd{=y5{HOS#_)$ `d7Cu!~`rr6E$4G+Y`fHA+3wWNB;Z^U^-j zzS92ETxp(kkn~0Ao6;H5nbP;9bEF?hKbFpuu96;;UXnhPK9W9>fsDvRvLIQAOd^xY z 7v&A*P33LnAF41_jLNI(sLD}QswSu=sivr= zs{ATmRj1mZ+N}Ck^}TAp>ZIzt>Z0nh>Z 3Y+ z@mC~?42hIQ+9L-?4vQQU`9|d1ku{NDMlO$B8Ce&(A@W${Pmw1h|BigDMry3))M9n8 zI#eB|wyJGvhuWp~sGF%1)veTR)a}&i>K^J|>OSghb&h(lx=cM*Jx*Pze%Y^{u6{@T zu6mYQP=BJHuU??8R@bT*s*gsAqLQQXqb5YX9rb?Hhf#B*K8acywI*s^)cUB6QJXbk znn+Eo#-?#-T$%(;k|tS`qG_Ya(Bx=_X~t+~YUXIxX!dAMXijQQY0hY_YMy90tzPTZ zcG7mycGG5Rdun@Yv$T0ye}T48TcjPME!S3P$7`o(U)9di3flLzbF{VErP}4%mD)P( zD(xoi7VUT1t=jF{AG8OwC$(3!k987Vgifu~=yW>0&Z@KN96FcIqid$i)RpSq(Jj<1 z*R9ZfrQ59AuREwatUIbZt~;SSr8}cLr@O8DLw8qqU-zf(p n69H}%u?GxRg{@97unm+QaQuhy^Cf1}@_->cuRKd3*fKdC>hKdV2l zzo@^he{4`1bOxKjYe+C88Ildp8QK`y8PW|M4BZVmhFrryL%yNZFv?J7C^u9X#vA;G zR}HTlrWyQi8Ri(~8x|O<4Yh_PhNXt(hLwgo!$!k)!y&^7!zsfV!#TrM!*# P zMlgmNql{i-f-%XMY)mn>G`2FfHnugU8QU8(j027N#scGDW3h3VvD7%qIL26RtTawE zPBzXkE-|h(?lWGA(Z;x9I>(g8ycjblrZ#4YKW1sn@|cw|Yh%8N*$}fSW=qU@lh)MU z)YFu0>Sr2Y$~P653Qa|(F{Y`e*G)4_b4(wZs!fYb%S>xbTTI`X_L&Zwj+%~}PMgk} z&YLcpZkZmL#b$+BWo~2cXdYlLFb_A6HIFmTH!m?SGp{h$nOB+Dm@k-rG2b!YizTuC z(Acn8S*#*9Dpnh-kBx~n$M%k$5<4w+dh9!~Gh^S2ogG^hTNC?P?B|wvi_g;8($&)4 z(! 1P>W$+hHJ##+W%DlHQ%lPps#Q!RcAZ+X@7x@DT>Gs{-XwYbnYZ(MfV z#JD+etK$yEor*gfcRuc7+^=zW 5qFD_bBd(6|BUnu!dVBts1M&s<) |)coAsdenDr;? zDeHObCF@n|b?ZIr1M6SbNAa2Qx$#BuL*q;0N5+@MPmG@u|57|3|7!f}@vGzgmu(TY zHn#q@k+w?PMB5bGRND;OEZc0`2euDwRkmfeI@@a7I@>1Ox3;ae?Y2F(!?x?T`*zMQ zvWxA(_DH+YZnnqSZFZ;KXHT)G+FRS(+0*SK?6d8Q?Q867?d$C8?OW|T?7Qqg+E3fh z*)Q6!*ss}d+aEiKL+l9gJ7f-}Bf_C}xE-mEj*d=_&W^5*{*GKnzT*W)k)zmA?x=8# zcT93DbF6o4a(wI9>e%7f>A39p&2igt$8paoaT=X=r_1SadYy^RWM{fF%h}gCz?thT za*lA0c8+yUc20A?>-@m^sdKG!v-7y~H|Im=V;8tMSCGpe;)-&`xe{F&u1>D5u1r@i zSC*@vE60`RDsYv%DqIs>lUy&l{H~W>ueqkV-g3R|n&VpL+Tl9ky6qOb6>hsb-QCsg zcfaO-&ppq**j?vd?Ox~J;NI;1!M)qP*L}c!*nQM}(-Z2kdIop~d4_t1d&YVudZu_@ z^6;Kl{GOSfIi9(md7cHH&pnGhOFb(*UwKY?L%hwsZM|vUOmDWgzc<&L?;YYD<}LM( z@|Jlgdi~yMNpq6sCVigtb<&!oZ<019ZAtn*X?xP4q@zj4lTId`NjjHwA?cDY#OL)5 z@V)Gt?wjqK=lj&R%(uq(jc + + + diff --git a/SwiftProject/SwiftProject/Project/Controller/RecordingVideo/CCSpatialVideoDisplayController/ZZHCustomPlayer.swift b/SwiftProject/SwiftProject/Project/Controller/RecordingVideo/CCSpatialVideoDisplayController/ZZHCustomPlayer.swift index e39a480..1f988ee 100644 --- a/SwiftProject/SwiftProject/Project/Controller/RecordingVideo/CCSpatialVideoDisplayController/ZZHCustomPlayer.swift +++ b/SwiftProject/SwiftProject/Project/Controller/RecordingVideo/CCSpatialVideoDisplayController/ZZHCustomPlayer.swift @@ -11,7 +11,8 @@ import AVKit //专门用于assetoutput资源释放的 线程控制 //let AssetGlobalQueue = DispatchQueue.global(qos: DispatchQoS.QoSClass.default) -let CustomPlayerShareSemaphore = DispatchSemaphore(value: 1) +//let CustomPlayerShareSemaphore = DispatchSemaphore(value: 1) +//let CustomPlayerShareRecursiveLock = NSRecursiveLock() class ZZHCustomPlayer: UIView { @@ -41,6 +42,8 @@ class ZZHCustomPlayer: UIView { } } + var playerIsSeeking:Bool = false//标记播放器是否正在拖动 + //ui var playerLayerBgView:UIView? @@ -137,12 +140,13 @@ class ZZHCustomPlayer: UIView { //通过slider进行seek播放时间点 func manualToSeekPlay(value:Float,isMoving:Bool){ + if isMoving { self.play(false) print("此处已暂停播放,那么后面希望不要出现 sta.....> 的打印信息") } - Task { +// Task { let totalSec = CMTimeGetSeconds((self.avPlayer?.currentItem?.duration)!) var atSec = Float(totalSec) * value var timeScale:CMTimeScale? = self.avPlayer?.currentItem?.duration.timescale @@ -154,24 +158,30 @@ class ZZHCustomPlayer: UIView { } let ct = CMTime(value:CMTimeValue(atSec) , timescale: timeScale!) // CustomPlayerShareSemaphore.wait() +// CustomPlayerShareRecursiveLock.lock() // self.quickLoadAReaderWhenSeek(startCT: ct) +// CustomPlayerShareRecursiveLock.unlock() // CustomPlayerShareSemaphore.signal() print("正在seek.....\(ct) ismainthread:\(Thread.isMainThread)") - DispatchQueue.main.async { +// DispatchQueue.main.async { + playerIsSeeking = true self.avPlayer?.seek(to: ct,toleranceBefore:.zero,toleranceAfter: .zero, completionHandler: { finished in if finished { if(!isMoving) {//结束拖动时,再进行播放 - CustomPlayerShareSemaphore.wait() - self.quickLoadAReaderWhenSeek(startCT: ct) - CustomPlayerShareSemaphore.signal() +// CustomPlayerShareSemaphore.wait() +// CustomPlayerShareRecursiveLock.lock() +// self.quickLoadAReaderWhenSeek(startCT: ct) +// CustomPlayerShareRecursiveLock.unlock() +// CustomPlayerShareSemaphore.signal() self.play(true) + self.playerIsSeeking = false } } }) - } +// } - } +// } diff --git a/SwiftProject/SwiftProject/Project/Controller/RecordingVideo/CCSpatialVideoDisplayController/ZZHCustomPlayerForVideoTask.swift b/SwiftProject/SwiftProject/Project/Controller/RecordingVideo/CCSpatialVideoDisplayController/ZZHCustomPlayerForVideoTask.swift index df1d948..c89a781 100644 --- a/SwiftProject/SwiftProject/Project/Controller/RecordingVideo/CCSpatialVideoDisplayController/ZZHCustomPlayerForVideoTask.swift +++ b/SwiftProject/SwiftProject/Project/Controller/RecordingVideo/CCSpatialVideoDisplayController/ZZHCustomPlayerForVideoTask.swift @@ -13,51 +13,51 @@ import VideoToolbox extension ZZHCustomPlayer { -// func getPlayerItem() -> AVPlayerItem { -// let temItem = AVPlayerItem(asset: self.videoOriginalAsset) -// AVVideoComposition.videoComposition(with: temItem.asset) { [weak self] request in -// -// print("正在请求解码图片frame....") -// guard let weakSelf = self else { -// print("self 被销毁了.....") -// return -// } -// weakSelf.convertFrame(request:request) -// -// } completionHandler: { ac, err in -// if err != nil { -// print("初始化coposition报错:\(err)") -// } -// else{ -// print("composition 生成ok....") -// temItem.videoComposition = ac -// } -// } -// return temItem -// } - func getPlayerItem() -> AVPlayerItem { let temItem = AVPlayerItem(asset: self.videoOriginalAsset) - let timeRange = CMTimeRange(start: CMTime.zero, duration: temItem.asset.duration) - let videoTracks = temItem.asset.tracks(withMediaType: AVMediaType.video) - guard let sourceVideoTrack = videoTracks.first else { - return temItem + AVVideoComposition.videoComposition(with: temItem.asset) { [weak self] request in + +// print("正在请求解码图片frame....") + guard let weakSelf = self else { + print("self 被销毁了.....") + return + } + weakSelf.convertFrame(request:request) + + } completionHandler: { ac, err in + if err != nil { + print("初始化coposition报错:\(err)") + } + else{ + print("composition 生成ok....") + temItem.videoComposition = ac + } } - - let videoComposition = AVMutableVideoComposition(propertiesOf: temItem.asset) - videoComposition.customVideoCompositorClass = ZZHCustomVideoCompositor.self - let instruction = ZZHCustomVideoCompositionInstruction(track: sourceVideoTrack, timeRange: timeRange, transform: sourceVideoTrack.preferredTransform, targetSize: sourceVideoTrack.naturalSize,sourceVideoURL: self.sourceVideoURL!) - custominstruction = instruction - videoComposition.instructions = [instruction] - temItem.videoComposition = videoComposition return temItem } +// func getPlayerItem() -> AVPlayerItem { +// let temItem = AVPlayerItem(asset: self.videoOriginalAsset) +// let timeRange = CMTimeRange(start: CMTime.zero, duration: temItem.asset.duration) +// let videoTracks = temItem.asset.tracks(withMediaType: AVMediaType.video) +// guard let sourceVideoTrack = videoTracks.first else { +// return temItem +// } +// +// let videoComposition = AVMutableVideoComposition(propertiesOf: temItem.asset) +// videoComposition.customVideoCompositorClass = ZZHCustomVideoCompositor.self +// let instruction = ZZHCustomVideoCompositionInstruction(track: sourceVideoTrack, timeRange: timeRange, transform: sourceVideoTrack.preferredTransform, targetSize: sourceVideoTrack.naturalSize,sourceVideoURL: self.sourceVideoURL!) +// custominstruction = instruction +// videoComposition.instructions = [instruction] +// temItem.videoComposition = videoComposition +// return temItem +// } + func convertFrame(request:AVAsynchronousCIImageFilteringRequest){ let compositionTime = request.compositionTime let end:CMTime = CMTimeMake(value: Int64(compositionTime.value+1), timescale: compositionTime.timescale) - let tr = CMTimeRange(start: compositionTime, end: end) +// let tr = CMTimeRange(start: compositionTime, end: end) var ciImg:CIImage? = nil switch self.selectedIndex { @@ -66,19 +66,31 @@ extension ZZHCustomPlayer { break default : - ciImg = self.otherModeImgWithMode(mode: self.selectedIndex,tr:tr,compositionTime: compositionTime) + if self.playerIsSeeking { + quickLoadAReaderWhenSeek(startCT: compositionTime) + ciImg = self.otherModeImgWithMode(mode: self.selectedIndex,compositionTime: compositionTime) + } + else { + ciImg = self.otherModeImgWithMode(mode: self.selectedIndex,compositionTime: compositionTime) + guard let ciImg else {print("未合成成功.....,此处将进行重新构建assetoutput,然后再次重拾") + quickLoadAReaderWhenSeek(startCT: compositionTime) + ciImg = self.otherModeImgWithMode(mode: self.selectedIndex,compositionTime: compositionTime) + break + } + + } break } if let ciImg { request.finish(with: ciImg, context: nil) } else { - print("未合成成功.....") + print("未合成成功.....,") request.finish(with: request.sourceImage, context: nil) } } - func otherModeImgWithMode(mode:SpatialType,tr:CMTimeRange,compositionTime:CMTime)->CIImage? { + func otherModeImgWithMode(mode:SpatialType,compositionTime:CMTime)->CIImage? { guard let ao = self.assetOutput else { print("assetOutput 应该是没有被创建成功.....") return nil @@ -168,11 +180,11 @@ extension ZZHCustomPlayer { func quickLoadAssetOutput() { if(assetOutput != nil){ - print("正在释放assetoutput----assetOutput:\(assetOutput) \n\(Date.now.timeIntervalSince1970)") +// print("正在释放assetoutput----assetOutput:\(assetOutput) \n\(Date.now.timeIntervalSince1970)") assetOutput?.markConfigurationAsFinal() - print("正在释放assetoutput....assetOutput:\(assetOutput) \n\(Date.now.timeIntervalSince1970)") +// print("正在释放assetoutput....assetOutput:\(assetOutput) \n\(Date.now.timeIntervalSince1970)") assetOutput = nil - print("释放完毕assetoutput....thread:\(Thread.current) \n\(Date.now.timeIntervalSince1970)") +// print("释放完毕assetoutput....thread:\(Thread.current) \n\(Date.now.timeIntervalSince1970)") } assetOutput = AVAssetReaderTrackOutput( diff --git a/SwiftProject/SwiftProject/Project/Controller/RecordingVideo/CCSpatialVideoDisplayController/ZZHCustomVideoCompositor.swift b/SwiftProject/SwiftProject/Project/Controller/RecordingVideo/CCSpatialVideoDisplayController/ZZHCustomVideoCompositor.swift index 5c49d3c..56397d5 100644 --- a/SwiftProject/SwiftProject/Project/Controller/RecordingVideo/CCSpatialVideoDisplayController/ZZHCustomVideoCompositor.swift +++ b/SwiftProject/SwiftProject/Project/Controller/RecordingVideo/CCSpatialVideoDisplayController/ZZHCustomVideoCompositor.swift @@ -55,7 +55,7 @@ final class ZZHCustomVideoCompositor: NSObject, AVVideoCompositing { // 将请求添加到正在处理的请求列表中 self.activeRequests.append(request) - print("startRequest ....AVAsynchronousVideoCompositionRequest: \(self.cancelled) request:\(request)") +// print("startRequest ....AVAsynchronousVideoCompositionRequest: \(self.cancelled) request:\(request)") guard !self.cancelled else { print("startRequest cancell....") request.finishCancelledRequest() @@ -64,18 +64,20 @@ final class ZZHCustomVideoCompositor: NSObject, AVVideoCompositing { return } - print("startRequest queue:\(self.queue) current:\(Thread.current)") - CustomPlayerShareSemaphore.wait() +// print("startRequest queue:\(self.queue) current:\(Thread.current)") +// CustomPlayerShareSemaphore.wait() +// CustomPlayerShareRecursiveLock.lock() guard let renderedBuffer = self.renderFrame(forRequest: request) else { request.finish(with: ZZHCustomVideoCompositoringError.invalidRequest) print("报了个异常,但是应该执行不到....") return } - CustomPlayerShareSemaphore.signal() +// CustomPlayerShareSemaphore.signal() +// CustomPlayerShareRecursiveLock.unlock() request.finish(withComposedVideoFrame: renderedBuffer) // 从请求列表中移除已完成的请求 self.activeRequests.removeAll { $0 === request } - print("完成执行 finish.....") +// print("完成执行 finish.....") } } diff --git a/SwiftProject/SwiftProject/Project/Util/PlayByTransferConvertor.swift b/SwiftProject/SwiftProject/Project/Util/PlayByTransferConvertor.swift index d2fca27..20ae8a9 100644 --- a/SwiftProject/SwiftProject/Project/Util/PlayByTransferConvertor.swift +++ b/SwiftProject/SwiftProject/Project/Util/PlayByTransferConvertor.swift @@ -17,15 +17,15 @@ class PlayByTransferConvertor { func convertVideo(asset:AVAsset, assetOutput:AVAssetReaderTrackOutput,type:SpatialType,time: CMTime)->(CIImage?,CMTime?) { var newpb:CIImage? = nil var presentationTime:CMTime? = nil - print("sta.....>>>>>>>thread:\(Thread.current) assetOutput:\(assetOutput) \n\(Date.now.timeIntervalSince1970)") + print("sta.....>>>>>>>thread") while let nextSampleBuffer = assetOutput.copyNextSampleBuffer() { presentationTime = CMSampleBufferGetPresentationTimeStamp(nextSampleBuffer) print("presentationTime: \(presentationTime) \ntime: \(time)") - if presentationTime! > time {//如果当前获取的buffer的时间>time的时间,则直接返回即可 - print("如果当前获取的buffer的时间>time的时间,则直接返回即可...") - break - } +// if presentationTime! > time {//如果当前获取的buffer的时间>time的时间,则直接返回即可 +// print("如果当前获取的buffer的时间>time的时间,则直接返回即可...") +// break +// } if presentationTime == time { guard let taggedBuffers = nextSampleBuffer.taggedBuffers else { break } @@ -80,8 +80,11 @@ class PlayByTransferConvertor { CMSampleBufferInvalidate(nextSampleBuffer) break } + else{//如果当没找到,则直接可以break,等待重新校准time后,再来 + break + } } - print("PlayByTransferConvertor 测试看是否有返回....") +// print("PlayByTransferConvertor 测试看是否有返回....") return (newpb,presentationTime) }+ +SchemeUserState ++ +Promises (Playground) 1.xcscheme ++ +isShown ++ orderHint +36 +Promises (Playground) 2.xcscheme ++ +isShown ++ orderHint +37 +Promises (Playground).xcscheme ++ +isShown ++ orderHint +35 +