Interpretation of the real-time video specification and code example analysis of the B interface of the State Grid

interface description

The B interface of the State Grid accesses real-time video, and the relevant specifications are relatively rough:

Access to real-time video includes signaling interface and media streaming interface, using standard SIP INVITE+SDP process, media transmission using RTP/RTCP.

The value of RTP Payload in SDP shall comply with the definition in the following interface parameters:

a) The media information in SDP should only have one m line, which is used to describe the video format.

b) When video data is packaged and transmitted using RTP, it should be considered that each transmission packet is not larger than the MTU, and the technologies that can be used include encoder layer support (such as ITU-T H.264 multi-slice technology), or RTP layer segmentation. chip mechanism (such as FU-A technology defined in IETF RFC 3984).

After receiving the INVITE request from the platform, the front-end device performs media negotiation according to the SDP description. After the negotiation is passed, the front-end system camera device is turned on and the obtained media stream is sent to the platform through the media channel.

After the session is successfully established, the front-end system can actively end the current call under some special circumstances.

The platform should support the distribution of video streams to reduce the frequency of operations on the front-end system and save network bandwidth.

The interface process of accessing real-time video

The main functional process is as follows:

a) F1: The user sends an INVITE message, carrying the SDP content and forwarding it to the front-end device through the platform.

b) F2: According to SIP requirements, if the front-end system fails to process the request within 0.5s, it will first send a 1xx provisional response and forward it to the user through the platform.

c) F3: The front-end system accepts the operation of the access request, then sends a 200 OK response carrying SDP and forwards it to the user through the platform.

d) F4: The ACK sent by the user is forwarded to the front-end device through the platform.

e) The video stream is transmitted from the front-end system to the user via the platform.

f) F5: The user ends the session and sends a BYE message to the front-end system through the platform.

g) F6: The front-end system sends a confirmation and disconnects the media channel.

Technical realization

Since the invite implementation of the State Grid B interface is not much different from GB28181, our GB28181 has already had a very good accumulation.

 After starting the B interface, complete the platform-side register and PushResource interaction. After some platforms are registered, they will respond to the Push_Resource request. Others are not listed. Here we mainly talk about invte and Ack related callback processing:

Invite signaling is as follows:

    INVITE sip:[email protected]:5060 SIP/2.0
    Via: SIP/2.0/UDP 192.168.0.104:15060;branch=z9hG4bK864531896
    From: <sip:000000000000000001@0000000000>;tag=482531896
    To: <sip:[email protected]:5060>
    Call-ID: 804531783
    CSeq: 6 INVITE
    Content-Type: application/sdp
    Contact: <sip:[email protected]:15060>
    Max-Forwards: 70
    User-Agent: SIPB
    Request-URI: <sip:[email protected]:5060>
    Content-Length: 152
    
    v=0
    o=- 0 0 IN IP4 192.168.0.104
    s=Play
    c=IN IP4 192.168.0.104
    t=0 0
    m=video 30004 RTP/AVP 100
    a=recvonly
    a=rtpmap:100 H264/90000
    y=0130111000

