Rtsp.h 8.87 KB
Newer Older
xiongziliang committed
1
/*
xiongziliang committed
2
 * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
xiongziliang committed
3
 *
4
 * This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
xiongziliang committed
5
 *
xiongziliang committed
6 7 8
 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
xiongziliang committed
9
 */
xiongziliang committed
10

xzl committed
11 12 13 14 15 16
#ifndef RTSP_RTSP_H_
#define RTSP_RTSP_H_

#include <string.h>
#include <string>
#include <memory>
xiongzilaing committed
17
#include <unordered_map>
18
#include "Util/util.h"
xiongziliang committed
19 20
#include "Common/config.h"
#include "Common/macros.h"
21
#include "Extension/Frame.h"
xiongzilaing committed
22

xzl committed
23
using namespace std;
xiongziliang committed
24 25
using namespace toolkit;
using namespace mediakit;
xzl committed
26

xiongziliang committed
27 28 29 30
namespace mediakit {

namespace Rtsp {
typedef enum {
31 32 33 34
    RTP_Invalid = -1,
    RTP_TCP = 0,
    RTP_UDP = 1,
    RTP_MULTICAST = 2,
xiongziliang committed
35
} eRtpType;
xiongziliang committed
36 37

#define RTP_PT_MAP(XX) \
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
    XX(PCMU, TrackAudio, 0, 8000, 1, CodecG711U) \
    XX(GSM, TrackAudio , 3, 8000, 1, CodecInvalid) \
    XX(G723, TrackAudio, 4, 8000, 1, CodecInvalid) \
    XX(DVI4_8000, TrackAudio, 5, 8000, 1, CodecInvalid) \
    XX(DVI4_16000, TrackAudio, 6, 16000, 1, CodecInvalid) \
    XX(LPC, TrackAudio, 7, 8000, 1, CodecInvalid) \
    XX(PCMA, TrackAudio, 8, 8000, 1, CodecG711A) \
    XX(G722, TrackAudio, 9, 8000, 1, CodecInvalid) \
    XX(L16_Stereo, TrackAudio, 10, 44100, 2, CodecInvalid) \
    XX(L16_Mono, TrackAudio, 11, 44100, 1, CodecInvalid) \
    XX(QCELP, TrackAudio, 12, 8000, 1, CodecInvalid) \
    XX(CN, TrackAudio, 13, 8000, 1, CodecInvalid) \
    XX(MPA, TrackAudio, 14, 90000, 1, CodecInvalid) \
    XX(G728, TrackAudio, 15, 8000, 1, CodecInvalid) \
    XX(DVI4_11025, TrackAudio, 16, 11025, 1, CodecInvalid) \
    XX(DVI4_22050, TrackAudio, 17, 22050, 1, CodecInvalid) \
    XX(G729, TrackAudio, 18, 8000, 1, CodecInvalid) \
    XX(CelB, TrackVideo, 25, 90000, 1, CodecInvalid) \
    XX(JPEG, TrackVideo, 26, 90000, 1, CodecInvalid) \
    XX(nv, TrackVideo, 28, 90000, 1, CodecInvalid) \
    XX(H261, TrackVideo, 31, 90000, 1, CodecInvalid) \
    XX(MPV, TrackVideo, 32, 90000, 1, CodecInvalid) \
    XX(MP2T, TrackVideo, 33, 90000, 1, CodecInvalid) \
    XX(H263, TrackVideo, 34, 90000, 1, CodecInvalid) \
xiongziliang committed
62 63

typedef enum {
64
#define ENUM_DEF(name, type, value, clock_rate, channel, codec_id) PT_ ## name = value,
xiongziliang committed
65 66 67 68 69
    RTP_PT_MAP(ENUM_DEF)
#undef ENUM_DEF
    PT_MAX = 128
} PayloadType;

xiongziliang committed
70 71
};

xiongziliang committed
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
#if defined(_WIN32)
#pragma pack(push, 1)
#endif // defined(_WIN32)

class RtpHeader {
public:
#if __BYTE_ORDER == __BIG_ENDIAN
    //版本号,固定为2
    uint32_t version: 2;
    //padding
    uint32_t padding: 1;
    //扩展
    uint32_t ext: 1;
    //csrc
    uint32_t csrc: 4;
    //mark
    uint32_t mark: 1;
    //负载类型
    uint32_t pt: 7;
#else
    //csrc
    uint32_t csrc: 4;
    //扩展
    uint32_t ext: 1;
    //padding
    uint32_t padding: 1;
    //版本号,固定为2
    uint32_t version: 2;
    //负载类型
    uint32_t pt: 7;
    //mark
    uint32_t mark: 1;
#endif
    //序列号
    uint32_t seq: 16;
    //时间戳
    uint32_t stamp;
    //ssrc
    uint32_t ssrc;
    //负载,如果有csrc和ext,前面为 4 * csrc + (4 + 4 * ext_len)
    uint8_t payload;

public:
    //返回csrc字段字节长度
    size_t getCsrcSize() const;
    //返回csrc字段首地址,不存在时返回nullptr
    uint8_t *getCsrcData();

