/* ----------------------------------------------------------------------------- This source file is part of OpenSpace3D For the latest info, see http://www.openspace3d.com Copyright (c) 2012 I-maginer This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA, or go to http://www.gnu.org/copyleft/lesser.txt ----------------------------------------------------------------------------- */ var iWidgetZIndex = 0;; struct PlugVideoPlayer = [ VIDP_instance : PInstance, VIDP_bOnMaterial : I, VIDP_bBackground : I, VIDP_bKeepRatio : I, VIDP_iRatioRef : I, VIDP_Object : SO3_OBJECT, VIDP_Material : SO3_MATERIAL, VIDP_iTechnique : I, VIDP_iPass : I, VIDP_iTexture : I, VIDP_win : SO3_WIDGET, VIDP_player : ObjMediaPlayer, VIDP_navbar : VUIcontainer, VIDP_navframe : VUIelement, VIDP_playbtn : VUIelement, VIDP_mutebtn : VUIelement, VIDP_slider : VUISlider, VIDP_iScaleMode : I, VIDP_iPosX : I, VIDP_iPosY : I, VIDP_iWidth : I, VIDP_iHeight : I, VIDP_tPercent : [I I I I I I I I], VIDP_tAlign : [I I], VIDP_bUrl : I, VIDP_sPath : S, VIDP_iStereo : I, VIDP_bAutoplay : I, VIDP_bLoop : I, VIDP_iVolume : I, VIDP_bMuted : I, VIDP_audio : ObjAudio, VIDP_iAudioFormat : I, VIDP_iSampleRate : I, VIDP_b3Daudio : I, VIDP_iDebounceTick : I, VIDP_fAttenuation : F, VIDP_tCone : [I I I], VIDP_bAudioEffect : I, VIDP_iZorder : I, VIDP_bTransparency : I, VIDP_iOpacity : I, VIDP_iTextureQuality : I, VIDP_bUpdateOnFocus : I, VIDP_bFocusOnInit : I, VIDP_bTopOnFocus : I, VIDP_bAllwaysOnTop : I, VIDP_bSwitchState : I, VIDP_bVisible : I, VIDP_bShowNavbar : I, VIDP_bLastState : I ]mkPlugVideoPlayer;; proto destroyNavbar = fun [PlugVideoPlayer] I;; proto createNavbar = fun [PlugVideoPlayer] I;; var sYoutubeApiKey = "AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8";; fun computePosSize(constr, vw, vh)= let _GETmediaPlayerSourceSize constr.VIDP_player -> srcsize in if (!constr.VIDP_bSwitchState) then ( let if constr.VIDP_bOnMaterial then [0 0 0 0 0 0 0 0] else constr.VIDP_tPercent -> [px py pw ph xo yo wo ho] in let constr.VIDP_tAlign -> [ax ay] in let if pw then (ftoi (((itof constr.VIDP_iWidth) /. 100.0) *. (itof vw))) + wo else constr.VIDP_iWidth -> pw in let if ph then (ftoi (((itof constr.VIDP_iHeight) /. 100.0) *. (itof vh))) + ho else constr.VIDP_iHeight -> ph in let if (srcsize == nil) then [pw ph] else srcsize -> [bw bh] in let if (constr.VIDP_bKeepRatio) then (if (constr.VIDP_iRatioRef == 0) then [pw (pw * bh) / bw] else [(ph * bw) / bh ph]) else [pw ph] -> [pw ph] in let if px then (ftoi (((itof constr.VIDP_iPosX) /. 100.0) *. (itof vw))) + xo else constr.VIDP_iPosX -> px in let if (ax == 1) then ((vw / 2) - (pw / 2)) + px else if (ax == 2) then (vw - pw) - px else px -> px in let if py then (ftoi (((itof constr.VIDP_iPosY) /. 100.0) *. (itof vh))) + yo else constr.VIDP_iPosY -> py in let if (ay == 1) then ((vh / 2) - (ph / 2)) + py else if (ay == 2) then (vh - ph) - py else py -> py in [px py pw ph]; ) else //fullscreen ( let if (srcsize == nil) then [constr.VIDP_iWidth constr.VIDP_iHeight] else srcsize -> [bw bh] in let if (constr.VIDP_bKeepRatio) then (if (constr.VIDP_iRatioRef == 0) then [vw (vw * bh) / bw] else [(vh * bw) / bh vh]) else [vw vh] -> [pw ph] in //let addLogMessage strcatn "Size: "::(itoa pw)::" "::(itoa ph)::nil -> _ in [((vw - pw) / 2) ((vh - ph) / 2) pw ph]; );; fun updateMediaSize(constr)= let V3DgetSessionView c3dXsession -> viewstr in let V3DgetDefaultViewport viewstr -> viewportstr in let if constr.VIDP_win == nil || constr.VIDP_bOnMaterial then [constr.VIDP_iWidth constr.VIDP_iHeight] else let V3DgetViewportSize viewstr viewportstr -> [_ _ vw vh] in [vw vh] -> [vw vh] in let computePosSize constr vw vh -> [px py pw ph] in ( SO3WidgetSetPosition constr.VIDP_win px py; // do not resize the bitmap and video if the new size is larger than the source video stream's size let _GETmediaPlayerSourceSize constr.VIDP_player -> srcsize in let _GETmediaPlayerSize constr.VIDP_player -> [curW curH] in let if (srcsize == nil) then [constr.VIDP_iWidth constr.VIDP_iHeight] else srcsize -> [srcW srcH] in let min srcW pw -> destW in let min srcH ph -> destH in ( if (!constr.VIDP_bOnMaterial) then SO3WidgetSetSize constr.VIDP_win pw ph else SO3WidgetSetSize constr.VIDP_win destW destH; destroyNavbar constr; // avoid video buffer change crash if ((srcsize != nil) && (destW == curW) && (destH == curH)) then nil else _SETmediaPlayerSize constr.VIDP_player destW destH; ); ); 0;; fun cbShow(inst, from, action, param, reply, constr)= if (constr.VIDP_win == nil) then nil else ( SO3WidgetSetVisibility constr.VIDP_win 1; ); set constr.VIDP_bVisible = 1; 0;; fun cbHide(inst, from, action, param, reply, constr)= if (constr.VIDP_win == nil) then nil else ( SO3WidgetSetVisibility constr.VIDP_win 0; ); set constr.VIDP_bVisible = 0; 0;; fun vpPlayAudio(constr)= if (!constr.VIDP_b3Daudio || constr.VIDP_Object == nil) then ( _AudioPlay constr.VIDP_audio 0; 0; ) else ( let SO3ObjectGetGlobalPosition constr.VIDP_Object -> pos in let SO3ObjectGetDerivedDirectionAxis constr.VIDP_Object [0.0 0.0 1.0] -> dir in if ((_AudioIsPlaying constr.VIDP_audio) && ((_tickcount - constr.VIDP_iDebounceTick) < 60)) then nil else ( _AudioSetPosition constr.VIDP_audio pos dir; _AudioPlay3d constr.VIDP_audio constr.VIDP_fAttenuation 0; set constr.VIDP_iDebounceTick = _tickcount; 0; ); ); 0;; fun cbPlay(inst, from, action, param, reply, constr)= if (constr.VIDP_player == nil) then nil else ( _PLAYmediaPlayer constr.VIDP_player; if (constr.VIDP_audio == nil) then nil else vpPlayAudio constr; if (constr.VIDP_playbtn == nil) then nil else VUIsetElementCheckState constr.VIDP_playbtn 1; ); set constr.VIDP_bLastState = 1; 0;; fun cbStop(inst, from, action, param, reply, constr)= if (constr.VIDP_player == nil) then nil else ( _STOPmediaPlayer constr.VIDP_player; if (constr.VIDP_audio == nil) then nil else ( _AudioStop constr.VIDP_audio; ); if (constr.VIDP_playbtn == nil) then nil else VUIsetElementCheckState constr.VIDP_playbtn 0; ); set constr.VIDP_bLastState = 0; 0;; fun cbPause(inst, from, action, param, reply, constr)= if (constr.VIDP_player == nil) then nil else ( // Stop if pause fails (could be the case with livestreams) if ((_PAUSEmediaPlayer constr.VIDP_player)== nil) then ( cbStop inst from action param reply constr; 0; ) else if (constr.VIDP_audio == nil) then nil else ( _AudioPause constr.VIDP_audio; 0; ); if (constr.VIDP_playbtn == nil) then nil else VUIsetElementCheckState constr.VIDP_playbtn 0; ); set constr.VIDP_bLastState = 0; 0;; fun cbMute(inst, from, action, param, reply, constr)= set constr.VIDP_bMuted = !constr.VIDP_bMuted; if (constr.VIDP_audio == nil) then nil else ( if (constr.VIDP_bMuted) then _AudioSetVolume constr.VIDP_audio 0 else _AudioSetVolume constr.VIDP_audio constr.VIDP_iVolume; if (constr.VIDP_mutebtn == nil) then nil else VUIsetElementCheckState constr.VIDP_mutebtn constr.VIDP_bMuted; ); 0;; fun vpSeek(constr, pos)= if ((constr == nil) || (constr.VIDP_player == nil) || !(_GETmediaPlayerIsSeekable constr.VIDP_player)) then nil else ( _SEEKmediaPlayer constr.VIDP_player pos; if (constr.VIDP_audio == nil) then nil else ( // Flush internal audio buffer _AudioStop constr.VIDP_audio; if ((_GETmediaPlayerState constr.VIDP_player) != MP_STATE_PLAYING) then nil else ( _AudioPlay constr.VIDP_audio 0; ); ); if (constr.VIDP_slider == nil) then nil else VUIsetSliderValue constr.VIDP_slider (itof pos); ); 0;; fun cbSeek(inst, from, action, param, reply, constr)= if ((atoi param)== nil) || (constr.VIDP_player == nil) then nil else ( vpSeek constr (atoi param); 0; ); 0;; fun cbSeekForward(inst, from, action, param, reply, constr)= let if ((atoi param)== nil) then 5000 else (atoi param) -> stime in if (constr.VIDP_player == nil) then nil else ( let _GETmediaPlayerTime constr.VIDP_player -> currentTime in vpSeek constr (currentTime + stime); 0; ); 0;; fun cbSeekBackward(inst, from, action, param, reply, constr)= let if ((atoi param)== nil) then 5000 else (atoi param) -> stime in if (constr.VIDP_player == nil) then nil else ( let _GETmediaPlayerTime constr.VIDP_player -> currentTime in vpSeek constr (currentTime - stime); 0; ); 0;; fun cbSetVolume(inst, from, action, param, reply, constr)= if (constr.VIDP_player == nil || (atoi param)== nil) then nil else ( set constr.VIDP_iVolume = abs(atoi param); if (constr.VIDP_audio == nil) then nil else _AudioSetVolume constr.VIDP_audio constr.VIDP_iVolume; 0; ); 0;; fun cbUpdateSound(constr)= let SO3ObjectGetGlobalPosition constr.VIDP_Object -> pos in let SO3ObjectGetDerivedDirectionAxis constr.VIDP_Object [0.0 0.0 1.0] -> dir in _AudioSetPosition constr.VIDP_audio pos dir; 0;; fun cbControlPreRender(inst, sessionstr, etime, constr)= //Creates navbar if destroyed because of video resize if (constr.VIDP_bShowNavbar == 0) || (constr.VIDP_navbar != nil) then nil else ( createNavbar constr; ); if (!(_GETmediaPlayerHasVideo constr.VIDP_player) || !(_GETmediaPlayerHasNewFrame constr.VIDP_player)) then nil else ( if (constr.VIDP_bShowNavbar) then ( set constr.VIDP_navbar.VUICNT_bNeedUpdate = 1; 0; ) else ( let _GETmediaPlayerBuffer constr.VIDP_player -> [buff bw bh bc] in SO3BitmapWidgetBlitBuffer constr.VIDP_win buff bw bh bc; 0; ); ); if ((_GETmediaPlayerState constr.VIDP_player) != MP_STATE_PLAYING) then nil else ( if (constr.VIDP_slider == nil) then nil else let _GETmediaPlayerTime constr.VIDP_player -> currentTime in VUIsetSliderValue constr.VIDP_slider (itof currentTime); let _GETmediaPlayerAudio constr.VIDP_player -> buff in if (constr.VIDP_audio == nil) then nil else ( _AudioFillBuffer constr.VIDP_audio buff; if (!constr.VIDP_b3Daudio || constr.VIDP_Object == nil) then nil else cbUpdateSound constr; ); ); 0;; fun cbGetAudioStreams(inst, from, action, param, reply, constr)= let _GETmediaPlayerAudioStreams constr.VIDP_player -> streams in let itoa (sizelist streams) -> nbStreams in SendPluginEvent constr.VIDP_instance "Get audio streams" (strcatnSep (nbStreams::streams) "\n") nil; 0;; fun cbGetVideoStreams(inst, from, action, param, reply, constr)= let _GETmediaPlayerVideoStreams constr.VIDP_player -> streams in let itoa (sizelist streams) -> nbStreams in SendPluginEvent constr.VIDP_instance "Get video streams" (strcatnSep (nbStreams::streams) "\n") nil; 0;; fun isYoutubeUrl(url)= if ((strfind "youtube.com" url 0) != nil) || ((strfind "y2u.be" url 0) != nil) || ((strfind "youtu.be" url 0) != nil) then 1 else 0;; fun isVimeoUrl(url)= if ((strfind "vimeo.com" url 0) != nil) then 1 else 0;; fun isDailymotionUrl(url)= if (((strfind "dailymotion.com" url 0) != nil) || ((strfind "dai.ly" url 0) != nil)) && ((strfind "/cdn/" url 0)== nil) then 1 else 0;; fun cbMediaPlayerLoaded(player, p, ret)= let p -> [constr play] in if (!ret) then nil else ( SendPluginEvent constr.VIDP_instance "Loaded" nil nil; cbGetVideoStreams constr.VIDP_instance nil nil nil nil constr; cbGetAudioStreams constr.VIDP_instance nil nil nil nil constr; if (!(_GETmediaPlayerHasAudio constr.VIDP_player) && constr.VIDP_audio != nil) then ( _DSAudio constr.VIDP_audio; set constr.VIDP_audio = nil; 0; ) else if ((_GETmediaPlayerHasAudio constr.VIDP_player) && constr.VIDP_audio == nil) then ( set constr.VIDP_audio = _CRAudioStream _channel (getPluginInstanceName constr.VIDP_instance) constr.VIDP_iSampleRate constr.VIDP_iAudioFormat; _AudioSetVolume constr.VIDP_audio constr.VIDP_iVolume; _AudioEnableSoundEffect constr.VIDP_audio constr.VIDP_bAudioEffect; if (constr.VIDP_b3Daudio && constr.VIDP_Object != nil) then ( let constr.VIDP_tCone -> [innerangle outerangle outervol] in _AudioSetCone constr.VIDP_audio innerangle outerangle outervol; ) else nil; 0; ) else nil; updateMediaSize constr; setPluginInstanceCbScenePreRender constr.VIDP_instance mkfun4 @cbControlPreRender constr; let _GETmediaPlayerLength constr.VIDP_player -> length in if (constr.VIDP_slider == nil) then nil else VUIsetSliderMaxValue constr.VIDP_slider (itof length); if (!play && !constr.VIDP_bLastState) then nil else ( cbPlay constr.VIDP_instance nil nil nil nil constr; ); ); 0;; fun openVideo(inst, constr, play)= //addLogMessage strcat "Open video from : " constr.VIDP_sPath; _CBmediaPlayerLoaded constr.VIDP_player @cbMediaPlayerLoaded [constr play]; if (!constr.VIDP_bUrl) then _OPENmediaPlayerFile constr.VIDP_player (_checkpack constr.VIDP_sPath) else _OPENmediaPlayerUrl constr.VIDP_player constr.VIDP_sPath; 0;; // TODO get wanted format (for youtube plugIT /* 5: Result := 'Low Quality, 240p, FLV, 400x240'; 17: Result := 'Low Quality, 144p, 3GP, 0x0'; 18: Result := 'Medium Quality, 360p, MP4, 480x360'; 22: Result := 'High Quality, 720p, MP4, 1280x720'; 34: Result := 'Medium Quality, 360p, FLV, 640x360'; 35: Result := 'Standard Definition, 480p, FLV, 854x480'; 36: Result := 'Low Quality, 240p, 3GP, 0x0'; 37: Result := 'Full High Quality, 1080p, MP4, 1920x1080'; 38: Result := 'Original Definition, MP4, 4096x3072'; 43: Result := 'Medium Quality, 360p, WebM, 640x360'; 44: Result := 'Standard Definition, 480p, WebM, 854x480'; 45: Result := 'High Quality, 720p, WebM, 1280x720'; 46: Result := 'Full High Quality, 1080p, WebM, 1280x720'; 82: Result := 'Medium Quality 3D, 360p, MP4, 640x360'; 84: Result := 'High Quality 3D, 720p, MP4, 1280x720'; 100: Result := 'Medium Quality 3D, 360p, WebM, 640x360'; 102: Result := 'High Quality 3D, 720p, WebM, 1280x720'; */ fun cbDownloadYoutube(url, data, p)= let p -> [constr vid play targetSize inst] in let webtostr data -> str in let nil -> lurl in let nil -> q480 in let nil -> q720 in ( if ((strfindi "\"formats\": [" str 0)== nil) then ( addLogMessage strcatn "Video "::(vid)::" on Youtube is not allowed as embed video"::nil; 0; ) else ( let strfindi "\"formats\": [" str 0 -> fmtstart in let strfindi "]" str fmtstart + 12 -> fmtend in let substr str (fmtstart + 12) (fmtend - fmtstart + 12) -> formats in let strToListOpenCloseSep formats "{" "}" -> l in while (l != nil) do ( let hd l -> req in let lineextr req -> lp in let nil -> itag in let nil -> yurl in let nil -> sig in ( while (lp != nil) do ( let hd lp -> pm in let strtrimChar pm nil "," -> pm in ( if (strfind "\"itag\":" pm 0)== nil then nil else let strfind ":" pm 0 -> dp in set itag = strtrimChar (substr pm dp + 1 (strlen pm) - dp) "\"" "\""; //addLogMessage strcat "itag " itag; //if (strfind "\"signature\":" pm 0)== nil then nil else //set sig = substr pm 13 (strlen pm) -14; if (strfind "\"url\":" pm 0)== nil then nil else let strfind ":" pm 0 -> dp in set yurl = urlDecode strtrimChar (substr pm dp + 1 (strlen pm) - dp) "\"" "\""; //addLogMessage strcat "url " yurl; ); set lp = tl lp; ); if (itag == nil) || (yurl == nil) then nil else ( //addLogMessage strcatn "Url found: "::yurl::" with itag: "::itag::" and sign: "::sig::nil; set lurl = [yurl itag sig]::lurl; ); ); set l = tl l; ); //check target size to get HD if needed let targetSize -> [tw th] in if (tw <= 800) then nil else let lurl -> cpl in while (cpl != nil && q720 == nil) do ( let hd cpl -> [yurl itag sig] in let webtostr yurl -> yurl in ( //addLogMessage strcat "available itag : " itag; if (strcmp itag "22") && (strcmp itag "95") && (strcmp itag "45") then nil else set q720 = if (sig != nil) then strcatn yurl::"&signature="::sig::nil else yurl; ); set cpl = tl cpl; ); while (lurl != nil && q480 == nil) do ( let hd lurl -> [yurl itag sig] in let webtostr yurl -> yurl in ( //addLogMessage strcat "available itag : " itag; if (strcmp itag "22") && (strcmp itag "94") && (strcmp itag "35") && (strcmp itag "18") && (strcmp itag "44") && (strcmp itag "43") then nil else set q480 = if (sig != nil) then strcatn yurl::"&signature="::sig::nil else yurl; ); set lurl = tl lurl; ); set constr.VIDP_sPath = if (q720 != nil) then q720 else q480; if (constr.VIDP_sPath != nil) then nil else addLogMessage strcat "Video stream not found on : " url; if (strcmp "encoded_fmt_stream_map=url=" (substr constr.VIDP_sPath 0 27)) then nil else ( //addLogMessage "remove encoded_fmt_stream_map=url="; set constr.VIDP_sPath = substr constr.VIDP_sPath 27 strlen constr.VIDP_sPath; ); //addLogMessage constr.VIDP_sPath; openVideo inst constr play; 0; ); ); 0;; fun callYoutubeApi(inst, constr, vid, play, targetSize)= let "Content-Type: application/json"::"Accept: application/json"::nil -> header in let "https://www.youtube.com/youtubei/v1/player?key=AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8" -> yurl in let strtoutf8 makeSimpleJson ["context" makeSimpleJson ["client" makeSimpleJson ["clientName" "'WEB'"]::["clientVersion" "'2.20201021.03.00'"]::nil]::nil]::["video_id" strcatn "'"::vid::"'"::nil]::nil -> jsonparam in ( //addLogMessage yurl; downloadFilePost yurl jsonparam header mkfun3 @cbDownloadYoutube [constr vid play targetSize inst]; ); 0;; fun cbDownloadYoutubePage(url, data, p)= let p -> [constr vid play targetSize inst] in let webtostr data -> str in if ((strfindi "\"playableInEmbed\":true" str 0)== nil) then ( addLogMessage strcatn "Video "::(vid)::" on Youtube is not allowed as embed video"::nil; 0; ) else ( callYoutubeApi inst constr vid play targetSize; ); 0;; fun fetchYoutubeUrl(url, constr, play, targetSize, inst)= let strfind "v=" url 0 -> burl in let if (burl != nil) then (substr url burl + 2 (strlen url)) else while ((strfind "/" url 0) != nil) do set url = substr url ((strfind "/" url 0) + 1) (strlen url) -> vid in let strcatn "https://www.youtube.com/watch?v="::vid::"&bpctr=9999999999&has_verified=1"::nil -> yurl in ( downloadFile yurl mkfun3 @cbDownloadYoutubePage [constr vid play targetSize inst]; ); 0;; fun stripUrlSlashes(s)= let strlen s -> size in let 0 -> pos in while (pos < size) do ( if ((((nth_char s pos)== 92) && ((nth_char s pos + 1)== 92)) || ((nth_char s pos) != 92)) then set pos = pos + 1 else ( set s = strcat (substr s 0 pos) (substr s (pos + 1) (strlen s)); set size = strlen s; set pos = pos + 1; ); ); s;; fun cbDownloadDailyMotion(url, data, p)= let p -> [constr vid play inst] in let stripUrlSlashes webtostr utf8tostr data -> str in let strreplace strreplace strreplace str "{" "" "}" "" (ctoa 34) "" -> str in let strToListSep str "," -> l in let nil -> stream in ( while (l != nil) do ( let hd l -> req in ( if ((strfind "stream_h264_hq_url" req 0) != nil) || (((strfind "stream_h264_url" req 0) != nil) && stream == nil) then let (substr req (strfind ":" req 0) + 1 (strlen req)) -> st1 in let (substr st1 0 (strlen st1)) -> st1 in ( set stream = st1; ) else nil; ); set l = tl l; ); if (strcmp stream "null") then nil else addLogMessage strcat "Error Daylimotion stream: " stream; //addLogMessage stream; set constr.VIDP_sPath = stream; openVideo inst constr play; ); 0;; fun fetchDailymotionUrl(url, constr, play, targetSize, inst)= let while ((strfind "/" url 0) != nil) do set url = substr url ((strfind "/" url 0) + 1) (strlen url) -> vid in let strcatn "https://www.dailymotion.com/json/video/"::vid::"?fields=stream_h264_hq_url,stream_h264_url"::nil -> yurl in ( downloadFile yurl mkfun3 @cbDownloadDailyMotion [constr vid play inst]; ); 0;; fun byBiggerIndex(s, t)= let s -> [i _] in let t -> [d _] in if (i < d) then 1 else -1;; fun cbDownloadVimeoData(url, data, p)= let p -> [constr vid play targetSize inst] in let stripUrlSlashes utf8tostr data -> str in let strfind "\"progressive\":[{" str 0 -> spos in let strfind "]}" str spos -> epos in let substr str (spos + 16) (epos - (spos + 16)) -> streams in let strToListSep streams "," -> l in let nil -> lstream in let nil -> fstream in ( let nil -> lastq in let nil -> laststream in while (l != nil) do ( let hd l -> req in ( if ((strfind "quality" req 0) != nil) then let substr req (strfind ":" req 0) + 1 (strlen req) -> ql1 in let strtrimChar substr ql1 0 (strlen ql1) "\"" "\"" -> ql1 in let substr ql1 0 (strlen ql1) - 1 -> ql1 in let atoi ql1 -> iql1 in ( set lastq = iql1; if (laststream == nil) then nil else ( set lstream = [iql1 laststream]::lstream; set lastq = nil; set laststream = nil; ); ); if ((strfind "url" req 0) != nil) then let substr req (strfind ":" req 0) + 1 (strlen req) -> st1 in let strtrimChar substr st1 0 (strlen st1) "\"" "\"" -> st1 in ( set laststream = st1; if (lastq == nil) then nil else ( set lstream = [lastq st1]::lstream; set lastq = nil; set laststream = nil; ); ) else nil; ); set l = tl l; ); set lstream = quicksort lstream @byBiggerIndex; let targetSize -> [tw th] in while (lstream != nil && fstream == nil) do ( let hd lstream -> [q st] in ( addLogMessage strcatn (itoa tw)::" "::(itoa q)::nil; if (tw >= q) then set fstream = st else nil; ); set lstream = tl lstream; ); if (fstream != nil) then nil else addLogMessage strcat "Video stream not found on : " url; set constr.VIDP_sPath = fstream; //addLogMessage constr.VIDP_sPath; openVideo inst constr play; 0; ); 0;; fun cbDownloadVimeo(url, data, p)= let p -> [constr vid play targetSize inst] in ( let strcatn "src=\\\"https://player.vimeo.com/video/"::vid::"?h="::nil -> turl in let strlen turl -> len in let strfind turl data 0 -> spos in let strfind "\\\"" data spos + len -> epos in let substr data (spos + len) (epos - (spos + len)) -> hv in ( if ((spos == nil) || (hv == nil)) then ( addLogMessage strcat "Error Daylimotion stream: " hv; 0; ) else ( let strcatn "https://player.vimeo.com/video/"::vid::"/config?autopause=1&byline=0&collections=1&context=Vimeo%5CController%5CClipController.main&default_to_hd=1&h="::hv::"&outro=nothing&portrait=0&share=1&speed=1&title=0&watch_trailer=0"::nil -> jsonurl in downloadFile jsonurl mkfun3 @cbDownloadVimeoData [constr vid play targetSize inst]; 0; ); ); ); 0;; fun fetchVimeoUrl(url, constr, play, targetSize, inst)= let while ((strfind "/" url 0) != nil) do set url = substr url ((strfind "/" url 0) + 1) (strlen url) -> vid in let strcatn "https://player.vimeo.com/video/"::vid::nil -> vurl in ( downloadFile vurl mkfun3 @cbDownloadVimeo [constr vid play targetSize inst]; ); 0;; fun cbChangeVideo(inst, from, action, param, reply, constr)= let strIsUrl param -> isurl in if param == nil then nil else ( set constr.VIDP_bUrl = isurl; set constr.VIDP_sPath = param; if constr.VIDP_win == nil then nil else ( let SO3WidgetGetSize constr.VIDP_win -> [cw ch] in let if (constr.VIDP_bKeepRatio) then if (constr.VIDP_iRatioRef == 0) then [cw cw] else [ch ch] else [cw ch] -> cursize in let _GETmediaPlayerState constr.VIDP_player -> previousState in ( cbStop inst nil nil nil nil constr; setPluginInstanceCbScenePreRender inst nil; if (isurl && isYoutubeUrl param) then ( fetchYoutubeUrl constr.VIDP_sPath constr (previousState == MP_STATE_PLAYING) cursize inst; 0; ) else if (isurl && isDailymotionUrl param) then ( fetchDailymotionUrl constr.VIDP_sPath constr (previousState == MP_STATE_PLAYING) cursize inst; 0; ) else if (isurl && isVimeoUrl param) then ( fetchVimeoUrl constr.VIDP_sPath constr (previousState == MP_STATE_PLAYING) cursize inst; 0; ) else ( openVideo inst constr (previousState == MP_STATE_PLAYING); 0; ); ); ); ); 0;; fun cbSetVideoStream(inst, from, action, param, reply, constr)= let (atoi param) -> streamId in if (streamId == nil) then nil else ( let _SETmediaPlayerStream constr.VIDP_player streamId -> success in if ((success == nil) || (constr.VIDP_audio == nil)) then nil else ( _AudioStop constr.VIDP_audio; if ((_GETmediaPlayerState constr.VIDP_player) != MP_STATE_PLAYING) then nil else vpPlayAudio constr; ); ); 0;; fun cbSetAudioStream(inst, from, action, param, reply, constr)= let (atoi param) -> streamId in if (streamId == nil) then nil else ( let _SETmediaPlayerAudioStream constr.VIDP_player streamId -> success in if ((success == nil) || (constr.VIDP_audio == nil)) then nil else ( _AudioStop constr.VIDP_audio; if ((_GETmediaPlayerState constr.VIDP_player) != MP_STATE_PLAYING) then nil else vpPlayAudio constr; ); ); 0;; fun cbSetPosition(inst, from, action, param, reply, constr)= if param == nil then nil else let strextr param -> lp in let (nth_list (hd lp) 0) -> sx in let (nth_list (hd lp) 1) -> sy in ( set constr.VIDP_bSwitchState = 0; let 0 -> xpercent in let if (!strcmp "%" (substr sx ((strlen sx) - 1) 1)) then ( set xpercent = 1; atoi sx; ) else atoi sx -> px in let 0 -> ypercent in let if (!strcmp "%" (substr sy ((strlen sy) - 1) 1)) then ( set ypercent = 1; atoi sy; ) else atoi sy -> py in let [(if px == nil then 0 else px) (if py == nil then 0 else py)] -> [px py] in ( mutate constr.VIDP_tPercent <- [xpercent ypercent _ _ _ _ _ _]; set constr.VIDP_iPosX = px; set constr.VIDP_iPosY = py; updateMediaSize constr; ); ); 0;; fun cbSetSize(inst, from, action, param, reply, constr)= if param == nil then nil else let strextr param -> lp in let (nth_list (hd lp) 0) -> sx in let (nth_list (hd lp) 1) -> sy in ( set constr.VIDP_bSwitchState = 0; let 0 -> wpercent in let if (!strcmp "%" (substr sx ((strlen sx) - 1) 1)) then ( set wpercent = 1; abs (atoi sx); ) else if (sx == nil) then constr.VIDP_iWidth else abs (atoi sx) -> px in let 0 -> hpercent in let if (!strcmp "%" (substr sy ((strlen sy) - 1) 1)) then ( set hpercent = 1; abs (atoi sy); ) else if (sy == nil) then constr.VIDP_iHeight else abs (atoi sy) -> py in let [(if px == nil then 0 else px) (if py == nil then 0 else py)] -> [px py] in ( mutate constr.VIDP_tPercent <- [_ _ wpercent hpercent _ _ _ _]; set constr.VIDP_iWidth = px; set constr.VIDP_iHeight = py; updateMediaSize constr; ); ); 0;; fun cbUnFocus(inst, from, action, param, reply, constr)= SO3WidgetUnFocus constr.VIDP_win; 0;; fun cbResizeCtrl(inst, viewstr, ww, wh, constr)= if constr.VIDP_win == nil || constr.VIDP_bOnMaterial then nil else updateMediaSize constr; 0;; fun cbOnFocus(widget, constr, state)= if state then SendPluginEvent constr.VIDP_instance "Focused" nil nil else SendPluginEvent constr.VIDP_instance "Unfocused" nil nil; 0;; fun cbMediaPlayerEnd(playerobj, constr)= SendPluginEvent constr.VIDP_instance "Video ended" nil nil; if (constr.VIDP_playbtn == nil) then nil else VUIsetElementCheckState constr.VIDP_playbtn 0; 0;; fun createWidget(constr, mode)= let V3DgetSessionView c3dXsession -> viewstr in let (V3DgetDefaultViewport viewstr) -> viewportstr in let nil -> vsize in ( setPluginInstanceCbResizeView constr.VIDP_instance nil; //destroy previous one V3DremoveWidgetControl viewportstr constr.VIDP_win; SO3WidgetDestroy constr.VIDP_win; set constr.VIDP_win = nil; if constr.VIDP_bOnMaterial && !mode then ( set vsize = [constr.VIDP_iWidth constr.VIDP_iHeight]; set constr.VIDP_win = SO3BitmapWidgetCreateOnMaterial (V3DgetSession c3dXsession) constr.VIDP_Material strcat (getPluginInstanceName constr.VIDP_instance) "_mediaPlayer" constr.VIDP_iWidth constr.VIDP_iHeight constr.VIDP_iTechnique constr.VIDP_iPass constr.VIDP_iTexture; 0; ) else if constr.VIDP_bBackground then ( let V3DgetViewportSize viewstr viewportstr -> [_ _ vw vh] in let computePosSize constr vw vh -> [px py pw ph] in ( set vsize = [pw ph]; set constr.VIDP_win = SO3BitmapWidgetCreateBackground (V3DgetSession c3dXsession) viewportstr.V3D_viewport (strcat (getPluginInstanceName constr.VIDP_instance) "_mediaPlayer") px py pw ph; ); 0; ) else ( let constr.VIDP_tAlign -> [ax ay] in let V3DgetViewportSize viewstr viewportstr -> [_ _ vw vh] in let computePosSize constr vw vh -> [px py pw ph] in ( set vsize = [pw ph]; set constr.VIDP_win = SO3BitmapWidgetCreate (V3DgetSession c3dXsession) viewportstr.V3D_viewport strcat (getPluginInstanceName constr.VIDP_instance) "_mediaPlayer" px py pw ph constr.VIDP_iZorder; ); SO3WidgetSetTopOnFocus constr.VIDP_win constr.VIDP_bTopOnFocus; SO3WidgetSetForeground constr.VIDP_win constr.VIDP_bAllwaysOnTop; ); V3DaddWidgetControl viewportstr constr.VIDP_win; SO3WidgetSetTransparency constr.VIDP_win constr.VIDP_bTransparency; SO3WidgetSetKeyboardEnable constr.VIDP_win 0; SO3WidgetSetMouseEnable constr.VIDP_win (constr.VIDP_bShowNavbar != 0); if !constr.VIDP_bFocusOnInit || !mode then nil else SO3WidgetSetFocus constr.VIDP_win; SO3WidgetSetOpacity constr.VIDP_win (itof constr.VIDP_iOpacity) *. 0.01; SO3WidgetSetTextureRatio constr.VIDP_win (itof constr.VIDP_iTextureQuality) *. 0.01; SO3WidgetSetUpdateOnFocusOnly constr.VIDP_win constr.VIDP_bUpdateOnFocus; SO3WidgetFocusEventCb constr.VIDP_win @cbOnFocus constr; SO3WidgetSetVisibility constr.VIDP_win constr.VIDP_bVisible; SO3WidgetSetStereo constr.VIDP_win constr.VIDP_iStereo; if constr.VIDP_bOnMaterial then nil else setPluginInstanceCbResizeView constr.VIDP_instance mkfun5 @cbResizeCtrl constr; updateMediaSize constr; vsize; );; fun destroyNavbar(constr)= if (constr.VIDP_navbar == nil) then nil else ( VUIdestroyContainer constr.VIDP_navbar; SO3WidgetSetKeyboardEnable constr.VIDP_win 0; SO3WidgetSetMouseEnable constr.VIDP_win 0; set constr.VIDP_navbar = nil; set constr.VIDP_playbtn = nil; set constr.VIDP_mutebtn = nil; set constr.VIDP_navframe = nil; set constr.VIDP_slider = nil; ); 0;; fun cbPreUpdateNavBar(contstr, abmp, constr)= if (!_GETmediaPlayerHasVideo constr.VIDP_player) then ( VUIsetContainerExternalBuffer contstr nil; ) else ( let _GETmediaPlayerBuffer constr.VIDP_player -> mbuffer in VUIsetContainerExternalBuffer contstr mbuffer; ); 0;; fun cbPostUpdateNavBar(contstr, abmp, constr)= if (contstr.VUICNT_extBuffer == nil) then nil else ( let contstr.VUICNT_extBuffer -> [buff bw bh bc] in SO3BitmapWidgetBlitBuffer constr.VIDP_win buff bw bh bc; //reset to nil to avoid reuse the dead buffer and crash VUIsetContainerExternalBuffer contstr nil; ); 0;; fun cbPlayButton(eltstr, id, x, y, btn, constr)= if (constr.VIDP_bLastState) then ( cbPause constr.VIDP_instance nil nil nil nil constr; ) else ( cbPlay constr.VIDP_instance nil nil nil nil constr; ); 0;; fun cbMuteButton(eltstr, id, x, y, btn, constr)= cbMute constr.VIDP_instance nil nil nil nil constr; 0;; fun cbStopButton(eltstr, id, x, y, btn, constr)= cbStop constr.VIDP_instance nil nil nil nil constr; VUIsetElementCheckState constr.VIDP_playbtn 0; 0;; fun cbPskipButton(eltstr, id, x, y, btn, constr)= cbSeekBackward constr.VIDP_instance nil nil nil nil constr; 0;; fun cbNskipButton(eltstr, id, x, y, btn, constr)= cbSeekForward constr.VIDP_instance nil nil nil nil constr; 0;; fun cbNavbarIn(cstr, constr)= VUIshowElement constr.VIDP_navframe 1; 0;; fun cbNavbarOut(cstr, constr)= VUIshowElement constr.VIDP_navframe 0; 0;; fun cbSliderPosition(cstr, value, constr)= vpSeek constr (ftoi value); 0;; fun createNavbar(constr)= if (constr.VIDP_navbar != nil) then nil else let V3DgetSessionView c3dXsession -> viewstr in ( set constr.VIDP_navbar = VUIcreateContainerFromWidget viewstr constr.VIDP_instance.INST_groupstr.GRP_project.PRJ_vuiGroup constr.VIDP_win 95; let if (constr.VIDP_bOnMaterial) then let _GETmediaPlayerSize constr.VIDP_player -> msize in let if msize == nil then [constr.VIDP_iWidth constr.VIDP_iHeight] else msize -> [curW curH] in (itof (max curW curH)) /. 512.0 else 1.0 -> scale in let VUIcreateFrame constr.VIDP_navbar nil [0.0 0.0] [80.0 35.0 *. scale] [0 0 1 0 0 0 0 0] [1 2] -> frame in let strcat (getPluginDirectory (getInstancePlugin constr.VIDP_instance)) "/res/tb_playpause.png" -> pbtnpath in let VUIcreateButton constr.VIDP_navbar frame [5.0 *. scale 0.0] [24.0 *. scale 24.0 *. scale] [0 0 0 0 0 0 0 0] [0 1] -> playbtn in let strcat (getPluginDirectory (getInstancePlugin constr.VIDP_instance)) "/res/tb_stop.png" -> sbtnpath in let VUIcreateButton constr.VIDP_navbar frame [40.0 *. scale 0.0] [24.0 *. scale 24.0 *. scale] [0 0 0 0 0 0 0 0] [0 1] -> stopbtn in let strcat (getPluginDirectory (getInstancePlugin constr.VIDP_instance)) "/res/tb_prevskip.png" -> psbtnpath in let VUIcreateButton constr.VIDP_navbar frame [75.0 *. scale 0.0] [24.0 *. scale 24.0 *. scale] [0 0 0 0 0 0 0 0] [0 1] -> pskipbtn in let strcat (getPluginDirectory (getInstancePlugin constr.VIDP_instance)) "/res/tb_nextskip.png" -> nsbtnpath in let VUIcreateButton constr.VIDP_navbar frame [110.0 *. scale 0.0] [24.0 *. scale 24.0 *. scale] [0 0 0 0 0 0 0 0] [0 1] -> nskipbtn in let strcat (getPluginDirectory (getInstancePlugin constr.VIDP_instance)) "/res/tb_mute.png" -> msbtnpath in let VUIcreateButton constr.VIDP_navbar frame [145.0 *. scale 0.0] [24.0 *. scale 24.0 *. scale] [0 0 0 0 0 0 0 0] [0 1] -> mutebtn in let VUIcreateSlider constr.VIDP_navbar frame [10.0 *. scale 0.0] [100.0 100.0] [0 0 1 1 0 0 ftoi (-.190.0 *. scale) ftoi (-. 10.0 *. scale)] [2 1] 0.0 1.0 1.0 0 0.0 0 10 0 -> slider in ( //set constr.VIDP_navbar.VUICNT_fScale = scale; VUIsetElementResource playbtn nil nil nil (_checkpack pbtnpath) VUI_ResKeepRatio 4 2 nil nil; VUIsetElementCheckState playbtn constr.VIDP_bLastState; //use unclick to avoid check state conflict VUIsetElementCbUnClick playbtn mkfun6 @cbPlayButton constr; VUIsetElementCbClick stopbtn mkfun6 @cbStopButton constr; VUIsetElementResource stopbtn nil nil nil (_checkpack sbtnpath) VUI_ResKeepRatio 4 1 nil nil; VUIsetElementCbClick pskipbtn mkfun6 @cbPskipButton constr; VUIsetElementResource pskipbtn nil nil nil (_checkpack psbtnpath) VUI_ResKeepRatio 4 1 nil nil; VUIsetElementCbClick nskipbtn mkfun6 @cbNskipButton constr; VUIsetElementResource nskipbtn nil nil nil (_checkpack nsbtnpath) VUI_ResKeepRatio 4 1 nil nil; VUIsetElementResource mutebtn nil nil nil (_checkpack msbtnpath) VUI_ResKeepRatio 4 2 nil nil; VUIsetElementCheckState mutebtn constr.VIDP_bMuted; //use unclick to avoid check state conflict VUIsetElementCbUnClick mutebtn mkfun6 @cbMuteButton constr; VUIsetSliderCbChange slider mkfun3 @cbSliderPosition constr; let _GETmediaPlayerLength constr.VIDP_player -> length in VUIsetSliderMaxValue slider (itof length); set constr.VIDP_playbtn = playbtn; set constr.VIDP_mutebtn = mutebtn; set constr.VIDP_navframe = frame; set constr.VIDP_slider = slider; VUIsetElementResource frame 0x222222dd nil nil nil nil nil nil nil nil; if (constr.VIDP_bShowNavbar != 2) then nil else ( VUIsetContainerCbMouseIn constr.VIDP_navbar mkfun2 @cbNavbarIn constr; VUIsetContainerCbMouseOut constr.VIDP_navbar mkfun2 @cbNavbarOut constr; ); ); if (constr.VIDP_bShowNavbar != 2) then nil else VUIshowElement constr.VIDP_navframe 0; VUIsetContainerOpacity constr.VIDP_navbar 90; VUIshowContainer constr.VIDP_navbar 1; VUIsetContainerPreUpdateCallback constr.VIDP_navbar mkfun3 @cbPreUpdateNavBar constr; VUIsetContainerPostUpdateCallback constr.VIDP_navbar mkfun3 @cbPostUpdateNavBar constr; SO3WidgetSetKeyboardEnable constr.VIDP_win 1; SO3WidgetSetMouseEnable constr.VIDP_win 1; SO3WidgetSetTextureRatio constr.VIDP_win (itof constr.VIDP_iTextureQuality) *. 0.01; ); 0;; fun cbCreate(inst, from, action, param, reply, constr)= let V3DgetSessionView c3dXsession -> viewstr in let (V3DgetDefaultViewport viewstr) -> viewportstr in let nil -> vsize in ( if (constr.VIDP_win != nil) then nil else ( set constr.VIDP_player = _CRmediaPlayer _channel; set vsize = createWidget constr constr.VIDP_bSwitchState; let vsize -> [cw ch] in set vsize = if (constr.VIDP_bKeepRatio) then if (constr.VIDP_iRatioRef == 0) then [cw cw] else [ch ch] else [cw ch]; // Enable 3D audio only if the video is also attached to a 3D object if (constr.VIDP_b3Daudio && constr.VIDP_Object != nil) then ( set constr.VIDP_iAudioFormat = MP_AUDIO_16BIT_MONO; ) else ( set constr.VIDP_iAudioFormat = MP_AUDIO_16BIT_STEREO; ); set constr.VIDP_iSampleRate = 44100; _SETmediaPlayerAudioFormat constr.VIDP_player constr.VIDP_iAudioFormat constr.VIDP_iSampleRate; _CBmediaPlayerEnd constr.VIDP_player @cbMediaPlayerEnd constr; _SETmediaPlayerLoop constr.VIDP_player constr.VIDP_bLoop; if (constr.VIDP_bUrl && isYoutubeUrl constr.VIDP_sPath) then ( fetchYoutubeUrl constr.VIDP_sPath constr constr.VIDP_bAutoplay vsize inst; 0; ) else if (constr.VIDP_bUrl && isDailymotionUrl constr.VIDP_sPath) then ( fetchDailymotionUrl constr.VIDP_sPath constr constr.VIDP_bAutoplay vsize inst; 0; ) else if (constr.VIDP_bUrl && isVimeoUrl constr.VIDP_sPath) then ( fetchVimeoUrl constr.VIDP_sPath constr constr.VIDP_bAutoplay vsize inst; 0; ) else ( openVideo inst constr constr.VIDP_bAutoplay; 0; ); if (!constr.VIDP_bShowNavbar) then nil else createNavbar constr; ); ); 0;; fun cbDestroy(inst, from, action, param, reply, constr)= setPluginInstanceCbResizeView inst nil; setPluginInstanceCbScenePreRender inst nil; destroyNavbar constr; _DSmediaPlayer constr.VIDP_player; set constr.VIDP_player = nil; _DSAudio constr.VIDP_audio; set constr.VIDP_audio = nil; V3DremoveWidgetControl (V3DgetDefaultViewport (V3DgetSessionView c3dXsession)) constr.VIDP_win; SO3WidgetDestroy constr.VIDP_win; set constr.VIDP_win = nil; set constr.VIDP_bLastState = 0; 0;; fun cbSwitchFullscreen(inst, from, action, param, reply, constr)= set constr.VIDP_bSwitchState = !constr.VIDP_bSwitchState; if (constr.VIDP_player == nil) then nil else createWidget constr constr.VIDP_bSwitchState; 0;; fun cbSetOpacity(inst, from, action, param, reply, constr)= if param == nil then nil else ( SO3WidgetSetOpacity constr.VIDP_win (atof param) *. 0.01; set constr.VIDP_iOpacity = atoi param; ); 0;; fun cbSetTextureQuality(inst, from, action, param, reply, constr)= if param == nil then nil else ( SO3WidgetSetTextureRatio constr.VIDP_win (atof param) *. 0.01; set constr.VIDP_iTextureQuality = atoi param; ); 0;; fun cbEnableEffect(inst, from, action, param, rep, constr)= set constr.VIDP_bAudioEffect = 1; _AudioEnableSoundEffect constr.VIDP_audio 1; 0;; fun cbDisableEffect(inst, from, action, param, rep, constr)= set constr.VIDP_bAudioEffect = 0; _AudioEnableSoundEffect constr.VIDP_audio 0; 0;; fun cbShowNavbar(inst, from, action, param, rep, constr)= let if ((atoi param) == 2) then 2 else 1 -> mode in if (constr.VIDP_bShowNavbar != 0) then nil else ( set constr.VIDP_bShowNavbar = mode; if (constr.VIDP_win == nil) then nil else createNavbar constr; ); 0;; fun cbHideNavbar(inst, from, action, param, rep, constr)= if (constr.VIDP_bShowNavbar == 0) then nil else ( set constr.VIDP_bShowNavbar = 0; destroyNavbar constr; ); 0;; fun deleteOb(inst, constr)= cbDestroy inst nil nil nil nil constr; 0;; fun newOb(inst)= let atoi (getPluginInstanceParam inst "istexture") -> istexture in let if istexture == nil then 0 else istexture -> istexture in let (getPluginInstanceParam inst "object") -> objname in let (getPluginInstanceParam inst "material") -> matname in let atoi (getPluginInstanceParam inst "technique") -> technique in let if technique == nil then 0 else technique -> technique in let atoi (getPluginInstanceParam inst "pass") -> pass in let if pass == nil then 0 else pass -> pass in let atoi (getPluginInstanceParam inst "texture") -> texture in let if texture == nil then 0 else texture -> texture in let (getPluginInstanceParam inst "path") -> path in let (getPluginInstanceParam inst "url") -> url in let atoi (getPluginInstanceParam inst "isurl") -> isurl in let atoi (getPluginInstanceParam inst "autoplay") -> autoplay in let if autoplay == nil then 1 else autoplay -> autoplay in let atoi (getPluginInstanceParam inst "navbar") -> navbar in let if navbar == nil then 0 else navbar -> navbar in let atoi (getPluginInstanceParam inst "stereo") -> stereo in let if stereo == nil then 0 else stereo -> stereo in let atoi (getPluginInstanceParam inst "loop") -> loop in let if loop == nil then 0 else loop -> loop in let atoi (getPluginInstanceParam inst "volume") -> volume in let if volume == nil then 100 else volume -> volume in let atoi (getPluginInstanceParam inst "enableeffect") -> enableeffect in let atoi (getPluginInstanceParam inst "background") -> isbackground in let if (isbackground == nil) then 0 else isbackground -> isbackground in let atoi (getPluginInstanceParam inst "keepratio") -> keepratio in let if (keepratio == nil) then 0 else keepratio -> keepratio in let atoi (getPluginInstanceParam inst "ratioref") -> ratioref in let if ratioref == nil then 0 else ratioref -> ratioref in let atoi (getPluginInstanceParam inst "scalemode") -> scalemode in let if scalemode == nil then 0 else scalemode -> scalemode in let atoi (getPluginInstanceParam inst "posx") -> posx in let atoi (getPluginInstanceParam inst "posy") -> posy in let atoi (getPluginInstanceParam inst "width") -> width in let atoi (getPluginInstanceParam inst "height") -> height in let atoi (getPluginInstanceParam inst "xpercent") -> xpercent in let atoi (getPluginInstanceParam inst "ypercent") -> ypercent in let atoi (getPluginInstanceParam inst "wpercent") -> wpercent in let atoi (getPluginInstanceParam inst "hpercent") -> hpercent in let atoi (getPluginInstanceParam inst "xoffset") -> xoffset in let if xoffset == nil then 0 else xoffset -> xoffset in let atoi (getPluginInstanceParam inst "yoffset") -> yoffset in let if yoffset == nil then 0 else yoffset -> yoffset in let atoi (getPluginInstanceParam inst "woffset") -> woffset in let if woffset == nil then 0 else woffset -> woffset in let atoi (getPluginInstanceParam inst "hoffset") -> hoffset in let if hoffset == nil then 0 else hoffset -> hoffset in let atoi (getPluginInstanceParam inst "xalign") -> xalign in let atoi (getPluginInstanceParam inst "yalign") -> yalign in let atoi (getPluginInstanceParam inst "transparency") -> transparency in let atoi (getPluginInstanceParam inst "updateonfocus") -> updateonfocus in let if updateonfocus == nil then 0 else updateonfocus -> updateonfocus in let atoi (getPluginInstanceParam inst "focus") -> focus in let atoi (getPluginInstanceParam inst "toponfocus") -> toponfocus in let if toponfocus == nil then 1 else toponfocus -> toponfocus in let atoi (getPluginInstanceParam inst "allwaysontop") -> allwaysontop in let if allwaysontop == nil then 0 else allwaysontop -> allwaysontop in let atoi (getPluginInstanceParam inst "opacity") -> opacity in let atoi (getPluginInstanceParam inst "texturequality") -> texturequality in let atoi (getPluginInstanceParam inst "zorder") -> zorder in let atoi (getPluginInstanceParam inst "is3daudio") -> is3daudio in let if is3daudio == nil then 0 else is3daudio -> is3daudio in let atof (getPluginInstanceParam inst "attenuation") -> attenuation in let if attenuation == nil then 1.0 else attenuation -> attenuation in let atoi (getPluginInstanceParam inst "innerangle") -> innerangle in let if innerangle == nil then 360 else innerangle -> innerangle in let atoi (getPluginInstanceParam inst "outerangle") -> outerangle in let if outerangle == nil then 360 else outerangle -> outerangle in let atoi (getPluginInstanceParam inst "outervol") -> outervol in let if outervol == nil then 0 else outervol -> outervol in let if ((zorder == nil) || (zorder == 0)) then set iWidgetZIndex = iWidgetZIndex + 1 else (if zorder > iWidgetZIndex then set iWidgetZIndex = zorder else zorder) -> zorder in let atoi (getPluginInstanceParam inst "init") -> oninit in let atoi (getPluginInstanceParam inst "show") -> show in let if show == nil then 1 else show -> show in let if !isurl then path else url -> file in let SO3SceneGetObject (V3DgetSession c3dXsession) objname -> obj in let if !istexture then nil else SO3SceneGetMaterial (V3DgetSession c3dXsession) (SO3EntityGetResourceGroup obj) matname -> mat in let mkPlugVideoPlayer [inst istexture isbackground keepratio ratioref obj mat technique pass texture nil nil nil nil nil nil nil scalemode posx posy width height [xpercent ypercent wpercent hpercent xoffset yoffset woffset hoffset] [xalign yalign] isurl file stereo autoplay loop volume 0 nil nil nil is3daudio 0 attenuation [innerangle outerangle outervol] enableeffect zorder transparency opacity texturequality updateonfocus focus toponfocus allwaysontop 0 show navbar 0] -> constr in ( if !oninit then nil else cbCreate inst nil nil nil nil constr; PluginRegisterAction inst "Show" mkfun6 @cbShow constr; PluginRegisterAction inst "Hide" mkfun6 @cbHide constr; PluginRegisterAction inst "Create" mkfun6 @cbCreate constr; PluginRegisterAction inst "Destroy" mkfun6 @cbDestroy constr; PluginRegisterAction inst "Set opacity" mkfun6 @cbSetOpacity constr; PluginRegisterAction inst "Set texture quality" mkfun6 @cbSetTextureQuality constr; PluginRegisterAction inst "Change video" mkfun6 @cbChangeVideo constr; PluginRegisterAction inst "Set position" mkfun6 @cbSetPosition constr; PluginRegisterAction inst "Set size" mkfun6 @cbSetSize constr; PluginRegisterAction inst "Release focus" mkfun6 @cbUnFocus constr; PluginRegisterAction inst "Play" mkfun6 @cbPlay constr; PluginRegisterAction inst "Pause" mkfun6 @cbPause constr; PluginRegisterAction inst "Stop" mkfun6 @cbStop constr; PluginRegisterAction inst "Seek" mkfun6 @cbSeek constr; PluginRegisterAction inst "Seek backward" mkfun6 @cbSeekBackward constr; PluginRegisterAction inst "Seek forward" mkfun6 @cbSeekForward constr; PluginRegisterAction inst "Set volume" mkfun6 @cbSetVolume constr; PluginRegisterAction inst "Mute" mkfun6 @cbMute constr; PluginRegisterAction inst "Enable Effect" mkfun6 @cbEnableEffect constr; PluginRegisterAction inst "Disable Effect" mkfun6 @cbDisableEffect constr; PluginRegisterAction inst "Set video stream" mkfun6 @cbSetVideoStream constr; PluginRegisterAction inst "Set audio stream" mkfun6 @cbSetAudioStream constr; PluginRegisterAction inst "Get video streams" mkfun6 @cbGetVideoStreams constr; PluginRegisterAction inst "Get audio streams" mkfun6 @cbGetAudioStreams constr; PluginRegisterAction inst "Switch fullscreen" mkfun6 @cbSwitchFullscreen constr; PluginRegisterAction inst "Show control bar" mkfun6 @cbShowNavbar constr; PluginRegisterAction inst "Hide control bar" mkfun6 @cbHideNavbar constr; setPluginInstanceCbDel inst mkfun2 @deleteOb constr; ); 0;; fun IniPlug(file)= PlugRegister @newOb nil; setPluginEditor @dynamicedit; 0;;