視頻服務器(9) Kurento[4] unity-kurento-player

1前面基於awrtc.js連接kurento的unity客戶端,能播放出來了,但是在某些環境下會有問題。

一、現狀整理

1.kurento-player的前端頁面在不同瀏覽器都能運行。

不過在IE裏面它自己會彈出一個要求安裝插件的提示,安裝後就和其他瀏覽器一樣能夠播放了。這是不是說明IE目前沒有原生支持WebRTC?

“用IE打開頁面,提示需要安裝 Temasys WebRTC Plugin插件,下載、安裝、刷新,可以播放。”

2.基於awrtc.js的html客戶端頁面,只有在Chrome裏面能播放,Firefox、IE、Edge裏面不能播放。

Firefox裏面有到顯示Video的地方,但是沒有播放視頻;

IE裏面直接說沒有RTCPeerConnection;

Edge裏面則是沒有createDataChannel,說明也不支持。

但是,awrtc.js裏面有看到對WebRTC相關的實現代碼啊。奇怪。

3.我測試用的打包好的webgl頁面,在Chrome裏面能夠播放,在Firefox裏面不能播放。

4.給別人接手,放到一個Demo項目裏面的WebGL打包,連接的是另一個攝像頭,在Chrome裏面不能播放,在Firefox裏面能夠播放。

這裏是爲了給別人演示,放到了一個能外網訪問的電腦上,電腦是雙網卡,有個內網ip和外網ip,攝像頭是在內網上的。訪問的電腦(也就是我的電腦是無法直接訪問那個攝像頭的)。

Firefox上播放正常,Chrome上播放結果是:

偶爾有幾次,就算有上面的錯誤Chrome也能正常播放。

但是手機上的:Chrome播放又是正常的,Firefox正常播放;默認的自帶瀏覽器則不能播放,一直在那裏轉圈;UC瀏覽器姑且試了一下,點擊Start沒反應。

現在的問題是我計劃的WebGL的推薦用戶使用瀏覽器是 1.Chrome 2.Firefox 3.IE ,至少Chrome和Firefox都要正常使用

5.用純js客戶端方式連接外網電腦,Firefox也無法播放視頻。

提示:ICE failed, add a TURN server and see about:webrtc for more details

這個看來需要把TURN server弄起來了

---------------------------------------------------------------------------------------------

現在有兩條路走,1.找到不能播放的原因;2.改kurento-player的前端代碼,放到unity裏面。

都挺花時間的,考慮先做第二種試試吧。其實kurento-player的前端代碼比awrtc封裝的好,也比較靈活。

不能播放的問題的具體研究放到另外一篇文章(視頻服務器(10) Kurento[5] ICE問題)裏面吧。

二、kurento-player js客戶端2

相當於是對《視頻服務器(7) Kurento[2] js客戶端》的後續,這次相當於要把kurento-player-js的代碼和unity結合起來。本來在《視頻服務器(8) Kurento[3] unity客戶端 》裏面已經用awrtc.js插件把視頻播放出來了,換一個外網環境,chrome就播放不出來了。總之繼續弄吧,本來就是一個未完成的任務。

2.1 Unity和Html交互接口

參考之前的awrtc.js,寫一個新的接口,和html中的js代碼交互。爲了提高調試效率,具體js代碼,就不放在unity裏面,直接放在另一個外部js文件中。相關的引用添加到webgl的打包模板中。

2.1.1 Unity調用外部js代碼

在Unity裏面獲取相應的配置信息(videoUrl,serverUrl,uiInfo),發送給外部的js代碼,進行視頻播放和調試。

1.Unity調用接口代碼(KurentoClient.cs)

public void Connect()
    {
        Debug.Log("KurentoClient.Connect");
        Config.ui = GetUIInfo();
        string jsonConfig = JsonUtility.ToJson(Config);
        Debug.Log(jsonConfig);

#if UNITY_WEBGL && !UNITY_EDITOR
        var jsonResult=KurentoClientJS.Unity_Kurento_Connect(jsonConfig);

        Debug.Log("jsonResult:" + jsonResult);
        Id = JsonUtility.FromJson<ConnectId>(jsonResult);
        Debug.Log(Id);
        Debug.Log(Id.id);
#endif

        if (KurentoManager.Instance)
        {
            KurentoManager.Instance.AddClient(this);
        }
    }

2.接口代碼Unity部分

public static class KurentoClientJS
{
    [DllImport("__Internal")]//開始播放
    public static extern string Unity_Kurento_Connect(string config);

    [DllImport("__Internal")]//暫時沒用
    public static extern int Unity_Kurento_Update(string e);

    [DllImport("__Internal")]//停止、暫停、顯示界面、移動界面等指令
    public static extern string Unity_Kurento_Command(string config);
}

2.接口代碼jslib部分(kurento_unity.jslib)

