GB28181标准制定多年,应用也逐渐广泛,从传统固定的摄像头到可移动的设备,对于前端设备的形态要求也十分多样化。比如单兵,车载等行业领域,传统的摄像头无法满足其便携性,以及丰富的功能接口要求。

     单兵,车载,以及执法仪等使用场景,除了对设备端的便携性外,对于网络的布局基本都是4G/5G的环境,即设备都使用运营商提供的4G物联网卡,对于网络互联互通以及视音频的质量也提出了很高的要求。

     对于GB28181在于公网的使用,除了GB28181-2016的完善外,其实对于技术的实现也是一个变革,如何在低带宽,不可靠的连接下实现流畅音视频交互是作为移动GB28181设备端很有意义的事情。

     从数据流通信来讲,设备端与国标平台的交互主要是sip信令和媒体流(rtp/ps流),设备端做的人性化一点自然会提供web配置页面,那么对外也提供http的访问协议。所以其数据流图如下:


android pjsip GB28181 国标_c++

 

        我们完整的实现了设备端全部的GB28181协议,这个协议比较多,因为我们的实现不仅仅是音视频,对讲,云台,录像,报警,位置定位 等功能模块都需要。

        但是国标设备端是一个被动性的终端,几乎所有GB28181的业务发起都是被动的,被客户端发起的(比如被预览,对讲,都是受控于客户端的,无需设备端主动发起交互),所以功能很多,但是其实封装成sdk,接口反而很简单。主要是一些配置接口,比如设置对讲模式(可以使用默认模式,我们支持外网对讲),配置接口完成后,只需要注册接口注册到平台上之后就可以坐等奇迹的出现了,后面的业务都是接收平台的GB信令,进行对应的响应了。

       将GB28181设备端实现封装成sdk后,接口如下:

//注册到国标平台
 public int open(String serverip,String localip,int serverport,int localport,String serverid,String userid,String userpwd);
 //退出注册
 public void close();
 //设置设备的经纬度位置
 setPosition( double longitude,double latitude);
 //开启采集音视流
 public boolean start(int cameraId, SurfaceHolder surfaceHolder);
 //停止采集音视频流
 public void stop();

    其实注册上平台后,就已经大功告成,调用代码如下:

  

public void startCapture() {
        SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
        String channelid = sharedPrefs.getString("channelID", "");
        String localip = sharedPrefs.getString("localip", "");
        int localport = PreferenceUtil.getPrefInt(sharedPrefs, "port", 5860);
        int talkprotocol = PreferenceUtil.getPrefInt(sharedPrefs, "protocol", 3);
        boolean isEnableTalk  = PreferenceUtil.getPrefBoolean(sharedPrefs, "enabletalk", false);
        GbtDeviceJni.gbtdevice_setTalkEnable(isEnableTalk);

        //视频设置
        int pix_index  = PreferenceUtil.getPrefInt(sharedPrefs, "video_pix", 0);
        int frame_rate = PreferenceUtil.getPrefInt(sharedPrefs, "video_framerate", 15);
        int video_rate = PreferenceUtil.getPrefInt(sharedPrefs, "video_rate", 512);
        int video_gop  = PreferenceUtil.getPrefInt(sharedPrefs, "video_gop", 2);
        int video_codec  = PreferenceUtil.getPrefInt(sharedPrefs, "video_codec", 0);
        int audio_codec  = PreferenceUtil.getPrefInt(sharedPrefs, "audio_codec", 0);
        int width  = 640;
        int height = 480;

        if(pix_index == 0)
        {
            width  = 640;
            height = 480;
        }
        else if(pix_index == 1)
        {
            width  = 1280;
            height = 720;
        }
        else if(pix_index == 2)
        {
            width  = 1920;
            height = 1080;
        }
        else if(pix_index == 3)
        {
            width  = 3840;
            height = 2160;
        }

        MFormat fmt = new MFormat();
        fmt.width  = width;
        fmt.height = height;
        if(video_codec == 0)
            fmt.codec = MediaType.MCODEC_H264;
        else
            fmt.codec = MediaType.MCODEC_H265;
        fmt.fps = frame_rate;
        fmt.gop = video_gop;
        fmt.bitrate = 1024 * video_rate;
        if(audio_codec == 1)
            fmt.audioCodec = MediaType.MCODEC_G711U;
        else if(audio_codec == 2)
            fmt.audioCodec = MediaType.MCODEC_AAC;
        else
            fmt.audioCodec = MediaType.MCODEC_G711A;
        fmt.channels = 1;
        fmt.sampleRate = 8000;

        gbtdevice = SYGbtDeviceApp.getInstance().gbtdevice;
        gbtdevice.setFormat(fmt);

        //字幕叠加
        configOsd();
        if(localip == null || localip.equals("") )
            localip = NetUtil.getLocalAddr(this);
        if(localip == null)
        {
            localip = "0.0.0.0";
            showToast("请确认该设备网络是否已连接.");
        }
        int cameraId = 0;
        String serverip = m_serverip.getText().toString();
        String serverid = m_serverid.getText().toString();
        String userid   = m_userid.getText().toString();
        String userpwd  = m_userpwd.getText().toString();
        int serverport = Integer.parseInt(m_serverport.getText().toString());
        //注册成功回调
        GbtTrack.setloginhandler(sthandler);
        //采集画面和显示画面旋转90度
        gbtdevice.setRotation(90);
        gbtdevice.setDisplayOrientation(90);
        //注册到GB平台
        int ret = gbtdevice.open(serverip,localip,serverport,localport,serverid,userid,userpwd);
        if (ret == 0) {
           //打开音视频采集流
           boolean isStart = gbtdevice.start(cameraId, surfaceView.getHolder());
            if(isStart == false)
            {
                showToast("该设备的camera不支持该分辨率!");
                gbtdevice.close();
                gbtdevice = null;
                return;
            }
        }
        else if(ret == -1)
        {
            showToast("camera打开 失败.");
        }
        else if(ret == -2)
        {
            showToast("GB28181注册 失败.");
        }
        else
        {
            showToast("其他未知错误.");
        }
        //设置对讲模式,我们支持外网对讲
        GbtDeviceJni.gbtdevice_setTalkMode(gbtdevice.GetDeviceHandle(), talkprotocol);
        SharedPreferences settings = this.getSharedPreferences(this.getClass().getName(), 0);
        Editor editor = settings.edit();
        editor.putString("serveripd", m_serverip.getText().toString());
        editor.putString("serverport", m_serverport.getText().toString());
        editor.putString("serverid", m_serverid.getText().toString());
        editor.putString("userid", m_userid.getText().toString());
        editor.putString("userpwd", m_userpwd.getText().toString());
        editor.commit();
    }

     调用的代码很简单,但是功能还是很丰富的,以上实现了全套的GB28181设备端的协议,对于一些公网使用情况并进行了优化和扩展,比如支持外网的持续对讲,对讲时支持回声消除。

   

     主要功能:

      1.H264/H265 多分辨率码率的音视频预览

      2.4G外网的双向对讲,回声消除

      3.录像回放和录像下载

      4.报警上报

      5.位置信息订阅

  通过以上代码函数,就可以实现注册到GB28181平台,然后可以进行呼叫和对讲了。如下图:

   

android pjsip GB28181 国标_python_02

android pjsip GB28181 国标_c++_03