From fef3d696e2bfc93aef8dfd634ae804a3dad4d297 Mon Sep 17 00:00:00 2001 From: Sebastien Vincent Date: Tue, 27 Apr 2010 07:11:16 +0000 Subject: [PATCH] Passes desktop captured images to scaler/colorspace converter as native memory. --- lib/native/freebsd-64/libscreencapture.so | Bin 9596 -> 10062 bytes lib/native/freebsd/libscreencapture.so | Bin 7089 -> 7795 bytes lib/native/linux-64/libscreencapture.so | Bin 10924 -> 11238 bytes lib/native/linux/libscreencapture.so | Bin 8237 -> 8679 bytes lib/native/mac/libscreencapture.jnilib | Bin 41776 -> 41936 bytes lib/native/windows-64/screencapture.dll | Bin 39292 -> 42212 bytes lib/native/windows/screencapture.dll | Bin 57169 -> 62986 bytes ...eomedia_imgstreaming_NativeScreenCapture.c | 48 ++++- ...eomedia_imgstreaming_NativeScreenCapture.h | 10 +- .../impl/neomedia/codec/video/ByteBuffer.java | 116 ++++++++++ .../impl/neomedia/codec/video/SwScaler.java | 3 + .../imgstreaming/DesktopInteract.java | 50 ++++- .../imgstreaming/DesktopInteractImpl.java | 87 ++++++-- .../imgstreaming/NativeScreenCapture.java | 25 ++- .../protocol/imgstreaming/DataSource.java | 9 +- .../protocol/imgstreaming/ImageStream.java | 200 +++++++++++++++--- .../protocol/quicktime/QuickTimeStream.java | 111 +--------- 17 files changed, 489 insertions(+), 170 deletions(-) create mode 100644 src/net/java/sip/communicator/impl/neomedia/codec/video/ByteBuffer.java diff --git a/lib/native/freebsd-64/libscreencapture.so b/lib/native/freebsd-64/libscreencapture.so index d259e4d95c392441a19651d9219922e2d94b23a6..4ee183a46e7139a6b7a1f8ef2e0633a6558bb44d 100755 GIT binary patch literal 10062 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 diff --git a/lib/native/freebsd/libscreencapture.so b/lib/native/freebsd/libscreencapture.so index d2fc68024474c44046c7eaa6a5aa472e58730017..98dd3f25184238823265861ae3a5952153b615f6 100755 GIT binary patch literal 7795 zcmeHMe{5UT6~3-bYf4y5Ng+TPhM5vr>o}!ro6?~+$?GqYHf!oq)|FSsd5sN@9qi{S zg=Vz4MYG^NPlr&LOrv8yt+cb&(5mih|)`)d%nh@*AzVE(w zomVfTOk(Vh?MlbzeD|Jv?yqz2yZ87>t$D4-^X!79B8ZY2 zag(?~mOJW_`74DWT}2cSb~!j@(jpj)fMz@8v%o8muV?_6#Bv|#PEZ)cw8&;+vBMR+ zMF|f7d>Q^6@J&u$4S2{^9(2hI9r-qgF95$4bdQ6{?gHHnx{=_&ly3eP?S9tDuLi%t zk?(Nn-VT}bIaB(UlWDKG5aU=QCa>TM32~Z>fkdBR`i@*cV!Pn|5|%43YUW5al-mXC zOV}3PC}B7k(wP#r-H$%UyM+cKWdrzFw9uvejU(N@Dfn74wCfOXjimDOCtgGjEpRw}D47j4y-F z!+1A4vJho|F08&nuc6G{IPD*FVU{0( z9W}lH+Iyv}{QEA<`m3NH!L*-)%>FL~SL-zo>-CsRpY~rVv(FV)^ULuar#)wW+5UH3 z_1WHiE*yls&4p=S=uHo8TGO(jQRwTMH#e+l);F(R+oo;Rx2|bu)^wpK(@9h4yTOF6 z$9rNFW2xlhhR`?e(YF|#$((6q8&k1d&d7;Q!!*)+#P-eIM!G4P>rTb?itUZ5OwK5w zwnW#L@pH9YOW+tmAySh^-&U6_a$rw;)&O{%& zlIc!;Q_M{6G1}r;!$>#Ay3Ksn&^xoSb~{JcHy~}?ApWxr==U~=RI)uD&Sk>Og>H1j z%ovuSJ(tsSW-N!&r3<23S$0Vl6t;#uM?R%L=Bk0+nQL-5tv_)yf4V>3=7e+~}di{$uF{DmBc z^84gCyf2aS;{yFTsOKZcN5@Yd#9k-A9nFyA<5fkDk5)DLT|z7%$44$mj*nqsvSNG} z`ZoRm&f3Co#SlzSy~cBS>LuqGg~W3*0TL5qQ%EnN6C%OliBXApjwP5mF(5I&A_@LX z^h?YRCxXN;N=z|PLws0bbWkKB#QP;?QDOygx5PZ9603=KNlewmdg4}zmlC%Uua=lq z6WfU+60aiOMI4lPHF1JC01Pgo#oxD$e*?mSp&R|27T^Bk%`C{TunJA!hX%}BtOBbS zeWCGs@C(-z27JXrh!)RUl3Rg8XY&)M3asfV4EuKM9O^sDBh9uShHzl$=Wr0%x1PO( ziiggc^Q~t&6iC!%XPkgWK8)ld16uXdD>I!bmZCwAj)=qK(nF zDvw3Sz7{=RJb7p!U)@(Y{dc>g-5-J@ukv6OKEB1O(D;YU(M~YS!>p6m{)4FB=i5Ix z=JP)Fb;wq$zZe~`dTOlo0joP?MJv3~{`%I6eRC}>;MM%~gT3=D?F1(x2y1VkM^h7T zVoO-j6KvuM*~BoLFwi$tDmH}{z)W##sJc&k2dHYKDMW`6;1%3VMKk0t?hE-GyMAfn zGzK%@F?tLmvRm2=eN^*Lq5D?!wAJ9NJkn4DqrMRzJxPpjekm6)bI>IzNWah<1@x3cZt4=0dyAs&D&HjE>!HX_JNbr%XSqtVbSfjx@+YVG^dc zG>vG(G;yH=%~WxYEX|Kz2CQg5CZfX9P6PR^=m3zi-46%AydB~)s8;PseHtZbk&V4A z#nTX{T2(7(V*%$8yxMMylU`*{dcbbE!fx4bX#<=sXJUI{t*CLTZ+0gC0p!?I{SGW1 z?lTvP5$y~_uu-x?Z$LbmpC~|d{M(9-VibO?B1U5OY<+R?z+2FmDz=>4-+Nq`w-rwh zj#XDoRUZ4z;Q7GSqs3ni{=t9Xyubzo(9T)fx#FC{DNkXGSm$wKD~6 z)MG^h_0duD`a*Ao`0Be>?-_6J(OYo9&>R|5lo|mnqtlnS}U; ztbLUnXkj?D<6(X0Q1P#QCvZy2{kp9%S!Ly`trmE05WBOo&-XfuDvu1-Yc;*s+V$`0 zJI2gnvl@IAmc?ob$kK5QGYKE5d~Trf*g#>p>R}uRQeW=p!eqe8`wP86QF-tvVm{;%3v-V zuf=!2HlEAZChuLbY_XBrT^rAu$#C1EJ;A#0^6-)+;kqy=xFiy(udR#JF8M+*Qn#`$ zvT{j%@KIc(`ZJhHs5J{a8L`29{HK1r=`Zf}TRA-QX-a1h;YZ=G*oPEW<|I&oe%FZvhqFR20F^JMvD5j(48_xSU!rvrqKgg zK8?cJjJ%(R?O!9I@6N`$3~3*4ins{J@#e?@+w74z+svRk?(-65HFsVoT&wy0BXP`rxsom#YdW;8=X3~4nrN=lCN%aXuCHaRgy)o#JnyKI<)*<}} z#CA9i#$8A=**k)AHJ1>jUY3HBR2h9k&aspK0y1V=4>iZC{%UNVel%Q-jC(=s1G+4I z(QWS{-mnE%hH4k8|CG3gnf@PF6=4;c|VxxK*P5Ison+CJ#I#3a;X&9-K&VU==s@V0_)c1I`AT zg}C6;!1Qgl)d=EUxgAa-NJUyt~V z7zK9s=NxbVXA=|czh{f`_v6e@x&HO831j_-fp?+*o!A?+&-ks}KwzF(*NP{AA5`O; zHCH_2sy`1pFS#&>`I9otxTrf$EZ>UIQ*q+OI52qzGBJ+2j0dQbnBC-H6(`;a?2Z%1 z%k;ZknEmT@VcP2h=6W(QPWyaW`O7ZM`mY1K
&p4@TbTU}=g?MHy!_Ll>XxyIK5 z?2Z#}an)yg?JgVy-s8g3Ol>}wt^J6%iCD!;Of228IF(Er_ls5S`DDsmoJ`*@@Oa6Y z`Q5w2al|hhw{G5|H*aX$sw23pH(iD{HoA&BGJ0n!(;iFd^3J5k@;w4gbf*wv?g%ek zzG8{!CW{Dp)zUliU0r)s1KOshY5NMS-Lj@d(-mT4N}g^@Uejb-A30z=mc%C&TE?{W z)YZuVv!0VNXN;mFm(dfL%@pG7dUDx{WnqNG_3pTCCi3Y=!|gpzlzjDSCjuOi5pfj+ zM?Cz~i-V(Q2>QEvQuVd>pN5Lp&-|wfBlj3&%q(>_GUMMVm;I0O4?Pmg-h^Y;cOAHcDvAk5savRI(d`QpyiR(_X)C zcIUFb21r$^{^^t6zWHX}yqSITW_I>HsdaXEJf3TWLtfz(9+X>3g;)t0tgsta3O`!v z#4X}x+3u)I@z(W1kgp!)$!zz5KL=g`CVjyc z;$BB8fo@Cao+U_#&${sEQLc4izpKo#NVnTU+zMF(zT3eRcY*7`pCb4l(5ErxEgv%O zXHZ`azS(KN)1`NZt6W@s-l?!x8|%PD19=5kM~E>l1c>oKs^Q{*ymEzv7%E`7>f&$# z+lAu=e6{S?WDE31V1YUd*bY6$8_6rKm9h%)LGp_0r1TeXnZ%4Ml2_Oba|L{ZtY=)2 zyrNvnm+2^wmjMboQouJ#JXXM!5|0<~a*2ITfOtif#OmP{H;K0ufMoC69bdAVqg58+ z!)yR0P)~g}tNGq2{*s?yqeJYkV!sKBT;I*$Ir!^cEKMc+ z-XB#XB-=H#tM{wG_#T%&+dpvWv;SRSwLXp!|~V?hR`1#)VCOYv9xKV+T!7K+DMCs!-HWxVVL^kETm%tdL-H3pGm|bVKbT1 zWBmhhG$;Fw-dGr@FKwobaDOb(r*8_Iu|cCdk}`}$TX?|Cqzt_;74ETXM4w?Ai9xY_ z^MH|PkEI9V;k{yeTRfRI3aC5U|47D2?bU{$nvNwCVmqqZFo0=n=nwZ9A|36A9g47g zM$EX>S!bHzNR;)xrmR?Rn060ZXg6f*_CjSm))NV&lY!MjH+sWn7>?;lr}eZMPQg`1 zqE~dZcDL&dfd*9wy1f4JMf=n!k+IAtLx^>h_8G%Ek8`@PzC^4?a81)msC^3uC zI^shT^Q#u+LM`l#~!+ zT(*`LPgzo06(grI3$JI{)03U??btazI>uwhwjV&@z;wB7-+JyMI*yz&Z?c}_tDtn< zXqI&tAb-m4ZPnCHA0lCXU*6W8U5w8!K;yvl8#iH+!+ueIa2BVh6)Lq#tdKvqwbqAn zuBtYF=m^5r3RO>?Eh&E`RMUK{{F^T*&Dr+aQckL<#}L{_Cd&_IAamN-tagDxTmGtc z;p^Jz(d^_q_PgKq4@?_seyYJ2KL*ZeCs=hotBzUw52D|wZ~xSs&->If9H^@_7dmbY z)maZ!SOc|~mN!(<+*P*kT1%_(YE{is!xffxg4TZf_k4cgH97Yac#rvdX?=#)8K=T)|^>en%f6g*d`}nGN(jzP z;Da(tn*=JgLdWIm+pio$9KmHHBj~6`wO{>5ILd+zwuTy%w3&*-IJa5J&>u+9I>>CQQy&=Hj&lFJr*KAG;S`>4p)n>y<-iJd50%{#TlGG zs0M7$4$lblHsvMTf4BUt;H3nM_AA~ei`Z)LP8qFOp)t9iI!S}sCW=8$m(15>Iv~TF{>Rk7z z_;~vX$Ns8+%RaxCNAay9(WU&>()GM2^2W^j8#m?iVBX+)-(LpF{{Y_CqL93Kb3b8O zF~-S$ z2SZ3bhSD~$(&L^WbFZ);>uHaAI+*s+EcYV!BlnLYH7@6@^!Tq#zMzyKsYf=zO0NY2 zkl$2B&_>^p_JEZh_dZ!3#j@45#o|{TJdq#{(1nF6Z0T4Lcl5~=D~>+ z0aowl!Izz98P66{32q2aLo&WOjt4h_Z$a|koaDg`U~PC z6;HYJD>3kMF3f%Qy(0W02dkXl1hBfpFemm}k^X51tDN5=@EpchIX?{tsypZRB_6O2 zar}@AbAE;kvpoas&iNfEYJbLs+5ZJ#ch2u6S3B*!3hcJ`OJH}-?=-MG=l7PYKkd)E zupjuM3)8-+&!kiJA8`j45Au={PV}yb#}dX`@nBCT7B^SK5^Du6>1i{wdv_p$tXJFC z&0F-&4c%LHBntKRCFtQcS5t3N?~5mU!f{>RiS%%0NMMM8II?=Zft9P98pQxbP{^y4 z-ka&~->U}DHnm@}uRzC^bsIHZAr7X>m&TIUFgeyozA%0Y#3z-qly2!wC-o@27e|g% zkF9E26+qTeABgB?G?Um9=oxYnku5Dwo-inrjw;WHlw%>)h>l2mx)clP+NH_QrKwq$ z{(mhYYbS;;B}HZO)HQH%?$w% Ko1k8jK>jC9xQK`V diff --git a/lib/native/linux-64/libscreencapture.so b/lib/native/linux-64/libscreencapture.so index b08a251eb0752b185f1448fae2ccb64ede54e13f..98bc46aa389d5020ac7e8533b67ac9ddebf5ac0b 100755 GIT binary patch literal 11238 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 literal 10924 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 KcJ7wBi~k9vqHzNN literal 8237 zcmd^EZH!da89ws?EFZcfE)`+b!L9~cnPr!C3k|lr><(X9U}afd!FahlbJ-c0ote(u zp^ITFIFLAAXlXS~KYnN;zginHEt7<30?1l|3v9S8eF(D~OPXAWov zXtpbLGx#;2nJy-~0fg#^TR=4+2AGo}jPF-e^uPK}y-I1f%fz*wyc-dp1!CQ+K{tWW z1!6krYN3{mMF@y0$vGYj0Wn4LCKg5r2vvj5GFFkEGG?!+aUc)4wTinP5sJ(&+xu-$2+bM|5KoaZy1moU-dPp; z-g3*|>z4nmi^-_}PRQ%}g~Y|N%Wi%*IPG0@F&X7K?z;b`qyOGx2Eqmq<@Fpnf%vVU z7eG3&e5Ar&EAT$Ie`x>fS{OVGI_u&LIQ2j2VlwJO@p1?=W*B|_nY59&&75r*!bql* zwlFq>AuBduGHRxh4_U%kwbfW>^(FJRm1|3x`Mi}EtIVyYk+y8(K}Pb)tP#uf_ZQO1 zm}zHnMzTMfLUyL#iYHB=zPz2Y%>HD$&sbyH$*opbEN5BiHZyA%a+cATGkaBv=(B7q zy;bzA&06X9WImfRw~3y%R3>kgQCFh>?t+!u79D_SKAB029wfEFfNibpH~TD+PxM0% znJK?9J0)dWZQG0`m>#!f!g9-2C8(j@lDR$Q#8k337RhHK&BCzarfs5Qdh>bJWk^cL z#qy4oOWTabNJC^{Io?=~EhzW+)gpe32}gyV%IAIq(l?E#GbbSGAjUCd$lsEjOb@oq zO`D!fV(|sUIv0l|_KW+e8i8w!tNT%xF94qiN6|zMT0|ZeVg>jlEb|U>tm{s4XkJea zC(}a?$8tY8CfFu&IH5Q>oMeI=lRiZb2bm>@9h)3ZX@DFKbUQhm9(!7OCdTM&5+E^pW(?tJ_DF)+qo*XM_f0TybVy=)=>$Kc z2PEc-ON5D^l9!j5g*ZVRlDM5XODurF%K?4VRXiUYVZz3p!xzxq&f}LMwEMI@VdN+x zJsV#g-d7HkANf9ncMcCj7Dacw$cl-=BB%HP%MIDHog(XA3f7IZBIVrF;!v_F1k zX-9G=wEJ{n^fyJ8^c9ZpktDo(zU3|3q2Ty3pU6qK1|Hc%Bb`;H?pK_Fxz37^ldVIQ z0^Om-ozu2YaiX<>XwBjygCQq+lA5+a^XQPQ_er#2Cswb#``1KK%r zZ}d%|8nh(@D*}8P-9pK(t14|rHz<`oQpM2jp+X2XqSA>pvJs-}g)vmv=^k>H&aHlS zX%PB?$Ag^IVx(FYJfph`JjirbGcL2vqFiZds8Ya*o}o+#GRLEG`V|Myj@h@X>gsB} zjj4z_&2yq>iyw~JRV?xn(xCJBQrRAk;kx$Y(POlFE)Fv_82B+KT7z1mEg|&5G$%R) zRONKPB1c{|d4|+oz55Xq)K*o~&wWG%XKAdH#!wnlty5cpjaqgg_)KMs{avH_8)HPv z)0E{ZC;AEyCY$Wj(@^3Kfa=Z_sZ6PkQ<$BD7Ye<-a!??lg+ zCM_!-4=yguEF5s6hxY~#l%j{nqKBY+ad)kKeQ|K6_}=@@;K9J);g@OuTuIw%FAg4q zr_~*#YJK8Txr6H2SE_ZdGnFe09W#wuobH3Hdd2eDj=6M*E9Tt7&niu2=O(D0IhNY^ zfKhfySnv0AjeLws>>O^y9**>26I1)UIanc_I@eV=%!Q<~P$nmth z8JwqF&R1lKCD@-he+EF@S$L-AS${tYGrk?1=d8IPp2g{d;5#x)kdC@!ScePXmtYiK zo}sS)B=GK{!zxsG1L#4}L!ie%KLh;&^aAJv=r5r6K$k#MaGsw9`WlGmfCP0dZ)^Kz zc<%Bw-SfgtIJY#08y75SZfIz@Gdwq&vvO9-GV|8F@Z5H*H)*D&OvC)fhI#)#CB+@+ zCN*BtP0D-f?MUNX;vC^z()TYwQ3vvi)A%a+2FS5|hdbvGmEm{zx_UW1M12AWwGZ znx9;_sJT9tFVx3!b~4iSc`27wPIhvGy5$OiQx*HhXKVNj6o5U;QAVawG0a46Or0f zNn8q12=`wrjZCcLLZ4yg%rus;hRO8ijEEMyX`l!jOE{z<*Jkm-Hjt%SfkO z3?@Agz0e#GeHG=n$B{w++}oH=8LnISb(uyv?ujJsg*xbH0}{BeQBLk@P_PtnVg_>3 zw?Nzn8RuR|YC)WKsY`iCAyy-fi>xfey_Cegl;s#G$368Pke1`#OX8kPIi_nl199rd z?2>+(OM&~f4%#mNzi7E8$dJ_3RFae~ed* zH59RJ6~KSl0`9y$J} zOMQynA486PLc8+cD&&S-3?}QxdOQhYdnm_$4hwJygJ?Ohex&^%Eypw063DG6ODP%3 z{mLW9v&=5YU9G*(L5}IP%l~zIAjk4L=s3@*w5tQ(bri4;bf4qEO#BFgbH=H)uP_!P0@pZ${(mjkvcznKTC?O|*8gmMRu9M{`zk z7^D3Pw5qL~g|lTgg@=)N$MbMhG@VW#6L zykHs0=0(jBya^fEm|-Uh=`E4o0bwlfSi7{f!&tj)SyyzuvA%U_N7Rt-Li#BPuR`V5 zpetXYpbPI*EiL*5Xu%ivB&MF`#-F9|dmCuK)l5 diff --git a/lib/native/mac/libscreencapture.jnilib b/lib/native/mac/libscreencapture.jnilib index b18b0b8034b2274651d2d656aeefda67b5eeaa91..eef6a1d3eff3813e2573801aaa188e2e8403adc8 100755 GIT binary patch delta 3943 zcmbVPeQ;FO6+drxlWfQ)yMX|a@UaVtMZSz~=7(7&3 zZ_~oTYh$D$JQMWRpytx{zTD&dk;Mc2g*gATu9`DTz4DM z5OQPyb8Idtc4c4AosLTIW8DV{cdCHoF+=*?aUTgO`jwg)J#%spUHG2DJDmWyL_#8zUa2$Q%EK1U3ci!X5Oa9qvFPu$E=(0P*?t&gFR&4G_;qN#nI zO;btjZ;v-szJp;HcTDq4Xnh~hP!|j;El2fd>H_khCJt)hH&oYz*hyE(-=D(pI0rk3 zU|P73Q@sFqghRyo8kf}7zkdRo_h9T&jYri#&*mcAEv$*$gJl2;}C!5h0Bb-lbcE?)$R|9QSThO&{Jf&YJ8S!3o8p*Q))RIN99(a4uG1PvLsv z;y30LnhUg448McVFsV^Io}_$H#IRN{%k=thCp|uGe2R}ZLvP(MQGcaAyT|2E@ymmg zQnSc)Ault3ygMW7VLq9dJ5A*$io&OaG2fB7HeL!`3Y-P|W56|xF#*07t0BCw_hu0d z*f`5eG#fU71Q$$nR}u~{Oi~`QFj}JZNmxz7FD2pEP0Tl(=xxhx;w=65r4#4!9$OUpj2*9PQ#loD=(ExhQ6+QdODjNaB=8`!HHu83>L5q^6Hhr@^SU+o0o5B`bqtx z8De20>f>L{>)Bs+$g`tr^H`7h zNN^ezEGF@p0SQU|U&tY+sb8zv%O4`*~3)0ZWiy zR~OxrE!kG{B%nv?Ik)IJ!BOSZAE{nguz9$z;LBYnA8Xxn>=*mGA2`Yr$wh7OTYK~( zf*sMXjGdUmJ*oPY>S;oio?Y{?kkWIdCNE76R);#Kd~wY%g4IUBC)jE4G%^a#1B4~@ z)8OLZgTZjHrdon%hilO5jW;E8NZwNiag0yoW)w3K?xMbg}F`Pqvdq>j6m zz$Nh&6pN8IvsLX+d;kkeJ~x$WAHy!wbRwjFp7^=di?~gqMMj>fo>3~=C$@d9N9+9Z zK26+Lrn>Hyz(f+LC>~P3O4MN}hp2!wAA}U^t6dUY8eA5v3o;k+Ua5anPgkhDlGfsr z+KnckO-4cQf!-1^ca)7Li0XiPwL(3U*py5|Rt#*&va=y|)o@6CJP}fxFNf5Y>)88J zN&Tl9KBX=g5Y>KBJsr{>_bq7u(%aU-E7#IO>R*k{TAcK~$#++1m-DsYQQEzgTka~V};B^eN$Y{oY z_UfnV=E^bbi&4;Sw$GU@UvHy8GusZc-DbAi(GreaE9AveWCU(uTx4OUi;FWYEHa*K z;Q(Wwg{LrfS@<^7etpCYl*!5^V4Dtaliz{Dg+rOee5+;oo^`mGRWegu%qFq4EvX$T zTV30nbD%NxeSqj(DuB&$<2c(~1lflAvF$%>+sX3xBqhq#uhkdadD&)w5nJZi*ZYF4 zpS7jiwvRH#sjNebe&gM-E|~UGZn`F1aO%>!LV1*c<{~XKy5AXXxEWfh) zouqrZe;{P)zU~=%(|U32|KMj(^7rs_PxgkY%pJ;;V=_7sTEZKkvqw>?9m1f#s(PkA zvdO=4_4!>}zI}bD?Zm_h7v4EtvjoX)%JeS<#y3V_2s8T|aPl`GzhbzuFTd;Y4H#&& z^gt96vkx4E#F)TLU5VivuxDvoQJOAonKahb*rGc3Mm^5RU0aA+x472mOhxrvG?7ek?0i2{d~Y^D0_uc1!=I2^%E z6e?*Tx^)s!G~@ETmFWg;4^Sw$ll)E z`kVG!V}?=sGR;X2B8z|0jgDMj;f==Ew)!(0M%Qu_OX&G<>z%?>zIWeWd$Rp!ytY|4#UhsDwWQo2m6bl#W}*^vV>*nh`=Uv=q=IqMP~FIxjyeW41C{>> a^V^QMhu;)F{r=!Q{nPH*|KBHV?!N%kK^!gs delta 3177 zcma)9VNg`p6+UlwfkhW~QPO}bvMXS%iY4l#V4>L+H+hRTpIZE;KBQd zLh!K=m>qDlr3hlm0A+&`n9t)|DPD?o@K2*g`QrB_n{m6bB)%qpX?Aa@O-Vpb&B@p{ zIMdYz^vNkxrmMAL)TI6O@y8lEZtfA{7X4sBN7O^kqo2Tq-elJ;dXqsgu@JUx- zeAc-tuyod$7q|g5#^7BR2Gh8g-h~6}eV@fRG(Rk;`fh`w>?ZAlc$UOWua8mpBlo}m3_AK-6 zoYDhR?AErfW6V}{=cx-R^P?^fM;LltKzxS(BTU}lrx_yJj?q0WJ6hlV9T}e1m2sOV z!=ntjGjqxIT2W4EwS8gkclnm#C}6C0tAi*&|_+guP2_GROFdzt)gX?>1ulUo?haE{F$f zhaA13myg$VExIXg1=5jE3GJrCc-pnZ7^*AHyTj>nx^ZnFYW&`@KTt@Xa19m9>9sO(*=?)qr+6pk0wWqAt{gldvl5S+ai6mF#K8 z>2B)Ie*?40?>u{rD?vm|u%2fb&yuwdlRdZa31m+H9nfyk#>N9zI69>Nm9D_48NYMY z=nOJ^n9*g0VT|E8qcbxo04Esr$vOy`27X57)CY($Z~+W6C=h-{!u^&#B+7-uaX3G? zN!BwK;{avde%=G!MV=sc*E|KDScp#6t#3lKgM!-3eCVGcbTj*3caCqP$5yvLov0^UmC)DUEPWy@pJuuB^dKqbdF{mXIAuMGR z53&g}mbp-jwjJe)8!;x!ibP*5davk9L|-QQuZsR_=n3Dr5PW+0i)0e`9>xPEz76$s zpNT(U{DO&j`_o+}=K4MzF)>%I>D+d6@CpywzA%=xZq2?QB5t>heXWI(+n8-F+t{4C z(QPRnN%3Hc`%=6;#pjY{gLAO{m(Jtu{;Yo$X5W!iiy^mHD04Yj4zFCC#I*i4x@LUY;4=#9FOg<%jpfBIk{3;J@!sz!fg z?SDkIc_Ma8|HY4zH+m$pzu-;QZ8}96O2X0~`MEnB8D1TZyth6a`TU#V=(5^ywEE#g z{v*;YwU$UZ`f>R1k<1D<4?Et+eXflWx_w43u8(BiotwKx z!3o3AnMl+fuEZwbyz<$PsItaWTT$Igbm_EJ-aDca6XKr8`j6CfQE46=Oe0hyH5eim?@aDXiD6;U@+P3T@A<$~0pu2cOwJK3{ zr06?qt9Fx3>1g)(PbNoAtMreQmCpZm{pvAKP7Dj}5xcejJic=L+Odt&GQOq%o8oz% z>rTVc_mKTYfva@Va@1nf_jwgwK;%t#3@3iCOEOR+o+uakT-EGLV#+5M_bvpllF7bNIJ~|8rmqxyD}qS|j`P>hw1U H*Np!Fx<&LF diff --git a/lib/native/windows-64/screencapture.dll b/lib/native/windows-64/screencapture.dll index 768a72464c54115e0b0595e0b4e7d6c0b31d3e2c..12d89577227cd6026a0050be49272ef8584b7228 100755 GIT binary patch literal 42212 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