Unity_Kurento_Connect:function(pconfig){
        var configJson=Pointer_stringify(pconfig);//轉換爲字符串
        console.log("------- Unity_Kurento_Connect",configJson,this);
        var config=JSON.parse(configJson);//轉換爲對象
        console.log("------- config",config);
        var client=kurento;//kurento_client.jspre裏面的kurento模塊
        var result= client.CAPI_Kurento_Connect(config);//具體
        console.log("------- result",result);

        //轉換爲字符串
        var returnStr=JSON.stringify(result);
        console.log("------- returnStr",returnStr);
        var bufferSize = lengthBytesUTF8(returnStr) + 1;
        var buffer = _malloc(bufferSize);
        stringToUTF8(returnStr, buffer, bufferSize);
        console.log("------- buffer",buffer);
        return buffer;
    }

3.接口代碼jspre部分(kurento_client.jspre)

                var kurentoClient=null;
                if(unityTool!=null&&unityTool.kurentoClient!=null){
                    kurentoClient=unityTool.kurentoClient;//對接到外部js文件,提高開發調試效率
                }
                 else{
                       kurentoClient=new KurentoClientClass();
                }
                function func_CAPI_Kurento_Connect(config){
                    console.log("------- func_CAPI_Kurento_Connect",config,this);
                    if(kurentoClient){
                        return kurentoClient.Connect(config);
                    }
                    return {id:-2};
                }

4.外部js代碼

KurentoClient.prototype.Connect = function (config) {
        //var player
        config.devId="dev1";
        config.serverUrl="ws://60.191.23.20:8443/player";
        config.videoUrl="rtsp://admin:[email protected]/h264/ch1/main/av_strema";

        console.log(tag + ".Connect", config, this);
        var player=this.players.find(function(item){
            return item.devId==config.devId;
        });
        if(player==null){//第一次播放
            this.currentId++;
            //動態創建Video並播放
            this.CreateVideo(config);
            player=new KurentoPlayerClass(config);
            player.id=this.currentId;
            player.devId=config.devId;
            player.start();
            //保存起來
            this.players.push(player);
        }
        else{

            this.stopPlayers.splice($.inArray(player,this.stopPlayers),1);

            var $ele=$(player.video);
            this.ShowHtmlElementEx($ele, config.ui);//調整位置
        }
        return {id: this.currentId};
    };
//unityTool是個事先創建好的對象
unityTool.kurentoClient=null;
unityTool.kurentoClient=new KurentoClientClass();
unityTool.kurentoClient.StartRemovePlayerTimer();

2.1.2 js代碼發送信息給Unity

一些html事件觸發後通知unity,或者發送數據給unity。

現在用於在頁面大小發生變化時(最大化,還原)讓unity重新發送一下界面信息。

1.js代碼部分

       $(window).resize(function(){//自動調整
            console.info("client windowresize");
            //....
            console.info("setTimeout1",new Date(),this);
            var t=setTimeout(function(){
                console.info("setTimeout2",new Date(),this);

                var evt={vid:0,type:1,data:"window_resize"};
                var s=JSON.stringify(evt);
                unityInstance.SendMessage('KurentoManager', 'ReceiveEvent',s);
            },100);//這裏要延遲執行,立刻執行的話,比例不對,unity裏面的大小還沒變。
        });

2.unity代碼部分

KurentoManager.js,腳本,在場景中掛在一個叫“KurentoManager"的空對象上。

public void ReceiveEvent(string evt)
    {
        Debug.Log("KurentoMananger.ReceiveEvent:" + evt);
        KurentoEvent ke = JsonUtility.FromJson<KurentoEvent>(evt);
        Debug.Log("ke:" + ke);
        Debug.Log("type:" + ke.type);
        Debug.Log("vid:" + ke.vid);
        Debug.Log("data:" + ke.data);
        Debug.Log("(ke.data == window_resize):" + (ke.data == "window_resize"));
        Debug.Log("clients:" + clients.Count);
        if (ke.vid == 0)//全部
        {
            foreach (KeyValuePair<int, KurentoClient> pair in clients)
            {
                pair.Value.DoEvent(ke);
            }
        }
        else
        {
            KurentoClient client = GetClient(ke.vid);
            if (client != null)
            {
                client.DoEvent(ke);
            }
            Debug.Log("client:" + client);
            Debug.Log("id:" + client.Id.id);
        } 
    }

KurentoClient.cs

public void DoEvent(KurentoEvent ke)
    {
        if (ke == null)
        {
            Debug.LogError("KurentoClient.DoEvent ke == null");
            return;
        }
        if (ke.data == "window_resize")
        {
            MoveWnd(null);
        }
    }

2.2 kurento-player封裝

對kurento-player例子的index.js文件進行一下封裝,把相關的變量、方法都放到一個類裏面;這樣子可以把多個攝像頭的變量分類開來。(說實話javascript不是很精通,會用,能看得懂,但是具體的類啊,繼承啊,只會模仿現成的代碼。)

 

2.3 Unity和Html界面同步

unity部分,獲取界面信息,現在支持ScaleWithScreenSize了。

