视频服务器(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中显示图片

暂时先不做

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