    //返回ext字段字节长度
    size_t getExtSize() const;
    //返回ext段首地址,不存在时返回nullptr
    uint8_t *getExtData();

    //返回有效负载指针,跳过csrc、ext
    uint8_t* getPayloadData();
    //返回有效负载总长度,不包括csrc、ext、padding
xia-chu committed
128 129 130
    size_t getPayloadSize(size_t rtp_size) const;
    //打印调试信息
    string dumpString(size_t rtp_size) const;
xiongziliang committed
131 132 133 134 135 136 137 138 139 140 141 142 143

private:
    //返回有效负载偏移量
    size_t getPayloadOffset() const;
    //返回padding长度
    size_t getPaddingSize(size_t rtp_size) const;
} PACKED;

#if defined(_WIN32)
#pragma pack(pop)
#endif // defined(_WIN32)

//此rtp为rtp over tcp形式,需要忽略前4个字节
xiongziliang committed
144 145
class RtpPacket : public BufferRaw{
public:
xiongziliang committed
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
    using Ptr = std::shared_ptr<RtpPacket>;
    enum {
        kRtpVersion = 2,
        kRtpHeaderSize = 12,
        kRtpTcpHeaderSize = 4
    };

    RtpHeader* getHeader();
    //主机字节序的seq
    uint16_t getSeq();
    //主机字节序的时间戳,已经转换为毫秒
    uint32_t getStampMS();
    //主机字节序的ssrc
    uint32_t getSSRC();
    //有效负载,跳过csrc、ext
    uint8_t* getPayload();
    //有效负载长度,不包括csrc、ext、padding
    size_t getPayloadSize();

    //音视频类型
166
    TrackType type;
xiongziliang committed
167 168
    //音频为采样率,视频一般为90000
    uint32_t sample_rate;
xia-chu committed
169 170 171 172 173 174

    static Ptr create();

private:
    friend class ResourcePool_l<RtpPacket>;
    RtpPacket() = default;
xia-chu committed
175 176 177 178

private:
    //对象个数统计
    ObjectStatistic<RtpPacket> _statistic;
xiongziliang committed
179 180
};

xiongziliang committed
181
class RtpPayload {
xiongziliang committed
182 183 184 185 186
public:
    static int getClockRate(int pt);
    static TrackType getTrackType(int pt);
    static int getAudioChannel(int pt);
    static const char *getName(int pt);
187
    static CodecId getCodecId(int pt);
xiongziliang committed
188

xiongziliang committed
189 190 191 192 193
private:
    RtpPayload() = delete;
    ~RtpPayload() = delete;
};

xiongziliang committed
194
class SdpTrack {
195
public:
xiongziliang committed
196
    using Ptr = std::shared_ptr<SdpTrack>;
197

198 199 200 201 202 203 204
    string _m;
    string _o;
    string _s;
    string _i;
    string _c;
    string _t;
    string _b;
xiongziliang committed
205
    uint16_t _port;
206

207 208 209
    float _duration = 0;
    float _start = 0;
    float _end = 0;
210

211 212
    map<char, string> _other;
    map<string, string> _attr;
213

214
    string toString() const;
xiongziliang committed
215
    string getName() const;
xiongziliang committed
216

217
public:
218
    int _pt;
xiongziliang committed
219
    int _channel;
xiongziliang committed
220 221 222
    int _samplerate;
    TrackType _type;
    string _codec;
223 224 225
    string _fmtp;
    string _control;
    string _control_surffix;
xiongziliang committed
226

xiongziliang committed
227
public:
228
    bool _inited = false;
xiongziliang committed
229
    uint8_t _interleaved = 0;
230
    uint16_t _seq = 0;
xiongziliang committed
231
    uint32_t _ssrc = 0;
232 233
    //时间戳,单位毫秒
    uint32_t _time_stamp = 0;
234
};
xiongziliang committed
235

xiongziliang committed
236
class SdpParser {
237
public:
xiongziliang committed
238
    using Ptr = std::shared_ptr<SdpParser>;
239 240 241 242