前面的座標轉換(UnityWebGL調研(5) 和網頁交互)需要Canvas上面的CanvsScaler是Constant Pixel Szie。

public UIInfo GetUIInfo()
    {
        UIInfo info = new UIInfo();

        CanvasScaler canvasScaler = VideoImage.GetComponentInParent<CanvasScaler>();
        if (canvasScaler)
        {
            if (canvasScaler.uiScaleMode == CanvasScaler.ScaleMode.ScaleWithScreenSize)
            {
                info.mode = 1;//默認是ConstantPixelSize,是0
            }
        }

        //獲取相對於最外層Canvas的座標
        var posEx = Vector2.zero;
        RectTransform[] pRects=VideoImage.GetComponentsInParent<RectTransform>();
        for (int i = 0; i < pRects.Length; i++)
        {
            RectTransform rec = pRects[i];
            RectTransform recP = null;
            if (i < pRects.Length - 1)
            {
                recP = pRects[i + 1];
                var p = rec.anchoredPosition;
                if (rec.anchorMin.x == 1 && rec.anchorMax.x == 1)
                {
                    p.x += recP.rect.width / 2;
                }
                posEx += p;
            }
            else
            {
                info.swidth = rec.rect.width;
                info.sheight = rec.rect.height;
            }
            Debug.Log("rec:" + rec.anchoredPosition + "," + rec.rect + ",|" + rec.anchorMin + "," + rec.anchorMax + "," + rec + "," + recP);
        }
        var pos = posEx;
        var rect = VideoImage.rect;
        info.id = "video1";
        info.x = pos.x;
        info.y = pos.y;
        info.height = rect.height;
        info.width = rect.width;
        return info;
    }

js部分

        KurentoClient.prototype.ShowHtmlElement=function($ele,posX, posY,sizeX,sizeY,padding){
            "use strict"
            if(this.screenSizeX==null){
                this.screenSizeX=$("#unityContainer").css("width").replace("px","");
            }
            if(this.screenSizeY==null){
                this.screenSizeY=$("#unityContainer").css("height").replace("px","");
            }
            var width=sizeX-padding;
            var height=sizeY-padding;
            $ele.css("width",width);
            $ele.css("height",height);

            var x=this.screenSizeX/2+posX-sizeX/2+padding/2+1;
            var y=this.screenSizeY/2-posY-sizeY/2+padding/2;
            $ele.css("left",x);
            $ele.css("top",y);
            $ele.show();
        };
KurentoClient.prototype.ShowHtmlElementEx=function($ele,ui){
        "use strict"
        if(this.unityContainer==null){
            this.unityContainer=$("#unityContainer");
        }
            this.screenSizeX=this.unityContainer.css("width").replace("px","");
            this.screenSizeY=this.unityContainer.css("height").replace("px","");
        var scale=1;
        if(ui.mode==1){//Unity裏面的CanvasScaler.uiScaleMode == CanvasScaler.ScaleMode.ScaleWithScreenSize,並且Match=0.5
            scale=this.screenSizeX/ui.swidth;
        }

        console.error("ui",ui,ui.swidth/ui.sheight);
        console.error("==>SetScreenInfo",this.screenSizeX,this.screenSizeY);
        console.error("scale",scale);

        this.ShowHtmlElement($ele, ui.x * scale, ui.y* scale, ui.width* scale, ui.height* scale,this.padding* scale);//調整位置
    };
KurentoClient.prototype.Command = function (cmd) {
            console.info(tag + ".Command", cmd, this);
            if(cmd==null){
                console.error("cmd==null");
                return {success:false};
            }
            var player=this.players.find(function(item){
                return item.id==cmd.vid;
            });
            if(player==null){
                console.error("no find player",cmd);
                return {success:false};
            }
            switch (cmd.cid) {
                case "resume":
                    player.resume();
                    break;
                //....
                case "moveWnd":
                    //player.moveWnd();
                    var data=cmd.data;
                    if(data=="end"){

                    }else if(data=="begin"){

                    }
                    else{
                        var ui=cmd.data;
                        player.config.ui=ui;
                        ui.id="video_element_"+cmd.vid;
                        //var video=this.SetupVideoElement();//動態創建元素
                        var $ele=$(player.video);
                        this.ShowHtmlElementEx($ele, ui);//調整位置
                    }

                    break;
                default:
                    break;
            }
            return {success:true};
        };

html部分

  <body>
    <div class="webgl-content">
      <div id="unityContainer" style="width: 960px; height: 600px"></div>
      <div id="videoContainer" style="width:100%;height:100%;position:absolute;left:0px;top:0px;pointer-events: none;"></div>
  </body>

2.4 效果

從結論上看,可以,而且,在網頁裏面播放視頻,不勉強放到unity裏面顯示的話,播放效果更好,也不影響unity的性能。

在Unity裏面拖動界面,視頻Video也能跟隨過去。

手機上的Chrome和Firefox能夠正常播放,PC上的Firefox能夠正常播放。

2.5 Unity中顯示圖片

暫時先不做

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章