From aaac6a4fbb6b806c4b962d8c54dd0a28c1ca03a3 Mon Sep 17 00:00:00 2001 From: Chris Gerth Date: Sun, 30 Oct 2022 13:16:17 -0500 Subject: [PATCH] Add Websocket Camera Streaming (#529) * WIP adding second websocket handling for cameras * just more WIP * even more wip. Most java-side framework completed, but not yet debugged * IT LIVES. Still needs lots of cleanup. But we're transferring and displaying data! * moved down an architecture layer. Improved multiple-camera handling * Additional WIP to help improve smoothness and performance, though not yet tested * bugfixes galore * tweak compression * spotless * more tweaks for handling slow/intermittent streams * wpilibformat maybe? * clang-format maybe? * WIP - adding thinclient. I don't like it yet, it should be more auto-generated than it is. * thinclient formatting fixups * Reduced amount of empty send data by limiting to only one stream per client (which is all we really need). Framerate is up slightly, overhead is down. * bugfixes, faster streaming, better mjpeg compression settings, thinclient working * spotless and formatting * cmon wpiformat.... * re-added mjpg streams * added a loading GIF to imporve the feeling of responsiveness * formatting * urlparams and built-in thinclient * wpiformat * prevent wpiformat complaints * Removed uint8 array and base64 conversion from client side * Synced up js implementations for ws streaming * formatting/spotless --- .styleguide | 1 + photon-client/src/assets/loading.gif | Bin 0 -> 12411 bytes photon-client/src/assets/noStream.jpg | Bin 49594 -> 77293 bytes .../src/components/common/cv-image.vue | 46 +++- photon-client/src/main.js | 4 +- photon-client/src/plugins/ColorPicker.js | 2 +- .../src/plugins/WebsocketVideoStream.js | 148 ++++++++++++ photon-client/src/store/index.js | 4 +- photon-client/src/views/CamerasView.vue | 3 +- photon-client/src/views/PipelineView.vue | 8 +- .../common/configuration/ConfigManager.java | 2 +- .../vision/processes/VisionModule.java | 91 +++---- .../vision/videoStream/SocketVideoStream.java | 116 +++++++++ .../videoStream/SocketVideoStreamManager.java | 97 ++++++++ photon-server/build.gradle | 7 + .../server/CameraSocketHandler.java | 140 +++++++++++ .../server/CameraSocketMessageType.java | 46 ++++ ...ketHandler.java => DataSocketHandler.java} | 27 +-- ...geType.java => DataSocketMessageType.java} | 10 +- .../java/org/photonvision/server/Server.java | 23 +- .../server/UIOutboundSubscriber.java | 4 +- photon-thinclient/loading.gif | Bin 0 -> 12411 bytes photon-thinclient/thinclient.html | 223 ++++++++++++++++++ 23 files changed, 890 insertions(+), 112 deletions(-) create mode 100644 photon-client/src/assets/loading.gif create mode 100644 photon-client/src/plugins/WebsocketVideoStream.js create mode 100644 photon-core/src/main/java/org/photonvision/vision/videoStream/SocketVideoStream.java create mode 100644 photon-core/src/main/java/org/photonvision/vision/videoStream/SocketVideoStreamManager.java create mode 100644 photon-server/src/main/java/org/photonvision/server/CameraSocketHandler.java create mode 100644 photon-server/src/main/java/org/photonvision/server/CameraSocketMessageType.java rename photon-server/src/main/java/org/photonvision/server/{SocketHandler.java => DataSocketHandler.java} (94%) rename photon-server/src/main/java/org/photonvision/server/{SocketMessageType.java => DataSocketMessageType.java} (84%) create mode 100644 photon-thinclient/loading.gif create mode 100644 photon-thinclient/thinclient.html diff --git a/.styleguide b/.styleguide index 72a1cf0e9..cf50b8839 100644 --- a/.styleguide +++ b/.styleguide @@ -13,6 +13,7 @@ modifiableFileExclude { \.jpg$ \.jpeg$ \.png$ + \.gif$ \.so$ \.dll$ } diff --git a/photon-client/src/assets/loading.gif b/photon-client/src/assets/loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..2dc1e701a76d44dbb91553f54a7f2fccd693b0ac GIT binary patch literal 12411 zcmeI2Wm{W&yX`};1P!i*;7%zNEwllOOY!0acZwG&EfU<_C1`MW3-0a(THI-&N}(-> zwVt(}^Q?XL-k;#iw{u?e#k~Gwj(d#Xt)L_?CT^||%)$5$0Mrb;X&Urz8}eD7F?m00 z^l|ao&5Hc(s_gCR(=SUZSIdf9Glu(fdZ!CoJF^DU6ShNRF5}}4i&K`X)A0UL*XLEe zFPqBzn~OafD=lkV%xl_g>l#(dM_{G1c|FmQ?O8D$8OdGANu4Q0=ubPX!now?yRq&d2r}{ea;-#FPn8rc>sR_H$F{kAz z^My$(R3E~mx^sTgDzz(VX2N!9$`U=|p5Ggl)g9;BP-R)uYE|1}U*8bbo>_tp%k7DY zXwNS13sFLijg31bbf(64q$PHy#CBwe7B8!p4{KNUr*kgMOLaafQ7Ril}kTiowSvbB{_EO{+UXTl0EH-A!vc3egcy%cf%5GenD) zWy_|eOJ|ZhlQX&#O8XExm3=CxQ3ce5eO-e_#b8oba%@L>U@Nk`KiIvoGPpHAt|KkC zCpx|}Eu%YLw-O!Ro)gxVlh&1x(Unlp8(EAFlPF$H>P!xA&kk?PPU%YO8upYaoq^Z1 znN)YkmQ6V~)Wme8BYPv_J5$U1g44U>QGFq5<-=N){qkiKqD3oZeIfSs^?AKfA+324 z?O7`2BgtJ!A#Hhp|9}1S3ozZ{tIO$V%Svm=3GxeIV%*(j`pxys)zjYD-p|?!`qJLh z4r=G=>FObI|Gu@Kt-TGuYzHlg-TF7Bzw7zI09x59}uhdXHmdvSLVLaAQGLbG|Ii91`SUQz0 z=5ewy)>t-^4-3J&r`&{^D^g76HW_a!UntWkQqEOwu2`znZ*vK?knD^@2@nL=-4);+3g3{p#8Npt0R2U<2a#WNc&wX5+qUUg2 zf@@WAT$pi#$tyR zd;kz~!d+}IQ(z%9l#42|;4@l*4?Q2l{AGzbbkG=N<^->R^rB4@ANzk<&;@}WG(Eti zBY#dG0%B*K6|fRxt(V1(K=3wvwFW_UIgQ2~(=d ztKay!bMpX(#elMTRa~^?^V|LDf_M%*IN?N;U5*<-XYR6x(&{1BpR5(sCP_~8g8|Mhv~ z%leK|z867$GxxDHK9?#ko?f3zU_E|x-g~gs2eI4Y_XBZ|Jq#LwmOYl91)30df0=uO z{Qhb3=H%!1ttXmNr#-hlV3L!Cb19NzmPx4}`|A>KevN-78rk-=W2CTx_ud?aR?Ws^3r+E5Jl*NuF z13a`)QjiScd^LhSW~n!(HE2eBn}GFI0okqTtOVmQf4G@%Anp_NAQ(sU%?W8AUTH)- z#||X2oEeSJG8;@yIuZIwh7PwjLQXKNKE_s+g?4FF-W9|7Ww3t{#rhRLA07Zer?Zal z2tb_2CdRo;_J6*H4zUn9hx8S+F0sF?C;AA~5s-iDB86!9UOM=o^< zO&$1qh8hr%@EZ3RuCzf^LqXzO zTUMGCG@JXUa90FpF>4lxv?)0$vW-*z7NseNfe{4OJ<_DDA4}nHDvrG_hT)!!kOIl^ zgsh>ej9xQYJ9TB98}_R2edP=BgmV?-9JEq9bV@~*%AbWg=#)t4R_HBNJRfq){5Sr?R?NkVz#SZ@jMcrHnnUmlf3;~r(L%!Nt{W3I|_><9fn2acY^5x* zg8+WNluPBOsD**)hQ@}Il69F#lVg{~rrNV5X`$0i-68i{#!H|N+40h+lg5q>FGc5) zVXg7EOWh8+$L4cym+C+1hFuF|y}9I>X)~p20k_#JfVnI7^e%g_^iCbn@G?o^ zE{L*9)5Lj?Ht0KnI*FX|qbMKCnC1_!g4|7i`QQhZy{$pHk*gdUza-Z+zj|o$p#*6{U z1Ht6ANxR1$Sxa39BAq`Pr(EM2a}HGxCDwmT``jIi?~{j*Z+^@K5;YazsvXJDUC&0S zHx*J%9mzkso=b>pD&|l-RyMkx&zNp16`eX(_rG2!AZkV_sGVqKUoWE6n=77Ao#=I5 zFV)30SJ|qa8m?b2w@o+Kyqr2Uy}4dN6SdTZtDRZU-K>tPw=|?ro!LCPS(}Y(X)04Y zcQCqnyE@&{(mHkS;(xQgMbz3hqV~Z(`)1=vy|rUy>VtQukst=fA3lx^0z3ooVqg>i zo&!t)fA~1@|Lo(00@PbYyYg5xvQdMYKyYj_+iUV!&IUF)GU>LQI%Z27Dl#yvW8>IW zh8CaBqJV_^Z6ZNiC6Qn-yn5x3h`_JZox`Eo z@`Nf-cyUK$k{)pbTAasZ9!9323{$ZKED8$Qu`>spQD^`QvfQ-HvUONI``i7AAb<_? zyBN+GihGG;B3!i zWUA97#@!Ze46UJ|M8ahhqPZ|=MLs+pkuKVWnCxsTY<)X z|4;LivUnHWg5X6_i zIIRro&V3l;;-$h2Y3LUZXOH*zzJHSo`ZU|?+gu$Gj4gOyr z_dQHH`GuIz1|4zT`8cUEvyJQM!(?yPEjAQks62Oh9&J#$9M0=G&)r;U$)J(qf-ni& zlKZNuCTb=7Yx$@u<#8maH}_V8PTNy!_M|$Q(lv~UBjf_4MP5u#?c^8Sl@_Gv6~R-?1SUu_#uyut>Xy$O@Zin`^C6Hc`Oq; z2+LV1&E6&~{DjWB3xLaefySb8y66LOR9*BF(2Z*i90*eEbwYN>ksh|iC-y`AM4(YN z2E`>ZP2>386fEG8?%d_pJu#? z;7usLv-U3w8VY=07j>RHe_hhIt^T?U6rK9I;^XJ`aM3o8>bOETz3V~i1G?bm8HD`d zz>;f7tRuaaLf}I}@9?La-`@w~@?UKs{PFF#6*(k7wi=At_P+9+0(* zu(}7&z;fu|0#-FF{eI!#kSyH1sC(;8eRp$hY8A>)mk9zhHnoeS3p^OFv-*7E74?Ig$ZxeF!w_W$kW>S%Cp{dr zU+_2r=wky?^N-vdE_)WfWi-2c(3fwYE`B+LJGxO3|2x#(yO629U-o;Q8@;b7O!2;O z`l^Af=bU7P(QR)W?q~fEzC>?o=P18l)%(3;Ij>}h^(3p^oOu5%?X@`zbp)Kk66ewu z`r_p#dda=me1A&~@~spO7TpM2Qc>G#r4AzT&d3j8>rTwGRnoZ14(B9#Dore)lK>{8 zk1#i*9cFUfid6tN7t-HT+}6PIwR9I3luI?O4q!2Xc( z8FiU${%asNDmS#H+}1bv0&!$&?I5j?8v+#1Ei!%mfUCqNsvec*=#9mwlmG1y0G5Mi z9^;#o-a2gM+Y%X$B#JpXe*Zruv2tZswMv-UZ6sAs~RnBgMun&auWPA@qYvooHH4Eq-VNn^GQJd;d{ zH*`#oRBRgE0!HM(vY9EleWj^j`EI;Z_=*y->=|{h%;NT@->P6>y*urTpQM2lmX0Y9 zHtlxwAS0&g0$Q-SDt!<>2za|3MQ(E{sD~Lki+as zHE5`bt!$EyE_t}P%&E-xZPhB>`P-UZS+)0?6l43hb!|opw57l4GA0{2RLvU;|6OqI zkf{nf*3kR0*thg8d5pvr!pGUw1LN+eVc#}(#UHf2HNTer{>t{050DxW&VPMWobJ-` zR&)0#YZ#!qcD)Z7(YcD1_=)l3*hPldJ;QQX#Pv)*O+)Z~+Iw|>L!491!lAwP$`ug2 zj>u;?Wyhuaa^+Cn{hRVJ>jGdyD7Cfb-+l+b%dHrtcW$TuPg&ych-nvXBY-%hf8|y% z&O^`s2WVL=>bu-(pV&_YVbpq!L_?X!(gl?Kwo&tu03g5R3H=(tLLI?pQ==iX$UdE` zs3OAE=LrKQkg73obu@6uF~S-oe6l>PSXenaH}0PWfTJH3pF#;|m<_u=QY=+I|5JwF5Flmqa;jz>ho+qac8W61nYv%Y@SMA;(+9 zvSm&4ktU?~_R%8y)l8j8WcZNNG6>oJGA9lq`2Z1*aUi{$;N-lN9mkai#|qN)5v58| z`lV+LQ4NaNS68Qbxu5=5ZZ$a2tK&*9%Gz@F%u7;<1KYl))Hq{VqR`)VtYcF@mJ=m#m9Qer5 zw*DPnMa_u1V|Xpjg%>Siw&moUAlhNP+&n*z=A>pc%aA2HSYE=u%hiq+Re-r~ctlb6 zsr7zuNLs6H{(V;S;1(>QBcSh|NENvrelySI5VdX9gJinKm$^gtL<`vH$%r;s2lRnV zTm(sqKNNDw8lkN9^i1MxuaR!UnPpYqs9D0KK+j2tKbiB`j59l3d=7z9X%r*sQfavH zRJ4E5j_`Xwpmoq9*8Q3d4RZvEOcojUi&`2*G*d zy7V)5ze<-FU5M0%;)~H=2XM@xXUre2cH?kMd=>=k2gNoAV|nYmSP4Xgyh8lteHD@M zl)^`5k-4H7s?t*}Ufe|cya!DjH9{+>l>?^pnTFi!5A6$x`Gd+IUc++~cpq^)*Q5fL zH!i!qC_iyo4126QU(R+~`w(WgxsD0PRcfGR^O`@wvhJrI)mrlMtJzk*r~0ypjrEs> zs{Uc2r2sR4!Jk^q{ChSf{0)s@`ENTWGMd0YI;PPCwns#YTpGA4@#Ok(fXn%v%q$}0 z)~ll}Xml5 zOB46wa{t$kDX)9G>jhFF-A)or$jY|$KJVF+Z`cHYERr>kpI=|<5(!z?4Fub9ia~)H z6h{ef2=vfUsvpN}OwVvj-DC(T_4J3qSI0{WVW7m8pa=@~#E`qTX>~h_m;b0R>;XeD zGl?*frUgRWaLJrO-VVN($Yay?9`;~pH5;1~YA}dx{}W&-%^|L|4Y`lHD0n4}r^Co% z)?#b(Lab?v5@Fjic98AzcgN)8vdhsm(P41%z?(0v)UOg^wb}f$pRs` zSS)os1qMno)Xn7}&d9w*YwVxa3V4}mQPPAiN>Td&X}cOq_1r@i5omq||m& zaVF`KH`GkCUX$o=njDtk37C+p3}$~m7+uk^(w|yga-er(iF}s|2_;~1hYh8$>VrA@ zETt4y$oOH$)L4!(^lp?RN*8MbgnRbE19*F*?AQ!=AOi>Z`Cy10>ks^XhKKB#F3)?y z3_%2uA|U2Sme2U9gwQp*k`zgipU#@1-Fq(SilTOW3m!q%pheB^8rjM84tk9#)5AXL zSy19g*JX#Od$`ymC!?}d8qD{whh^>$(YA$1abFI)F^Y8q0bxTvSytBhXF)WS1BvDd z!S`g^mT=Z7JU2;yUuF~ghseR>G-5tkK7A49yXXcs?sRc?#`#-JJ^)@!jLJJHJqG}A zZv%aTLlB{1;o&$D(J`@c@d=4Z!9>Yv@oMQ=**Up+q3ZdCMa3nhWo3_1l~vU>wGmi# zjZMuht!?ccon75+!aaTc`3eKWBco&Ep~OjM5)-im({s^NORH;d*Ecrbz2Dm2Nx|Je zI6OK&IXyf7@bThk7je12d(8I(jB^P5en7_QLnDR+Jn`ST#`ZbbqlpUu4RA>|6c#23 z5fc60RbWOW#WT`M%x26QD9YJ?z&`}3E>owD^p4s216Fz!)>~bKwvPDKwGkD z_g!IJvw)jutyJ|tL{F?3TEw~w-;0^U!F{9;1HL+cDx2<1Vfv(Ks8HnXu0@)5TM;zq36#-!5!PK)%*x@9@FigYh3;3w;yl1Np6=7jUVK|6j zU>%4N%TWZx6zdC$71gSX7obPJBlqz93Zi9j-C;7rR+Sk^y8Z@qD7@TH}LOK55ccw!Xv+xMwm-3!o3xGY8n zl0w4q5tJ3l_AlHOpOS(;tSn>8k^A-2C2JYl2kN1b)~~W~D$>iOt(2|FzqfORyDK8H zPD=Ai4mM&WSfw$kJDq)bYJ8ZNhqBIN5WE!wS>B9hBY5k)x=+3wN<+G9zV9|I9&GXX zZ-hDOLjN)d<9`{1;a}xN`@aohNAbUd5SAfvP+7yDJ_)RYxXkxk6vrAY5NWsz=p3bF zwvenpA%svFIOB;w9@~{=-|T-th)DTAAcSs^cunwRMJjWA4e#zljLtdM{{kVhmw7ik zv9b4tCPa6pdY;|_hb7wT-gok-471s<)cp%W5PT2(2ZVT0ivJclHvCNJ5wxyA8i@o6vVq)>2Kz2=ZbQxk%xQE!qf*Zx_K7a*J&W6@h7 zA5*^LU{{6KyOxPIW{>0qM<*EuM#u*m9+GiLKrQjoar}>y+WC2a`NIqyILYH5KxhxA z-->5W`U2+8b-pnUr>Q)gS=9~Asp2edJ}1lN*tIo0mC-j~WH2@sah6kChm=x(f3|za zi{9UO_yXZAOO)*WPfH_fI!ILL?S~mHySAE^YND%0V+3(gy#o$0pTfjI+uRdPVLt`q z6%FY^vWeakuryMr_Vvw5(^b{Z7!jcvBe9Fb@6Ri(2ht%!Wt_d*{+(G2{&~zB|9#AV z|9#9!bD)2+wou4o#2ssk20o6W&kU6wOaMMfFdlQigA(*l=t*Sy_Qui}aGzQ&J|I$$ zP?P-m!`BsS?ye1o${iI9&X+-v%FUx56}n+02{zs1sa!!d|H0aln#%83TQS#r{(YwJ z9Ge|-jMuY5pgTC*l(QkU@{ntIS^+Fwfi2qq&@=w+#dm9gcaS}?2 zQggOdy^;pcQmdc2VU!{KCMMnwtR@6SyrK44v3XC9>qs7FR)=%fxYx~(Qa zf^|m~SP+rEv$K&@X~;bYhKK+>QlLeHAwqEU@F}3XS=7X^@?Hi^n|D+%1bkv|Z-ZgS zKcfFya&^`wYmN}0onfgCDD&|-$mGD1ZqvY}4V*7S0{!k-o0s?p0XbaDhY}-1U&LoO zktvkimUvoL6bPD?|}uy?tY!LM_X1X z(G;pdQsB76Cg7Ql>uLS7RfA(wN$x(D%KqWw!}`_=z-e9WhbWYjp!B7E({48er@4ZN zn~&P!H`F1Ayk@Ja5zqwVY@3!6;A_uvcRTk0A26{dD_&jfSDAJ3EVO>%FMA5TI>6ud zG0})*s{2e-iD{3N&c0Bg6zP&hZ;pu-w@{V^)wI)%p!$ohI^ZmWJM+{pDtCpEZsUxC z(lrD^13ASJ&|ThlSSo=i9OixQ)5gh9cv7B)!+C}y6_^BFo>8odCtntTfE%9Z`i4%y z1tX)k4^hu=={?uP6ef!)0G&!g>;1nk-mQGAR{1_G{)Is8)4P9lbQ83YzkI+B!29zq zDE!^E&HXJ9vK@e+t4#lY!e~kaJfUbf9(vyotkl4og+s1@r(+y6Z zBSjr0va*@5CrsbK%1w3}IP$~|s^d*uis5v*%Gk>RBBgwf_$2~3Y(Q)i+P6NIGD45wLG&;*Me>l_A_ z&|y%5n&$&c44g20W%TOkD~Ycs%<=AIYjE?y<*CSSkiupG7S%i2B%TrGKoN^fnAC`P zeOJc|%$$;m2+e>W`(p&;7q^NH-Tv-O@9%{(3T*!TaJm-F`0_oyzh!uf(dlx)y{qjE zDR4?Yr7XFfJXPabc!ruiI0Il8g9t3JFC$4`lfkqqg@P}bly zcqC^ORWgWskA%gZh|_h)0#ki^G)_WrB^Y>#F>8n`L~dV9ZJ5x4v?#x)5Js-Ru$Jv1 zran7B^h}tVoM|)J0#&J-1?kUHBq*3;{_pTxm^IS6i#a!N%d$*mD?_Y>&Yx|&urQA9C#Yp zACfr7j?Y(Es7*@TWW;V{oiNu|NzIvA;Zr`XbgSJSrvurJpJ+9O2n$ydGo2-3yu8Yr z9U#QUqSFsFjT5WP`kwWYGZL3iWsW3|RQRLwmtUyrP`t*k0$wC6s`cT&9hR1ctgR$3 z8x}iG-SnW*F%_+lyr8u~>k=mutY2|XMi7#yZ=c3-e+kP3s!DYMhuhlq@~1En;@|Bh1NbC)0cX}Euf0&M{A z^__73pEit)mNRfyH8xxfk5}hkTO4HSK38Q$>0mI#>MmjL$>GVwAq=??z>r9G%W>AV z{^(?BUL*(#@F;zjMe5H`1;#F8&UqC2+qj}$DY6VxM(gPh>9M&q!W7ysiP#Z@xLTP> zo*9Bu3w0peRf5FP8HFa<&W@#R-5|w!YBirD4`HRWbnR{+sxlRhAmOf+0Y!bcTJH(L zr^6u-bxG}!pi*>^Y}cBe%vN*%xzW#m7zF{a)nqkYYFF~AXguB|N3%iNzFxt3MR21F zxsUZqoqx1OR+W9_N79*#T%xmNXN;lSxX%`5{@&t9mX^Qm#ea80827?AeMbFDFeR1Z z%Ve_`iGGXQ_SjW*NyuC9_cVP`#(-w&;yn3u5@cU6=jcU0?p^eUyO5|44dFZxKoyV> zzh*PneyKyT9)$Z#4-rONdyslA6aQaGR^+@;uTYit_DH-F|Rl!7Xx$!~^ciAfiFLu6XZNmcgKE z0~8X2KIVa^F~;@fC~LaYr?D})uRPt1+FtkZ)w&`DORt>?FkkUB7@Ou(u^5!3>R+$# zBp=J271zK%Jdk<%lKcB`76Lgu5-nFWH&KS?&&*9o5fGmu$#Ae)m=q2 zJ*+4qtFIBu%Y~d>E%yLQd_LojNcqRQDLPS~7vi;%|m1Sl$ z6T?otYf$s!AZI3oB!`JDNk?)Io9!hart3(@5)!Jiq zzp0*u=?G}w08!3)=QCC@Iqj6tpVMI%*mNgjm}m8Sm72ueZZ10aUWN0pT|$3P&Snz zfx$|qir5281N$CgY37Nh;$UBsmoLTe>WsoPi%-F9rj(pVKd?(@b7=zr29G{-E2YU> zj0QYx#eEw>XD{G>O~P%^Z4kxmn!Ol|(-A@3S+^*{9XLY9>OjBkeqz#3>B}k}#O}7k z$~VmIBxwjsEf=V?m^SvVIjl_tdyrojhixs{_Xz~3Vd2ECKUV=1{wl??-{3K^(m2b! zgtwA@iHIOw2shi4df?+lco=52M$bfhJCtXvl6$Tm_>lUAR}g~HLM}P|whNwIWn*BR z_vA@9_+x#n0u0M3beQ2y#VG;ev#!4_=h=|u4#KWo_toc zIL@tWPJu1Z6=aRABIvuB{B6pcGIq_Hh9v>+zE)xojb&}@LKS7toGDMFWNxi(a0$29 z?=Y|+X_2-o4JgA14JRV9Nh{9tD5gG4c3^XR%cLe@@Giol|A(zTkUHJc-BV|L=ym#z zS5dLg+qu4YA%5D5{3@=IAeOqfx0-__jx`cY*ovMhxVnG_2ghI{oX-6}cd+X3cCehZ zJ_bEJYj`MZHR>6r4|Y~#KeBoEoIB8bAa^ASZzFSk2|K@b<$xls@ta#B>x<>EM~Ba3 zP-2jXoJ$w7=p}>&~JeeBJb&L_0Z1;W(%^?!=1`2KC6ixNPd}9 zs!5F zPHmZ`Q_d2O7H`0Q7x6_l_YZUNdv8AfQu7aRNx+B~&utRo&c#KLzA5eZll!@HcCeBm zfn8x#Q(!IiM8W)uR7LLgQ>{_;lj)xeYd^OrVHhoYFLN!knxb?hZWe2Up5cN1613|d zb8O+A9sk#53|jqBNYKCLSZcSx_-F!Jt-Ga4%OO$;#4ISXC{RA0Q#((`4wE3AOwhtz zdWR)QHdRc#rEV40Hx=?^UVjzF8m7s^pLRAmM$Sx}U?MsDa2tIfjlmsdw>mD&j>uCR zpv9umjxit?V$)|6gN{ZQnZ#z4YwA{QQVJXEXb9oV5eT}J=0N%fSl1x}yOjF_!RVPz z@p|`*o7RT+%qHx11QJ*-#-wpfLSIRSs`eMm1+WBo>&}gaLa?o@GO9ir(9Tb2SMNTq$`X>VV|K{->8=4(+5 zw_6%{)9!~A0h5$GS2qpM4@5jnmHlo{V?$FFwPO$IE#7mHGPv%gw#vV`^@8`g!|YoC z`c083a1h(%azTh)0mmkuNL7gz5iiVbFv@lDshLNToW3+^o1ESNDXZ@l5=aKBUwK32 zd1awY^}B8}t}oz%h3>ZjB{b<#9&(TT)n(dS1ZD<^&6m#_`#G@;QG1C3mZWY{8o?$6 z02b2{JFs(L$57Pa@1bD>Xd1VUV81}vA3l{kIZAQ0CePYrG&}xY76{m|GnbQMEu~hA z;-{r2W%dz0Oyup}qj|2u>R>P98&I$nB}(nHflLDm3lDz0mzDQwy22@R!TYUjsj~Hr zv%YS*^@sMemeUWN7sEUsyS^+te(Y`+jJV%s$FFnVT=>B#p9<@VL>(E3Y~w|@SXE|S zKQ3_tu%dehe^8N3yGpaXLBjuj9v$-u?+BgWq`>IC7ggrNE+70a>u42zVh;j2W-lhe z`D4qyfN+)jGZ>$Zjz@Bqo&F){+p&d?52Z$zPazLaI6W>+i<`%2m~j+n=ZSJpS0iIg z=vG2L(0VMf_HKR)*h&R`)UN*&)vQvMHDJiGA+U1Z=q0ewT-QLf`~2)3LQ?Vy#lA(I zrvtaO<6AoPi#^|dYr5$*_b)-qn%J1flPRT6YdLOm9#nMpwB#0-AAR3B+9C9Cvx(LN zz6Ez=-Hg8n_m%{3t%trEb7E1V+^mdj_t?jszjqS)LjIk?r?gg8Zuh=2qRi&8)QR?~ z$O-$4@0;~XzrwS6KYpYN!c}u1>k_^7EuB5RX`%w{<{dYrwPyD5+jm@t0J{^|j`_}Q Rj6C2AMEVk(cOdK0{{eTA@00)l literal 0 HcmV?d00001 diff --git a/photon-client/src/assets/noStream.jpg b/photon-client/src/assets/noStream.jpg index b3b4f09b2a4aceb3d4ae511f13436a31e54c1973..b3a28512d696ce4d86f941d6eda8950bdad92108 100644 GIT binary patch literal 77293 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 L7+z_B{r^n>Rt!64 literal 49594 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 diff --git a/photon-client/src/components/common/cv-image.vue b/photon-client/src/components/common/cv-image.vue index 366cc0827..240e5a89c 100644 --- a/photon-client/src/components/common/cv-image.vue +++ b/photon-client/src/components/common/cv-image.vue @@ -5,7 +5,7 @@ :style="styleObject" :src="src" alt="" - @click="e => $emit('click', e)" + @click="e => {this.openThinclientStream(e)}" > @@ -13,7 +13,7 @@ export default { name: "CvImage", // eslint-disable-next-line vue/require-prop-types - props: ['address', 'scale', 'maxHeight', 'maxHeightMd', 'maxHeightLg', 'maxHeightXl', 'colorPicking', 'id', 'disconnected'], + props: ['idx', 'scale', 'maxHeight', 'maxHeightMd', 'maxHeightLg', 'maxHeightXl', 'colorPicking', 'id', 'disconnected'], data() { return { seed: 1.0, @@ -46,18 +46,48 @@ return ret; } }, - src: { + port: { get() { - return this.disconnected ? require("../../assets/noStream.jpg") : this.address + "?" + this.seed // This prevents caching - }, - }, + if(this.idx == 0){ + return this.$store.state.cameraSettings[this.$store.state.currentCameraIndex].inputStreamPort; + } else { + return this.$store.state.cameraSettings[this.$store.state.currentCameraIndex].outputStreamPort; + } + } + } + }, + watch : { + port(newPort, oldPort){ + newPort; + oldPort; + this.reload(); + }, + disconnected(newVal, oldVal){ + oldVal; + if(newVal){ + this.wsStream.stopStream(); + } else { + this.wsStream.startStream(); + } + } }, mounted() { - this.reload(); // Force reload image on creation + var wsvs = require('../../plugins/WebsocketVideoStream'); + this.wsStream = new wsvs.WebsocketVideoStream(this.id, this.port, window.location.host); + }, + unmounted() { + this.wsStream.stopStream(); + this.wsStream.ws_close(); }, methods: { reload() { - this.seed = new Date().getTime(); + console.log("Reloading " + this.id + " with port " + String(this.port)); + this.wsStream.setPort(this.port); + }, + openThinclientStream(e){ + e; + var URL = "/thinclient.html?port=" + String(this.port) + "&host=" + window.location.hostname; + window.open(URL, '_blank'); } }, } diff --git a/photon-client/src/main.js b/photon-client/src/main.js index 81248f7c7..fd1bcba83 100644 --- a/photon-client/src/main.js +++ b/photon-client/src/main.js @@ -15,11 +15,11 @@ if (process.env.NODE_ENV === "production") { Vue.prototype.$address = location.hostname + ":5800"; } -const wsURL = '//' + Vue.prototype.$address + '/websocket'; +const wsDataURL = '//' + Vue.prototype.$address + '/websocket_data'; import VueNativeSock from 'vue-native-websocket'; -Vue.use(VueNativeSock, wsURL, { +Vue.use(VueNativeSock, wsDataURL, { reconnection: true, reconnectionDelay: 100, connectManually: true, diff --git a/photon-client/src/plugins/ColorPicker.js b/photon-client/src/plugins/ColorPicker.js index b887fd2da..8c58235d2 100644 --- a/photon-client/src/plugins/ColorPicker.js +++ b/photon-client/src/plugins/ColorPicker.js @@ -5,7 +5,7 @@ function initColorPicker() { if (!canvas) canvas = document.createElement('canvas'); - image = document.querySelector('#normal-stream'); + image = document.querySelector('#raw-stream'); if (image !== null) { canvas.width = image.width; canvas.height = image.height; diff --git a/photon-client/src/plugins/WebsocketVideoStream.js b/photon-client/src/plugins/WebsocketVideoStream.js new file mode 100644 index 000000000..7a409e8dd --- /dev/null +++ b/photon-client/src/plugins/WebsocketVideoStream.js @@ -0,0 +1,148 @@ + + +export class WebsocketVideoStream{ + + + constructor(drawDiv, streamPort, host) { + + this.drawDiv = drawDiv; + this.image = document.getElementById(this.drawDiv); + this.streamPort = streamPort; + this.serverAddr = "ws://" + host + "/websocket_cameras"; + this.noStream = false; + this.noStreamPrev = false; + this.setNoStream(); + this.ws_connect(); + this.imgData = null; + this.imgDataTime = -1; + this.imgObjURL = null; + this.frameRxCount = 0; + + requestAnimationFrame(()=>this.animationLoop()); + + } + + animationLoop(){ + var now = window.performance.now(); + + if((now - this.imgDataTime) > 2500 && this.imgData != null){ + //Handle websocket send timeouts by restarting + this.setNoStream(); + this.stopStream(); + setTimeout(this.startStream.bind(this), 1000); //restart stream one second later + } else { + if(this.streamPort == null){ + this.setNoStream(); + } else if (this.imgData != null) { + //From https://stackoverflow.com/questions/67507616/set-image-src-from-image-blob/67507685#67507685 + if(this.imgObjURL != null){ + URL.revokeObjectURL(this.imgObjURL) + } + this.imgObjURL = URL.createObjectURL(this.imgData); + + //Update the image with the new mimetype and image + this.image.src = this.imgObjURL; + this.noStream = false; + + } else { + //Nothing, hold previous image while waiting for next frame + } + } + + + requestAnimationFrame(()=>this.animationLoop()); + } + + setNoStream() { + this.noStreamPrev = this.noStream; + this.noStream = true; + if(this.noStreamPrev == false && this.noStream == true){ + //One-shot background change to preserve animation + this.image.src = require("../assets/loading.gif"); + } + } + + startStream() { + if(this.serverConnectionActive == true && this.streamPort > 0){ + this.ws.send(JSON.stringify({"cmd": "subscribe", "port":this.streamPort})); + this.noStream = false; + } + } + + stopStream() { + if(this.serverConnectionActive == true && this.streamPort > 0){ + this.ws.send(JSON.stringify({"cmd": "unsubscribe"})); + this.noStream = true; + } + } + + setPort(streamPort){ + this.stopStream(); + this.frameRxCount = 0; + this.streamPort = streamPort; + this.startStream(); + } + + ws_onOpen() { + // Set the flag allowing general server communication + this.serverConnectionActive = true; + console.log("Connected!"); + this.startStream(); + } + + ws_onClose(e) { + this.setNoStream(); + + //Clear flags to stop server communication + this.ws = null; + this.serverConnectionActive = false; + + console.log('Camera Socket is closed. Reconnect will be attempted in 0.5 second.', e.reason); + setTimeout(this.ws_connect.bind(this), 500); + + if(!e.wasClean){ + console.error('Socket encountered error!'); + } + + } + + ws_onError(e){ + e; //prevent unused failure + this.ws.close(); + } + + ws_onMessage(e){ + if(typeof e.data === 'string'){ + //string data from host + //TODO - anything to receive info here? Maybe "available streams?" + } else { + if(e.data.size > 0){ + //binary data - a frame + this.imgData = e.data; + this.imgDataTime = window.performance.now(); + this.frameRxCount++; + } else { + //TODO - server is sending empty frames? + } + } + + } + + ws_connect() { + this.ws = new WebSocket(this.serverAddr); + this.ws.binaryType = "blob"; + this.ws.onopen = this.ws_onOpen.bind(this); + this.ws.onmessage = this.ws_onMessage.bind(this); + this.ws.onclose = this.ws_onClose.bind(this); + this.ws.onerror = this.ws_onError.bind(this); + console.log("Connecting to server " + this.serverAddr); + } + + ws_close(){ + this.ws.close(); + } + +} + + +export default {WebsocketVideoStream} diff --git a/photon-client/src/store/index.js b/photon-client/src/store/index.js index 086b75260..fc0cc2e54 100644 --- a/photon-client/src/store/index.js +++ b/photon-client/src/store/index.js @@ -35,8 +35,8 @@ export default new Vuex.Store({ tiltDegrees: 0.0, currentPipelineIndex: 0, pipelineNicknames: ["Unknown"], - outputStreamPort: 1181, - inputStreamPort: 1182, + outputStreamPort: 0, + inputStreamPort: 0, nickname: "Unknown", videoFormatList: [ { diff --git a/photon-client/src/views/CamerasView.vue b/photon-client/src/views/CamerasView.vue index 39a8f9dfd..3a5f2a578 100644 --- a/photon-client/src/views/CamerasView.vue +++ b/photon-client/src/views/CamerasView.vue @@ -291,7 +291,8 @@ >