H265Rtp.cpp 9.72 KB
Newer Older
1
/*
xiongziliang committed
2
 * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
3
 *
4
 * This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
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.
9 10
 */

xiongziliang committed
11
#include "H265Rtp.h"
12 13 14

namespace mediakit{

xiongziliang committed
15 16 17 18 19 20 21 22 23 24 25 26
//H265 nalu 头两个字节的定义
/*
 0               1
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |F|    Type   |  LayerId  | TID |
 +-------------+-----------------+
 Forbidden zero(F) : 1 bit
 NAL unit type(Type) : 6 bits
 NUH layer ID(LayerId) : 6 bits
 NUH temporal ID plus 1 (TID) : 3 bits
*/
27 28

H265RtpDecoder::H265RtpDecoder() {
xiongziliang committed
29
    _frame = obtainFrame();
30 31
}

32 33
H265Frame::Ptr H265RtpDecoder::obtainFrame() {
    auto frame = FrameImp::create<H265Frame>();
34
    frame->_prefix_size = 4;
35 36 37
    return frame;
}

xiongziliang committed
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 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 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
#define AV_RB16(x)                           \
    ((((const uint8_t*)(x))[0] << 8) |          \
      ((const uint8_t*)(x))[1])

#define CHECK_SIZE(total, size, ret) \
        if (total < size) {     \
            WarnL << "数据不够:" << total << " " << size; return ret; \
        }

// 4.4.2. Aggregation Packets (APs) (p25)
/*
 0               1               2               3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                          RTP Header                           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|      PayloadHdr (Type=48)     |           NALU 1 DONL         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           NALU 1 Size         |            NALU 1 HDR         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
|                         NALU 1 Data . . .                     |
|                                                               |
+     . . .     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|               |  NALU 2 DOND  |            NALU 2 Size        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          NALU 2 HDR           |                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+            NALU 2 Data        |
|                                                               |
|         . . .                 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                               :    ...OPTIONAL RTP padding    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
bool H265RtpDecoder::unpackAp(const uint8_t *ptr, ssize_t size, uint32_t stamp){
    bool have_key_frame = false;

    //忽略PayloadHdr
    CHECK_SIZE(size, 2, have_key_frame);
    ptr += 2;
    size -= 2;

    while (size) {
        if (_using_donl_field) {
            CHECK_SIZE(size, 2, have_key_frame);
            uint16_t donl = AV_RB16(ptr);
            size -= 2;
            ptr += 2;
        }
        CHECK_SIZE(size, 2, have_key_frame);
        uint16_t nalu_size = AV_RB16(ptr);
        size -= 2;
        ptr += 2;
        CHECK_SIZE(size, nalu_size, have_key_frame)
        if (singleFrame(ptr, nalu_size, stamp)) {
            have_key_frame = true;
        }
        size -= nalu_size;
        ptr += nalu_size;
    }
    return have_key_frame;
}

// 4.4.3. Fragmentation Units (p29)
/*
 0               1               2               3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|     PayloadHdr (Type=49)      |    FU header  |  DONL (cond)  |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
|  DONL (cond)  |                                               |
|-+-+-+-+-+-+-+-+                                               |
|                           FU payload                          |
|                                                               |
|                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                               :    ...OPTIONAL RTP padding    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|S|E|   FuType  |
+---------------+
*/

bool H265RtpDecoder::mergeFu(const uint8_t *ptr, ssize_t size, uint16_t seq, uint32_t stamp){
    CHECK_SIZE(size, 4, false);
    auto s_bit = ptr[2] >> 7;
    auto e_bit = (ptr[2] >> 6) & 0x01;
    auto type = ptr[2] & 0x3f;
    if (s_bit) {
        //该帧的第一个rtp包
        _frame->_buffer.assign("\x00\x00\x00\x01", 4);
        //恢复nalu头两个字节
        _frame->_buffer.push_back((type << 1) | (ptr[0] & 0x81));
        _frame->_buffer.push_back(ptr[1]);
    }

    if (!s_bit && seq != (uint16_t) (_last_seq + 1) && seq != 0) {
        //中间的或末尾的rtp包,其seq必须连续,否则说明rtp丢包,那么该帧不完整,必须得丢弃
        _frame->_buffer.clear();
        WarnL << "rtp丢包: " << seq << " != " << _last_seq << " + 1,该帧被废弃";
        return false;
    }

    //跳过PayloadHdr +  FU header
    ptr += 3;
    size -= 3;
    if (_using_donl_field) {
        //DONL确保不少于2个字节
        CHECK_SIZE(size, 2, false);
        uint16_t donl = AV_RB16(ptr);
        size -= 2;
        ptr += 2;
    }

    CHECK_SIZE(size, 1, false);

    if (!e_bit) {
        //非末尾包
        _last_seq = seq;
        _frame->_buffer.append((char *) ptr, size);
        return s_bit ? _frame->keyFrame() : false;
    }

    //该帧最后一个rtp包
    _frame->_pts = stamp;
    _frame->_buffer.append((char *) ptr, size);
    outputFrame(_frame);
    return false;
167 168
}

xiongziliang committed
169 170 171 172 173
bool H265RtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool ) {
    auto frame = rtp->getPayload();
    auto length = rtp->getPayloadSize();
    auto stamp = rtp->getStampMS();
    auto seq = rtp->getSeq();
174
    int nal = H265_TYPE(frame[0]);
175

176
    if (nal > 50){
xiongziliang committed
177
        // packet discard, Unsupported (HEVC) NAL type
178
        WarnL << "不支持该类型的265 RTP包" << nal;
xiongziliang committed
179
        return false;
180 181 182
    }
    switch (nal) {
        case 50:
xiongziliang committed
183
            //4.4.4. PACI Packets (p32)
184 185
            WarnL << "不支持该类型的265 RTP包" << nal;
            return false;
xiongziliang committed
186 187
        case 48:
            // aggregated packet (AP) - with two or more NAL units
xiongziliang committed
188
            return unpackAp(frame, length, stamp);
xiongziliang committed
189
        case 49: 
190
            // fragmentation unit (FU)
xiongziliang committed
191
            return mergeFu(frame, length, seq, stamp);
xiongziliang committed
192 193
        default: 
            // 4.4.1. Single NAL Unit Packets (p24)
xiongziliang committed
194
            return singleFrame(frame, length, stamp);
195 196 197
    }
}