    SdpParser() {}
    SdpParser(const string &sdp) { load(sdp); }
    ~SdpParser() {}
xiongziliang committed
243

244 245 246 247
    void load(const string &sdp);
    bool available() const;
    SdpTrack::Ptr getTrack(TrackType type) const;
    vector<SdpTrack::Ptr> getAvailableTrack() const;
xiongziliang committed
248 249
    string toString() const;

250
private:
251
    vector<SdpTrack::Ptr> _track_vec;
252
};
xzl committed
253

254 255 256 257 258
/**
 * 解析rtsp url的工具类
 */
class RtspUrl{
public:
xiongziliang committed
259 260
    bool _is_ssl;
    uint16_t _port;
261 262 263 264
    string _url;
    string _user;
    string _passwd;
    string _host;
xiongziliang committed
265

266
public:
267 268 269
    RtspUrl() = default;
    ~RtspUrl() = default;
    bool parse(const string &url);
xiongziliang committed
270

271
private:
272
    bool setup(bool,const string &, const string &, const string &);
273
};
xzl committed
274

xiongziliang committed
275 276 277 278 279
/**
* rtsp sdp基类
*/
class Sdp : public CodecInfo{
public:
xiongziliang committed
280
    using Ptr = std::shared_ptr<Sdp>;
281 282 283 284

    /**
     * 构造sdp
     * @param sample_rate 采样率
xiongziliang committed
285
     * @param payload_type pt类型
286
     */
xiongziliang committed
287
    Sdp(uint32_t sample_rate, uint8_t payload_type){
288
        _sample_rate = sample_rate;
xiongziliang committed
289
        _payload_type = payload_type;
290 291 292 293 294 295 296 297 298 299 300 301 302 303
    }

    virtual ~Sdp(){}

    /**
     * 获取sdp字符串
     * @return
     */
    virtual string getSdp() const  = 0;

    /**
     * 获取pt
     * @return
     */
xiongziliang committed
304 305
    uint8_t getPayloadType() const{
        return _payload_type;
306 307 308 309 310 311 312 313 314
    }

    /**
     * 获取采样率
     * @return
     */
    uint32_t getSampleRate() const{
        return _sample_rate;
    }
xiongziliang committed
315

xiongziliang committed
316
private:
xiongziliang committed
317
    uint8_t _payload_type;
318
    uint32_t _sample_rate;
xiongziliang committed
319 320 321 322 323 324 325 326
};

/**
* sdp中除音视频外的其他描述部分
*/
class TitleSdp : public Sdp{
public:

327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
    /**
     * 构造title类型sdp
     * @param dur_sec rtsp点播时长,0代表直播,单位秒
     * @param header 自定义sdp描述
     * @param version sdp版本
     */
    TitleSdp(float dur_sec = 0,
             const map<string,string> &header = map<string,string>(),
             int version = 0) : Sdp(0,0){
        _printer << "v=" << version << "\r\n";

        if(!header.empty()){
            for (auto &pr : header){
                _printer << pr.first << "=" << pr.second << "\r\n";
            }
        } else {
xiongziliang committed
343 344
            _printer << "o=- 0 0 IN IP4 0.0.0.0\r\n";
            _printer << "s=Streamed by " << SERVER_NAME << "\r\n";
345 346 347 348 349
            _printer << "c=IN IP4 0.0.0.0\r\n";
            _printer << "t=0 0\r\n";
        }

        if(dur_sec <= 0){
xiongziliang committed
350
            //直播
351
            _printer << "a=range:npt=now-\r\n";
352
        }else{
xiongziliang committed
353
            //点播
354
            _printer << "a=range:npt=0-" << dur_sec  << "\r\n";
355 356 357 358 359 360 361 362 363 364
        }
        _printer << "a=control:*\r\n";
    }
    string getSdp() const override {
        return _printer;
    }

    CodecId getCodecId() const override{
        return CodecInvalid;
    }
xiongziliang committed
365
private:
366
    _StrPrinter _printer;
xiongziliang committed
367 368
};

xiongziliang committed
369 370 371
//创建rtp over tcp4个字节的头
Buffer::Ptr makeRtpOverTcpPrefix(uint16_t size, uint8_t interleaved);
//创建rtp-rtcp端口对
372
void makeSockPair(std::pair<Socket::Ptr, Socket::Ptr> &pair, const string &local_ip);
xiongziliang committed
373
//十六进制方式打印ssrc
xiongziliang committed
374
string printSSRC(uint32_t ui32Ssrc);
375

xiongziliang committed
376
} //namespace mediakit
xzl committed
377
#endif //RTSP_RTSP_H_