The processing logic of receiving the Invite callback is as follows:

    @Override
    public void ntsOnInvitePlay(String deviceId, SessionDescription session_des) {
        handler_.postDelayed(new Runnable() {
            @Override
            public void run() {
                // 先振铃响应下
                gb28181_agent_.respondPlayInvite(180, device_id_);

                MediaSessionDescription video_des = null;
                SDPRtpMapAttribute ps_rtpmap_attr = null;

                Vector<MediaSessionDescription> video_des_list = session_des_.getVideoPSDescriptions();
                if (video_des_list != null && !video_des_list.isEmpty()) {
                    for(MediaSessionDescription m : video_des_list) {
                        if (m != null && m.isValidAddressType() && m.isHasAddress() ) {
                            video_des = m;
                            ps_rtpmap_attr = video_des.getPSRtpMapAttribute();
                            break;
                        }
                    }
                }

                if (null == video_des) {
                    gb28181_agent_.respondPlayInvite(488, device_id_);
                    Log.i(TAG, "ntsOnInvitePlay get video description is null, response 488, device_id:" + device_id_);
                    return;
                }

                Log.i(TAG,"ntsOnInvitePlay, device_id:" +device_id_+", is_tcp:" + video_des.isRTPOverTCP()
                        + " rtp_port:" + video_des.getPort() + " ssrc:" + video_des.getSSRC()
                        + " address_type:" + video_des.getAddressType() + " address:" + video_des.getAddress());

                long rtp_sender_handle = libPublisher.CreateRTPSender(0);
                if ( rtp_sender_handle == 0 ) {
                    gb28181_agent_.respondPlayInvite(488, device_id_);
                    Log.i(TAG, "ntsOnInvitePlay CreateRTPSender failed, response 488, device_id:" + device_id_);
                    return;
                }


                gb28181_rtp_payload_type_  = 100;
                gb28181_rtp_encoding_name_ =  "PS";

                libPublisher.SetRTPSenderTransportProtocol(rtp_sender_handle, video_des.isRTPOverUDP()?0:1);
                libPublisher.SetRTPSenderIPAddressType(rtp_sender_handle, video_des.isIPv4()?0:1);
                libPublisher.SetRTPSenderLocalPort(rtp_sender_handle, 0);
                libPublisher.SetRTPSenderSSRC(rtp_sender_handle, video_des.getSSRC());
                libPublisher.SetRTPSenderSocketSendBuffer(rtp_sender_handle, 2*1024*1024); // 设置到2M
                libPublisher.SetRTPSenderClockRate(rtp_sender_handle, 90000 /*ps_rtpmap_attr.getClockRate()*/);
                libPublisher.SetRTPSenderDestination(rtp_sender_handle, video_des.getAddress(), video_des.getPort());

                if ( libPublisher.InitRTPSender(rtp_sender_handle) != 0 ) {
                    gb28181_agent_.respondPlayInvite(488, device_id_);
                    libPublisher.DestoryRTPSender(rtp_sender_handle);
                    return;
                }

                int local_port = libPublisher.GetRTPSenderLocalPort(rtp_sender_handle);
                if (local_port == 0) {
                    gb28181_agent_.respondPlayInvite(488, device_id_);
                    libPublisher.DestoryRTPSender(rtp_sender_handle);
                    return;
                }

                Log.i(TAG,"get local_port:" + local_port);

                String local_ip_addr = IPAddrUtils.getIpAddress(context_);

                MediaSessionDescription local_video_des = new MediaSessionDescription(video_des.getType());


                local_video_des.addFormat(String.valueOf(100));
                local_video_des.addRtpMapAttribute(ps_rtpmap_attr);

                local_video_des.setAddressType(video_des.getAddressType());
                local_video_des.setAddress(local_ip_addr);
                local_video_des.setPort(local_port);

                local_video_des.setTransportProtocol(video_des.getTransportProtocol());
                local_video_des.setSSRC(video_des.getSSRC());

                if (!gb28181_agent_.respondPlayInviteOK(device_id_,local_video_des) ) {
                    libPublisher.DestoryRTPSender(rtp_sender_handle);
                    Log.e(TAG, "ntsOnInvitePlay call respondPlayInviteOK failed.");
                    return;
                }

                gb28181_rtp_sender_handle_ = rtp_sender_handle;
            }

            private String device_id_;
            private SessionDescription session_des_;

            public Runnable set(String device_id, SessionDescription session_des) {
                this.device_id_ = device_id;
                this.session_des_ = session_des;
                return this;
            }
        }.set(deviceId, session_des),0);
    }

The ack signaling is as follows:

    ACK sip:[email protected]:5060 SIP/2.0
    Via: SIP/2.0/UDP 192.168.0.104:15060;branch=z9hG4bK991532349
    From: <sip:000000000000000001@0000000000>;tag=482531896
    To: <sip:[email protected]:5060>;tag=2d6ebb3d
    Call-ID: 804531783
    CSeq: 6 ACK
    Contact: <sip:[email protected]:15060>
    Max-Forwards: 70
    User-Agent: SIPB
    Request-URI: <sip:[email protected]:5060>
    Content-Length: 0

The ack callback code processing logic is as follows:

    @Override
    public void ntsOnAckPlay(String deviceId) {
        handler_.postDelayed(new Runnable() {
            @Override
            public void run() {
                Log.i(TAG,"ntsOnACKPlay, device_id:" +device_id_);

                if (!isRTSPPublisherRunning && !isPushingRtmp && !isRecording) {
                    InitAndSetConfig();
                }

                libPublisher.SetGB28181RTPSender(publisherHandle, gb28181_rtp_sender_handle_, gb28181_rtp_payload_type_, gb28181_rtp_encoding_name_);
                int startRet = libPublisher.StartGB28181MediaStream(publisherHandle);
                if (startRet != 0) {

                    if (!isRTSPPublisherRunning && !isPushingRtmp  && !isRecording) {
                        if (publisherHandle != 0) {
                            libPublisher.SmartPublisherClose(publisherHandle);
                            publisherHandle = 0;
                        }
                    }

                    destoryRTPSender();

                    Log.e(TAG, "Failed to start GB28181 service..");
                    return;
                }

                startAudioRecorder();

                startLayerPostThread();
                isGB28181StreamRunning = true;
            }

            private String device_id_;

            public Runnable set(String device_id) {
                this.device_id_ = device_id;
                return this;
            }

        }.set(deviceId),0);
    }

Summarize

The real-time video access process of the State Grid B interface is basically the same as the GB28181 process. Interested developers can refer to the relevant specifications for implementation. Compared with GB28181, the B interface has a narrower scope and less data. If it is commercialized, there are tests Platform, it is not difficult to achieve.

Guess you like

Origin blog.csdn.net/renhui1112/article/details/130151017