6dPUv*+;KI7*b}0~-2+n(g~E+skcq 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, output) < size) { @@ -506,3 +506,43 @@ JNIEXPORT jboolean JNICALL Java_net_java_sip_communicator_impl_neomedia_imgstrea return JNI_TRUE; } +/** + * \brief JNI native method to grab desktop screen and retrieve ARGB pixels. + * \param env JVM environment + * \param clazz NativeScreenCapture Java class + * \param x x position to start capture + * \param y y position to start capture + * \param width capture width + * \param height capture height + * \param output native output buffer + * \return true if success, false otherwise + */ +JNIEXPORT jboolean JNICALL Java_net_java_sip_communicator_impl_neomedia_imgstreaming_NativeScreenCapture_grabScreen__IIIIJI + (JNIEnv* env, jclass clazz, jint x, jint y, jint width, jint height, jlong output, jint outputLength) +{ + jint size = width * height * 4; + jbyte* data = (jbyte*)output; + + /* not used */ + clazz = clazz; + env = env; + + if(!data || outputLength < size) + { + return JNI_FALSE; + } + +#if defined (_WIN32) || defined(_WIN64) + if(windows_grab_screen(data, x, y, width, height) == -1) +#elif defined(__APPLE__) + if(quartz_grab_screen(data, x, y, width, height) == -1) +#else /* Unix */ + if(x11_grab_screen(NULL, data, x, y, width, height) == -1) +#endif + { + return JNI_FALSE; + } + + return JNI_TRUE; +} + diff --git a/src/native/screencapture/net_java_sip_communicator_impl_neomedia_imgstreaming_NativeScreenCapture.h b/src/native/screencapture/net_java_sip_communicator_impl_neomedia_imgstreaming_NativeScreenCapture.h index ed9d8b1ea..d1d6581de 100644 --- a/src/native/screencapture/net_java_sip_communicator_impl_neomedia_imgstreaming_NativeScreenCapture.h +++ b/src/native/screencapture/net_java_sip_communicator_impl_neomedia_imgstreaming_NativeScreenCapture.h @@ -12,9 +12,17 @@ extern "C" { * Method: grabScreen * Signature: (IIII[B)Z */ -JNIEXPORT jboolean JNICALL Java_net_java_sip_communicator_impl_neomedia_imgstreaming_NativeScreenCapture_grabScreen +JNIEXPORT jboolean JNICALL Java_net_java_sip_communicator_impl_neomedia_imgstreaming_NativeScreenCapture_grabScreen__IIII_3B (JNIEnv *, jclass, jint, jint, jint, jint, jbyteArray); +/* + * Class: net_java_sip_communicator_impl_neomedia_imgstreaming_NativeScreenCapture + * Method: grabScreen + * Signature: (IIIIJI)Z + */ +JNIEXPORT jboolean JNICALL Java_net_java_sip_communicator_impl_neomedia_imgstreaming_NativeScreenCapture_grabScreen__IIIIJI + (JNIEnv *, jclass, jint, jint, jint, jint, jlong, jint); + #ifdef __cplusplus } #endif diff --git a/src/net/java/sip/communicator/impl/neomedia/codec/video/ByteBuffer.java b/src/net/java/sip/communicator/impl/neomedia/codec/video/ByteBuffer.java new file mode 100644 index 000000000..d5aaa7352 --- /dev/null +++ b/src/net/java/sip/communicator/impl/neomedia/codec/video/ByteBuffer.java @@ -0,0 +1,116 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.neomedia.codec.video; + +/** + * Represents a buffer of native memory with a specific size/capacity which + * either contains a specific number of bytes of valid data or is free for + * consumption. + * + * @author Lubomir Marinov + */ +public class ByteBuffer +{ + + /** + * The maximum number of bytes which can be written into the native + * memory represented by this instance. + */ + public final int capacity; + + /** + * The indicator which determines whether this instance is free to be + * written bytes into. + */ + private boolean free; + + /** + * The number of bytes of valid data that the native memory represented + * by this instance contains. + */ + private int length; + + /** + * The pointer to the native memory represented by this instance. + */ + public final long ptr; + + /** + * Initializes a new ByteBuffer instance with a specific + * capacity. + * + * @param capacity the maximum number of bytes which can be written into + * the native memory represented by the new instance + */ + public ByteBuffer(int capacity) + { + this.capacity = capacity; + this.ptr = FFmpeg.av_malloc(this.capacity); + + this.free = true; + this.length = 0; + + if (this.ptr == 0) + { + throw + new OutOfMemoryError( + getClass().getSimpleName() + + " with capacity " + + this.capacity); + } + } + + /** + * Gets the number of bytes of valid data that the native memory + * represented by this instance contains. + * + * @return the number of bytes of valid data that the native memory + * represented by this instance contains + */ + public int getLength() + { + return length; + } + + /** + * Determines whether this instance is free to be written bytes into. + * + * @return true if this instance is free to be written bytes + * into or false is the native memory represented by this + * instance is already is use + */ + public boolean isFree() + { + return free; + } + + /** + * Sets the indicator which determines whether this instance is free to + * be written bytes into. + * + * @param free true if this instance is to be made available + * for writing bytes into; otherwise, false + */ + public void setFree(boolean free) + { + this.free = free; + if (this.free) + setLength(0); + } + + /** + * Sets the number of bytes of valid data that the native memory + * represented by this instance contains. + * + * @param length the number of bytes of valid data that the native + * memory represented by this instance contains + */ + public void setLength(int length) + { + this.length = length; + } +} \ No newline at end of file diff --git a/src/net/java/sip/communicator/impl/neomedia/codec/video/SwScaler.java b/src/net/java/sip/communicator/impl/neomedia/codec/video/SwScaler.java index 2f784964b..2d481908b 100644 --- a/src/net/java/sip/communicator/impl/neomedia/codec/video/SwScaler.java +++ b/src/net/java/sip/communicator/impl/neomedia/codec/video/SwScaler.java @@ -58,6 +58,9 @@ public class SwScaler new RGBFormat(null, -1, Format.shortArray, -1.0f, 24, -1, -1, -1), }; + /** + * Libswscale context pointer. + */ private long swsContext = 0; /** diff --git a/src/net/java/sip/communicator/impl/neomedia/imgstreaming/DesktopInteract.java b/src/net/java/sip/communicator/impl/neomedia/imgstreaming/DesktopInteract.java index e45f53d40..b271c9758 100644 --- a/src/net/java/sip/communicator/impl/neomedia/imgstreaming/DesktopInteract.java +++ b/src/net/java/sip/communicator/impl/neomedia/imgstreaming/DesktopInteract.java @@ -11,7 +11,7 @@ /** * Interface to interact with the desktop such as taking * screen capture or to generate mouse/keyboard event. - * + * * @author Sebastien Vincent */ public interface DesktopInteract @@ -23,7 +23,8 @@ public interface DesktopInteract * and not BufferedImage. It is done in order to limit * slow operation such as converting ARGB images (uint32_t) to bytes * especially for big big screen. For example a 1920x1200 desktop consumes - * 9 MB of memory for grabbing and another 9 MB array for convertion operation. + * 9 MB of memory for grabbing and another 9 MB array for conversion + * operation. * * @param output output buffer to store bytes in. * Be sure that output length is sufficient @@ -31,6 +32,23 @@ public interface DesktopInteract */ public boolean captureScreen(byte output[]); + /** + * Capture the full desktop screen using native grabber. + * + * Contrary to other captureScreen method, it only returns raw bytes + * and not BufferedImage. It is done in order to limit + * slow operation such as converting ARGB images (uint32_t) to bytes + * especially for big big screen. For example a 1920x1200 desktop consumes + * 9 MB of memory for grabbing and another 9 MB array for conversion + * operation. + * + * @param buffer native output buffer to store bytes in. + * Be sure that output length is sufficient + * @param bufferLength length of native buffer + * @return true if success, false if JNI error or output length too short + */ + public boolean captureScreen(long buffer, int bufferLength); + /** * Capture a part of the desktop screen using native grabber. * @@ -38,7 +56,8 @@ public interface DesktopInteract * and not BufferedImage. It is done in order to limit * slow operation such as converting ARGB images (uint32_t) to bytes * especially for big big screen. For example a 1920x1200 desktop consumes - * 9 MB of memory for grabbing and another 9 MB array for convertion operation. + * 9 MB of memory for grabbing and another 9 MB array for conversion + * operation. * * @param x x position to start capture * @param y y position to start capture @@ -48,7 +67,30 @@ public interface DesktopInteract * Be sure that output length is sufficient * @return true if success, false if JNI error or output length too short */ - public boolean captureScreen(int x, int y, int width, int height, byte output[]); + public boolean captureScreen(int x, int y, int width, int height, + byte output[]); + + /** + * Capture a part of the desktop screen using native grabber. + * + * Contrary to other captureScreen method, it only returns raw bytes + * and not BufferedImage. It is done in order to limit + * slow operation such as converting ARGB images (uint32_t) to bytes + * especially for big big screen. For example a 1920x1200 desktop consumes + * 9 MB of memory for grabbing and another 9 MB array for conversion + * operation. + * + * @param x x position to start capture + * @param y y position to start capture + * @param width capture width + * @param height capture height + * @param buffer native output buffer to store bytes in. + * Be sure that output length is sufficient + * @param bufferLength length of native buffer + * @return true if success, false if JNI error or output length too short + */ + public boolean captureScreen(int x, int y, int width, int height, + long buffer, int bufferLength); /** * Capture the full desktop screen. diff --git a/src/net/java/sip/communicator/impl/neomedia/imgstreaming/DesktopInteractImpl.java b/src/net/java/sip/communicator/impl/neomedia/imgstreaming/DesktopInteractImpl.java index 704c1b870..d64ec5f4a 100644 --- a/src/net/java/sip/communicator/impl/neomedia/imgstreaming/DesktopInteractImpl.java +++ b/src/net/java/sip/communicator/impl/neomedia/imgstreaming/DesktopInteractImpl.java @@ -12,19 +12,20 @@ import net.java.sip.communicator.util.*; /** - * This singleton class provide screen capture and key/mouse + * This singleton class provide screen capture and key/mouse * events generation by wrapping partial or all java.awt.Robot * methods to interact with desktop. * * @see java.awt.Robot * @author Sebastien Vincent */ -public class DesktopInteractImpl implements DesktopInteract +public class DesktopInteractImpl implements DesktopInteract { /** * The Logger. */ - private static final Logger logger = Logger.getLogger(DesktopInteractImpl.class); + private static final Logger logger = + Logger.getLogger(DesktopInteractImpl.class); /** * Screen capture robot. @@ -33,11 +34,12 @@ public class DesktopInteractImpl implements DesktopInteract /** * Constructor. - * - * @throws AWTException if platform configuration does not allow low-level input control + * + * @throws AWTException if platform configuration does not allow low-level + * input control * @throws SecurityException if Robot creation is not permitted */ - public DesktopInteractImpl() throws AWTException, SecurityException + public DesktopInteractImpl() throws AWTException, SecurityException { robot = new Robot(); } @@ -49,7 +51,8 @@ public DesktopInteractImpl() throws AWTException, SecurityException * and not BufferedImage. It is done in order to limit * slow operation such as converting ARGB images (uint32_t) to bytes * especially for big big screen. For example a 1920x1200 desktop consumes - * 9 MB of memory for grabbing and another 9 MB array for convertion operation. + * 9 MB of memory for grabbing and another 9 MB array for conversion + * operation. * * @param output output buffer to store bytes in. * Be sure that output length is sufficient @@ -59,7 +62,29 @@ public boolean captureScreen(byte output[]) { Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); - return captureScreen(0, 0, (int)dim.getWidth(), (int)dim.getHeight(), output); + return captureScreen(0, 0, dim.width, dim.height, + output); + } + + /** + * Capture the full desktop screen using native grabber. + * + * Contrary to other captureScreen method, it only returns raw bytes + * and not BufferedImage. It is done in order to limit + * slow operation such as converting ARGB images (uint32_t) to bytes + * especially for big big screen. For example a 1920x1200 desktop consumes + * 9 MB of memory for grabbing and another 9 MB array for conversion + * operation. + * + * @param buffer native output buffer to store bytes in. + * Be sure that output length is sufficient + * @param bufferLength length of native buffer + * @return true if success, false if JNI error or output length too short + */ + public boolean captureScreen(long buffer, int bufferLength) + { + Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); + return captureScreen(0, 0, dim.width, dim.height, buffer, bufferLength); } /** @@ -67,9 +92,10 @@ public boolean captureScreen(byte output[]) * * Contrary to other captureScreen method, it only returns raw bytes * and not BufferedImage. It is done in order to limit - * slow operation such as converting ARGB images (uint32_t) to bytes + * slow operation such as converting ARGB images (uint32_t) to bytes * especially for big big screen. For example a 1920x1200 desktop consumes - * 9 MB of memory for grabbing and another 9 MB array for convertion operation. + * 9 MB of memory for grabbing and another 9 MB array for conversion + * operation. * * @param x x position to start capture * @param y y position to start capture @@ -79,7 +105,8 @@ public boolean captureScreen(byte output[]) * Be sure that output length is sufficient * @return true if success, false if JNI error or output length too short */ - public boolean captureScreen(int x, int y, int width, int height, byte output[]) + public boolean captureScreen(int x, int y, int width, int height, + byte output[]) { if(OSUtils.IS_LINUX || OSUtils.IS_FREEBSD || OSUtils.IS_WINDOWS || OSUtils.IS_MAC) @@ -91,6 +118,38 @@ public boolean captureScreen(int x, int y, int width, int height, byte output[]) return false; } + /** + * Capture a part of the desktop screen using native grabber. + * + * Contrary to other captureScreen method, it only returns raw bytes + * and not BufferedImage. It is done in order to limit + * slow operation such as converting ARGB images (uint32_t) to bytes + * especially for big big screen. For example a 1920x1200 desktop consumes + * 9 MB of memory for grabbing and another 9 MB array for conversion + * operation. + * + * @param x x position to start capture + * @param y y position to start capture + * @param width capture width + * @param height capture height + * @param buffer native output buffer to store bytes in. + * Be sure that output length is sufficient + * @param bufferLength length of native buffer + * @return true if success, false if JNI error or output length too short + */ + public boolean captureScreen(int x, int y, int width, int height, + long buffer, int bufferLength) + { + if(OSUtils.IS_LINUX || OSUtils.IS_FREEBSD || OSUtils.IS_WINDOWS + || OSUtils.IS_MAC) + { + return NativeScreenCapture.grabScreen( + x, y, width, height, buffer, bufferLength); + } + + return false; + } + /** * Capture the full desktop screen using java.awt.Robot. * @@ -100,7 +159,7 @@ public BufferedImage captureScreen() { Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); - return captureScreen(0, 0, (int)dim.getWidth(), (int)dim.getHeight()); + return captureScreen(0, 0, dim.width, dim.height); } /** @@ -117,7 +176,7 @@ public BufferedImage captureScreen(int x, int y, int width, int height) { BufferedImage img = null; Rectangle rect = null; - + if(robot == null) { /* Robot has not been created so abort */ @@ -128,7 +187,7 @@ public BufferedImage captureScreen(int x, int y, int width, int height) rect = new Rectangle(x, y, width, height); img = robot.createScreenCapture(rect); logger.info("End capture: " + System.nanoTime()); - + return img; } diff --git a/src/net/java/sip/communicator/impl/neomedia/imgstreaming/NativeScreenCapture.java b/src/net/java/sip/communicator/impl/neomedia/imgstreaming/NativeScreenCapture.java index 82568e26b..895600cf1 100644 --- a/src/net/java/sip/communicator/impl/neomedia/imgstreaming/NativeScreenCapture.java +++ b/src/net/java/sip/communicator/impl/neomedia/imgstreaming/NativeScreenCapture.java @@ -6,12 +6,10 @@ */ package net.java.sip.communicator.impl.neomedia.imgstreaming; -import java.awt.image.*; - /** * This class uses native code to capture desktop screen. - * - * It should work for Windows, Mac OS X and X11-based Unix such as Linux + * + * It should work for Windows, Mac OS X and X11-based Unix such as Linux * and FreeBSD. * * @author Sebastien Vincent @@ -25,7 +23,7 @@ public class NativeScreenCapture /** * Grab desktop screen and get raw bytes. - * + * * @param x x position to start capture * @param y y position to start capture * @param width capture width @@ -33,5 +31,20 @@ public class NativeScreenCapture * @param output output buffer to store screen bytes * @return true if grab success, false otherwise */ - public static native boolean grabScreen(int x, int y, int width, int height, byte output[]); + public static native boolean grabScreen(int x, int y, int width, int height, + byte output[]); + + /** + * Grab desktop screen and get raw bytes. + * + * @param x x position to start capture + * @param y y position to start capture + * @param width capture width + * @param height capture height + * @param output native output buffer to store screen bytes + * @param outputLength native output length + * @return true if grab success, false otherwise + */ + public static native boolean grabScreen(int x, int y, int width, int height, + long output, int outputLength); } diff --git a/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/imgstreaming/DataSource.java b/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/imgstreaming/DataSource.java index cbdece5d9..2de47a571 100644 --- a/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/imgstreaming/DataSource.java +++ b/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/imgstreaming/DataSource.java @@ -12,10 +12,11 @@ import javax.media.control.*; import javax.media.format.*; +import net.java.sip.communicator.impl.neomedia.codec.video.*; import net.java.sip.communicator.impl.neomedia.jmfext.media.protocol.*; /** - * DataSource for our image streaming (which is used for + * DataSource for our image streaming (which is used for * Desktop streaming). * * @author Sebastien Vincent @@ -32,7 +33,11 @@ public class DataSource private static final Format[] formats = new Format[] { - new RGBFormat( + new AVFrameFormat( + Toolkit.getDefaultToolkit().getScreenSize(), + Format.NOT_SPECIFIED, + FFmpeg.PIX_FMT_ARGB), + new RGBFormat( Toolkit.getDefaultToolkit().getScreenSize(), // size Format.NOT_SPECIFIED, // maxDataLength Format.byteArray, // dataType diff --git a/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/imgstreaming/ImageStream.java b/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/imgstreaming/ImageStream.java index 29281d118..88c215f09 100644 --- a/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/imgstreaming/ImageStream.java +++ b/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/imgstreaming/ImageStream.java @@ -14,14 +14,13 @@ import javax.media.control.*; import javax.media.format.*; +import net.java.sip.communicator.impl.neomedia.codec.video.*; import net.java.sip.communicator.impl.neomedia.imgstreaming.*; import net.java.sip.communicator.impl.neomedia.jmfext.media.protocol.*; import net.java.sip.communicator.util.*; /** * The stream used by JMF for our image streaming. - * - * This class launches a thread to handle desktop capture interactions. * * @author Sebastien Vincent * @author Lubomir Marinov @@ -45,6 +44,11 @@ public class ImageStream */ private DesktopInteract desktopInteract = null; + /** + * Native buffer pointer. + */ + ByteBuffer data = null; + /** * Initializes a new ImageStream instance which is to have a * specific FormatControl @@ -67,41 +71,80 @@ public void read(Buffer buffer) throws IOException { //System.out.println(System.currentTimeMillis()); - byte data[] = (byte[])buffer.getData(); - int dataLength = (data != null) ? data.length : 0; long begin = System.currentTimeMillis(); /* maximum time allowed for a capture to respect frame rate */ - long maxTime = 1000 / 10; + long maxTime = 1000 / 10; int wait = 0; - if((data != null) || (dataLength != 0)) + if(buffer.getFormat() instanceof AVFrameFormat) { - byte buf[] = readScreen(data); + /* native transfert: we keep data in native memory rather + * than Java Heap until we reach SwScaler + */ + Object dataAv = buffer.getData(); + AVFrame bufferFrame = null; + long bufferFramePtr = 0; - if(buf != data) + if (dataAv instanceof AVFrame) { - /* readScreen returns us a different buffer than JMF ones, - * it means that JMF's initial buffer was too short. - */ - //System.out.println("use our own buffer"); - buffer.setData(buf); + bufferFrame = (AVFrame)dataAv; + bufferFramePtr = bufferFrame.getPtr(); + } + else + { + bufferFrame = new FinalizableAVFrame(); + bufferFramePtr = bufferFrame.getPtr(); } - buffer.setOffset(0); - buffer.setLength(buf.length); - buffer.setFormat(getFormat()); - buffer.setHeader(null); - buffer.setTimeStamp(System.nanoTime()); - buffer.setSequenceNumber(seqNo); - buffer.setFlags(Buffer.FLAG_SYSTEM_TIME | Buffer.FLAG_LIVE_DATA); - seqNo++; + AVFrameFormat bufferFrameFormat = (AVFrameFormat)buffer.getFormat(); + Dimension bufferFrameSize = bufferFrameFormat.getSize(); + + if(readScreenNative(bufferFrameSize)) + { + FFmpeg.avpicture_fill( + bufferFramePtr, + data.ptr, + bufferFrameFormat.getPixFmt(), + bufferFrameSize.width, bufferFrameSize.height); + } + + buffer.setData(bufferFrame); } - + else + { + byte dataByte[] = (byte[])buffer.getData(); + int dataLength = (dataByte != null) ? dataByte.length : 0; + + if((dataByte != null) || (dataLength != 0)) + { + byte buf[] = readScreen(dataByte); + + if(buf != dataByte) + { + /* readScreen returns us a different buffer than JMF ones, + * it means that JMF's initial buffer was too short. + */ + //System.out.println("use our own buffer"); + buffer.setData(buf); + } + + buffer.setOffset(0); + buffer.setLength(buf.length); + } + } + + buffer.setFormat(buffer.getFormat()); + buffer.setHeader(null); + buffer.setTimeStamp(System.nanoTime()); + buffer.setSequenceNumber(seqNo); + buffer.setFlags(Buffer.FLAG_SYSTEM_TIME | Buffer.FLAG_LIVE_DATA); + seqNo++; + wait = (int)(maxTime - (System.currentTimeMillis() - begin)); try { - /* sleep to respect as much as possible the + /* sleep to respect as much as possible the * frame rate */ if(wait > 0) @@ -110,7 +153,7 @@ public void read(Buffer buffer) } else { - /* yield a little bit to not use all the + /* yield a little bit to not use all the * CPU */ Thread.yield(); @@ -151,14 +194,54 @@ public void start() public void stop() { logger.info("Stop stream"); + + /* native pointer is freed in FinalizableAVFrame */ + data = null; + } + + /** + * Read screen and store result in native buffer. + * + * @param dim dimension of the video + * @return true if success, false otherwise + */ + private boolean readScreenNative(Dimension dim) + { + int size = dim.width * dim.height * 4; + + /* pad the buffer */ + size += FFmpeg.FF_INPUT_BUFFER_PADDING_SIZE; + + /* allocate native array */ + if(data == null) + { + data = new ByteBuffer(size); + data.setLength(size); + } + + /* reallocate native array if capacity is not enough */ + if(data.getLength() < size) + { + data.setFree(true); + FFmpeg.av_free(data.ptr); + data = new ByteBuffer(size); + data.setLength(size); + } + + /* get desktop screen via native grabber */ + if(desktopInteract.captureScreen(data.ptr, data.getLength())) + { + return true; + } + return false; } /** * Read screen. - * + * * @param output output buffer for screen bytes - * @return raw bytes, it could be equal to output or not. Take care in the caller - * to check if output is the returned value. + * @return raw bytes, it could be equal to output or not. Take care in the + * caller to check if output is the returned value. */ public byte[] readScreen(byte output[]) { @@ -194,8 +277,8 @@ public byte[] readScreen(byte output[]) * Note that it is very memory consuming since memory are allocated * to capture screen (via Robot) and then for converting to raw bytes * - * Normally not of our supported platform (Windows (x86, x64), - * Linux (x86, x86-64), Mac OS X (i386, x86-64, ppc) and + * Normally not of our supported platform (Windows (x86, x64), + * Linux (x86, x86-64), Mac OS X (i386, x86-64, ppc) and * FreeBSD (x86, x86-64) should go here. */ screen = desktopInteract.captureScreen(); @@ -203,7 +286,7 @@ public byte[] readScreen(byte output[]) if(screen != null) { /* convert to ARGB BufferedImage */ - scaledScreen + scaledScreen = ImageStreamingUtils .getScaledImage( screen, @@ -219,4 +302,61 @@ public byte[] readScreen(byte output[]) scaledScreen = null; return data; } + + /** + * Represents an AVFrame used by this instance to provide captured + * media data in native format without representing the very frame data in + * the Java heap. Since this instance cannot know when the AVFrame + * instances are really safe for deallocation, FinalizableAVFrame + * relies on the Java finalization mechanism to reclaim the represented + * native memory. + */ + public class FinalizableAVFrame + extends AVFrame + { + + /** + * The indicator which determines whether the native memory represented + * by this instance has already been freed/deallocated. + */ + private boolean freed = false; + + /** + * Initializes a new FinalizableAVFrame instance which is to + * allocate a new native FFmpeg AVFrame and represent it. + */ + public FinalizableAVFrame() + { + super(FFmpeg.avcodec_alloc_frame()); + } + + /** + * Deallocates the native memory represented by this instance. + * + * @see Object#finalize() + */ + @Override + protected void finalize() + throws Throwable + { + try + { + if (!freed) + { + long ptr = getPtr(); + long bufferPtr = FFmpeg.avpicture_get_data0(ptr); + + if(bufferPtr != 0) + FFmpeg.av_free(bufferPtr); + + FFmpeg.av_free(ptr); + freed = true; + } + } + finally + { + super.finalize(); + } + } + } } diff --git a/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/quicktime/QuickTimeStream.java b/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/quicktime/QuickTimeStream.java index 89da1d641..781f996eb 100644 --- a/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/quicktime/QuickTimeStream.java +++ b/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/quicktime/QuickTimeStream.java @@ -694,7 +694,7 @@ private void runInTransferDataThread() nextData = null; } } - + synchronized (dataSyncRoot) { if (data == null) @@ -879,119 +879,12 @@ public void stop() } } - /** - * Represents a buffer of native memory with a specific size/capacity which - * either contains a specific number of bytes of valid data or is free for - * consumption. - */ - private static class ByteBuffer - { - - /** - * The maximum number of bytes which can be written into the native - * memory represented by this instance. - */ - public final int capacity; - - /** - * The indicator which determines whether this instance is free to be - * written bytes into. - */ - private boolean free; - - /** - * The number of bytes of valid data that the native memory represented - * by this instance contains. - */ - private int length; - - /** - * The pointer to the native memory represented by this instance. - */ - public final long ptr; - - /** - * Initializes a new ByteBuffer instance with a specific - * capacity. - * - * @param capacity the maximum number of bytes which can be written into - * the native memory represented by the new instance - */ - public ByteBuffer(int capacity) - { - this.capacity = capacity; - this.ptr = FFmpeg.av_malloc(this.capacity); - - this.free = true; - this.length = 0; - - if (this.ptr == 0) - { - throw - new OutOfMemoryError( - getClass().getSimpleName() - + " with capacity " - + this.capacity); - } - } - - /** - * Gets the number of bytes of valid data that the native memory - * represented by this instance contains. - * - * @return the number of bytes of valid data that the native memory - * represented by this instance contains - */ - public int getLength() - { - return length; - } - - /** - * Determines whether this instance is free to be written bytes into. - * - * @return true if this instance is free to be written bytes - * into or false is the native memory represented by this - * instance is already is use - */ - public boolean isFree() - { - return free; - } - - /** - * Sets the indicator which determines whether this instance is free to - * be written bytes into. - * - * @param free true if this instance is to be made available - * for writing bytes into; otherwise, false - */ - public void setFree(boolean free) - { - this.free = free; - if (this.free) - setLength(0); - } - - /** - * Sets the number of bytes of valid data that the native memory - * represented by this instance contains. - * - * @param length the number of bytes of valid data that the native - * memory represented by this instance contains - */ - public void setLength(int length) - { - this.length = length; - } - } - /** * Represents an AVFrame used by this instance to provide captured * media data in native format without representing the very frame data in * the Java heap. Since this instance cannot know when the AVFrame * instances are really safe for deallocation, FinalizableAVFrame - * relies on the Java finialization mechanism to reclaim the represented + * relies on the Java finalization mechanism to reclaim the represented * native memory. */ private class FinalizableAVFrame