xiongziliang committed
198 199 200 201 202 203 204 205 206 207 208
bool H265RtpDecoder::singleFrame(const uint8_t *ptr, ssize_t size, uint32_t stamp){
    //a full frame
    _frame->_buffer.assign("\x00\x00\x00\x01", 4);
    _frame->_buffer.append((char *) ptr, size);
    _frame->_pts = stamp;
    auto key = _frame->keyFrame();
    outputFrame(_frame);
    return key;
}

void H265RtpDecoder::outputFrame(const H265Frame::Ptr &frame) {
xiongziliang committed
209 210
    //rtsp没有dts,那么根据pts排序算法生成dts
    _dts_generator.getDts(frame->_pts,frame->_dts);
xiongziliang committed
211
    //输出frame
xiongziliang committed
212
    RtpCodec::inputFrame(frame);
xiongziliang committed
213
    _frame = obtainFrame();
214 215 216 217 218 219 220
}

////////////////////////////////////////////////////////////////////////

H265RtpEncoder::H265RtpEncoder(uint32_t ui32Ssrc,
                               uint32_t ui32MtuSize,
                               uint32_t ui32SampleRate,
xiongziliang committed
221
                               uint8_t ui8PayloadType,
222 223 224 225
                               uint8_t ui8Interleaved) :
        RtpInfo(ui32Ssrc,
                ui32MtuSize,
                ui32SampleRate,
xiongziliang committed
226
                ui8PayloadType,
227 228 229 230
                ui8Interleaved) {
}

void H265RtpEncoder::inputFrame(const Frame::Ptr &frame) {
231 232
    auto ptr = (uint8_t *) frame->data() + frame->prefixSize();
    auto len = frame->size() - frame->prefixSize();
xiongziliang committed
233
    auto pts = frame->pts();
234
    auto nal_type = H265_TYPE(ptr[0]); //获取NALU的5bit 帧类型
xiongziliang committed
235
    auto max_size = getMaxSize() - 3;
236

xiongziliang committed
237
    //超过MTU,按照FU方式打包
xiongziliang committed
238
    if (len > max_size + 2) {
239
        //获取帧头数据,1byte
xiongziliang committed
240
        unsigned char s_e_flags;
241 242
        bool fu_start = true;
        bool mark_bit = false;
243
        size_t offset = 2;
244
        while (!mark_bit) {
xiongziliang committed
245
            if (len <= offset + max_size) {
xiongziliang committed
246
                //FU end
247
                mark_bit = true;
xiongziliang committed
248
                max_size = len - offset;
249 250
                s_e_flags = (1 << 6) | nal_type;
            } else if (fu_start) {
xiongziliang committed
251
                //FU start
252
                s_e_flags = (1 << 7) | nal_type;
253
            } else {
xiongziliang committed
254
                //FU mid
255
                s_e_flags = nal_type;
256
            }
257

258 259
            {
                //传入nullptr先不做payload的内存拷贝
xiongziliang committed
260
                auto rtp = makeRtp(getTrackType(), nullptr, max_size + 3, mark_bit, pts);
261
                //rtp payload 负载部分
xiongziliang committed
262
                uint8_t *payload = rtp->getPayload();
xiongziliang committed
263
                //FU 第1个字节,表明为FU
264
                payload[0] = 49 << 1;
xiongziliang committed
265
                //FU 第2个字节貌似固定为1
266
                payload[1] = 1;
xiongziliang committed
267
                //FU 第3个字节
xiongziliang committed
268
                payload[2] = s_e_flags;
269
                //H265 数据
xiongziliang committed
270
                memcpy(payload + 3, ptr + offset, max_size);
271
                //输入到rtp环形缓存
272
                RtpCodec::inputRtp(rtp, fu_start && H265Frame::isKeyFrame(nal_type));
273 274
            }

xiongziliang committed
275
            offset += max_size;
276
            fu_start = false;
277 278
        }
    } else {
279
        makeH265Rtp(nal_type, ptr, len, false, true, pts);
280 281 282
    }
}

283
void H265RtpEncoder::makeH265Rtp(int nal_type,const void* data, size_t len, bool mark, bool first_packet, uint32_t uiStamp) {
284
    RtpCodec::inputRtp(makeRtp(getTrackType(),data,len,mark,uiStamp),first_packet && H265Frame::isKeyFrame(nal_type));
285 286
}

287
}//namespace mediakit