H265.h 11.5 KB
Newer Older
1
/*
xiongziliang committed
2 3 4 5 6 7 8 9
 * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
 *
 * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
 *
 * 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.
 */
10 11 12 13 14 15

#ifndef ZLMEDIAKIT_H265_H
#define ZLMEDIAKIT_H265_H

#include "Frame.h"
#include "Track.h"
xiongziliang committed
16
#include "Util/base64.h"
17
#include "H264.h"
xiongziliang committed
18 19
using namespace toolkit;
#define H265_TYPE(v) (((uint8_t)(v) >> 1) & 0x3f)
20

xiongziliang committed
21 22
namespace mediakit {

xiongziliang committed
23
bool getHEVCInfo(const string &strVps, const string &strSps, int &iVideoWidth, int &iVideoHeight, float &iVideoFps);
zqsong committed
24

25 26 27 28 29 30 31
/**
* 265帧类
*/
class H265Frame : public Frame {
public:
    typedef std::shared_ptr<H265Frame> Ptr;

xiongziliang committed
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
    typedef enum {
        NAL_TRAIL_N = 0,
        NAL_TRAIL_R = 1,
        NAL_TSA_N = 2,
        NAL_TSA_R = 3,
        NAL_STSA_N = 4,
        NAL_STSA_R = 5,
        NAL_RADL_N = 6,
        NAL_RADL_R = 7,
        NAL_RASL_N = 8,
        NAL_RASL_R = 9,
        NAL_BLA_W_LP = 16,
        NAL_BLA_W_RADL = 17,
        NAL_BLA_N_LP = 18,
        NAL_IDR_W_RADL = 19,
        NAL_IDR_N_LP = 20,
        NAL_CRA_NUT = 21,
        NAL_VPS = 32,
        NAL_SPS = 33,
        NAL_PPS = 34,
        NAL_AUD = 35,
        NAL_EOS_NUT = 36,
        NAL_EOB_NUT = 37,
        NAL_FD_NUT = 38,
        NAL_SEI_PREFIX = 39,
        NAL_SEI_SUFFIX = 40,
    } NaleType;

    char *data() const override {
61
        return (char *) _buffer.data();
62
    }
xiongziliang committed
63

64
    uint32_t size() const override {
65
        return _buffer.size();
66
    }
xiongziliang committed
67

xiongziliang committed
68
    uint32_t dts() const override {
69
        return _dts;
70
    }
xiongziliang committed
71

xiongziliang committed
72
    uint32_t pts() const override {
73
        return _pts ? _pts : _dts;
xiongziliang committed
74 75
    }

xiongziliang committed
76
    uint32_t prefixSize() const override {
77
        return _prefix_size;
78 79
    }

xiongziliang committed
80
    TrackType getTrackType() const override {
81 82 83
        return TrackVideo;
    }

xiongziliang committed
84
    CodecId getCodecId() const override {
85 86 87 88
        return CodecH265;
    }

    bool keyFrame() const override {
89
        return isKeyFrame(H265_TYPE(_buffer[_prefix_size]));
xiongziliang committed
90 91 92
    }

    bool configFrame() const override{
93
        switch(H265_TYPE(_buffer[_prefix_size])){
xiongziliang committed
94 95 96 97 98 99 100
            case H265Frame::NAL_VPS:
            case H265Frame::NAL_SPS:
            case H265Frame::NAL_PPS:
                return true;
            default:
                return false;
        }
xiongziliang committed
101 102 103 104 105 106 107 108 109 110 111 112 113 114
    }

    static bool isKeyFrame(int type) {
        switch (type) {
            case NAL_BLA_N_LP:
            case NAL_BLA_W_LP:
            case NAL_BLA_W_RADL:
            case NAL_CRA_NUT:
            case NAL_IDR_N_LP:
            case NAL_IDR_W_RADL:
                return true;
            default:
                return false;
        }
115
    }
xiongziliang committed
116

117
public:
118 119 120 121
    uint32_t _dts = 0;
    uint32_t _pts = 0;
    uint32_t _prefix_size = 4;
    string _buffer;
122 123 124
};


125
class H265FrameNoCacheAble : public FrameNoCacheAble {
126
public:
127
    typedef std::shared_ptr<H265FrameNoCacheAble> Ptr;
128

129
    H265FrameNoCacheAble(char *ptr, uint32_t size, uint32_t dts,uint32_t pts, int prefixeSize = 4) {
xiongziliang committed
130 131 132 133 134
        _ptr = ptr;
        _size = size;
        _dts = dts;
        _pts = pts;
        _prefixSize = prefixeSize;
135 136
    }

xiongziliang committed
137
    TrackType getTrackType() const override {
138 139 140
        return TrackVideo;
    }

xiongziliang committed
141
    CodecId getCodecId() const override {
142 143 144 145
        return CodecH265;
    }

    bool keyFrame() const override {
xiongziliang committed
146 147 148 149 150 151 152 153 154 155 156 157
        return H265Frame::isKeyFrame(H265_TYPE(((uint8_t *) _ptr)[_prefixSize]));
    }

    bool configFrame() const override{
        switch(H265_TYPE(((uint8_t *) _ptr)[_prefixSize])){
            case H265Frame::NAL_VPS:
            case H265Frame::NAL_SPS:
            case H265Frame::NAL_PPS:
                return true;
            default:
                return false;
        }
xiongziliang committed
158 159 160
    }
};

161
typedef FrameInternal<H265FrameNoCacheAble> H265FrameInternal;
xiongziliang committed
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177

/**
* 265视频通道
*/
class H265Track : public VideoTrack {
public:
    typedef std::shared_ptr<H265Track> Ptr;

    /**
     * 不指定sps pps构造h265类型的媒体
     * 在随后的inputFrame中获取sps pps
     */
    H265Track() {}

    /**
     * 构造h265类型的媒体
xiongziliang committed
178
     * @param vps vps帧数据
xiongziliang committed
179 180
     * @param sps sps帧数据
     * @param pps pps帧数据
xiongziliang committed
181
     * @param vps_prefix_len 265头长度,可以为3个或4个字节,一般为0x00 00 00 01
xiongziliang committed
182 183 184
     * @param sps_prefix_len 265头长度,可以为3个或4个字节,一般为0x00 00 00 01
     * @param pps_prefix_len 265头长度,可以为3个或4个字节,一般为0x00 00 00 01
     */
xiongziliang committed
185 186
    H265Track(const string &vps,const string &sps, const string &pps,int vps_prefix_len = 4, int sps_prefix_len = 4, int pps_prefix_len = 4) {
        _vps = vps.substr(vps_prefix_len);
xiongziliang committed
187 188
        _sps = sps.substr(sps_prefix_len);
        _pps = pps.substr(pps_prefix_len);
189
        onReady();
xiongziliang committed
190 191 192
    }

    /**
xiongziliang committed
193 194
     * 返回不带0x00 00 00 01头的vps
     * @return
xiongziliang committed
195
     */
xiongziliang committed
196 197
    const string &getVps() const {
        return _vps;
xiongziliang committed
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
    }

    /**
     * 返回不带0x00 00 00 01头的sps
     * @return
     */
    const string &getSps() const {
        return _sps;
    }

    /**
     * 返回不带0x00 00 00 01头的pps
     * @return
     */
    const string &getPps() const {
        return _pps;
    }

    CodecId getCodecId() const override {
        return CodecH265;
    }

zqsong committed
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
    /**
     * 返回视频高度
     * @return
     */
    int getVideoHeight() const override{
        return _height ;
    }

    /**
     * 返回视频宽度
     * @return
     */
    int getVideoWidth() const override{
        return _width;
    }

    /**
     * 返回视频fps
     * @return
     */
    float getVideoFps() const override{
        return _fps;
    }

xiongziliang committed
244
    bool ready() override {
xiongziliang committed
245
        return !_vps.empty() && !_sps.empty() && !_pps.empty();
246
    }
xiongziliang committed
247 248 249


    /**
250 251 252 253
    * 输入数据帧,并获取sps pps
    * @param frame 数据帧
    */
    void inputFrame(const Frame::Ptr &frame) override{
254
        int type = H265_TYPE(*((uint8_t *)frame->data() + frame->prefixSize()));
xiongziliang committed
255
        if(frame->configFrame()){
256 257
            bool  first_frame = true;
            splitH264(frame->data() + frame->prefixSize(),
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
                  frame->size() - frame->prefixSize(),
                  [&](const char *ptr, int len){
                      if(first_frame){
                          H265FrameInternal::Ptr sub_frame = std::make_shared<H265FrameInternal>(frame,
                                                                                                 frame->data(),
                                                                                                 len + frame->prefixSize(),
                                                                                                 frame->prefixSize());
                          inputFrame_l(sub_frame);
                          first_frame = false;
                      }else{
                          H265FrameInternal::Ptr sub_frame = std::make_shared<H265FrameInternal>(frame,
                                                                                                 (char *)ptr,
                                                                                                 len ,
                                                                                                 3);
                          inputFrame_l(sub_frame);
                      }
                  });
275 276 277
            }else{
                inputFrame_l(frame);
            }
278 279 280 281
    }

private:
    /**
xiongziliang committed
282 283 284
     * 输入数据帧,并获取sps pps
     * @param frame 数据帧
     */
285
    void inputFrame_l(const Frame::Ptr &frame) {
xiongziliang committed
286 287
        int type = H265_TYPE(((uint8_t *) frame->data() + frame->prefixSize())[0]);
        if (H265Frame::isKeyFrame(type)) {
xiongziliang committed
288
            insertConfigFrame(frame);
xiongziliang committed
289
            VideoTrack::inputFrame(frame);
xiongziliang committed
290
            _last_frame_is_idr = true;
xiongziliang committed
291 292 293
            return;
        }

xiongziliang committed
294 295
        _last_frame_is_idr = false;

xiongziliang committed
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
        //非idr帧
        switch (type) {
            case H265Frame::NAL_VPS: {
                //vps
                _vps = string(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize());
            }
                break;

            case H265Frame::NAL_SPS: {
                //sps
                _sps = string(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize());
            }
                break;
            case H265Frame::NAL_PPS: {
                //pps
                _pps = string(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize());
            }
                break;

            default: {
                //other frames
                VideoTrack::inputFrame(frame);
            }
                break;
        }
    }
322

323
    /**
zqsong committed
324 325 326
     * 解析sps获取宽高fps
     */
    void onReady(){
xiongziliang committed
327
        getHEVCInfo(_vps, _sps, _width, _height, _fps);
zqsong committed
328
    }
xiongziliang committed
329 330 331 332
    Track::Ptr clone() override {
        return std::make_shared<std::remove_reference<decltype(*this)>::type>(*this);
    }

xiongziliang committed
333 334 335
    //生成sdp
    Sdp::Ptr getSdp() override ;

xiongziliang committed
336 337 338 339 340 341
    //在idr帧前插入vps sps pps帧
    void insertConfigFrame(const Frame::Ptr &frame){
        if(_last_frame_is_idr){
            return;
        }
        if(!_vps.empty()){
xiongziliang committed
342
            auto vpsFrame = std::make_shared<H265Frame>();
343 344 345 346
            vpsFrame->_prefix_size = 4;
            vpsFrame->_buffer.assign("\x0\x0\x0\x1", 4);
            vpsFrame->_buffer.append(_vps);
            vpsFrame->_dts = frame->dts();
xiongziliang committed
347
            VideoTrack::inputFrame(vpsFrame);
xiongziliang committed
348 349
        }
        if (!_sps.empty()) {
xiongziliang committed
350
            auto spsFrame = std::make_shared<H265Frame>();
351 352 353 354
            spsFrame->_prefix_size = 4;
            spsFrame->_buffer.assign("\x0\x0\x0\x1", 4);
            spsFrame->_buffer.append(_sps);
            spsFrame->_dts = frame->dts();
xiongziliang committed
355
            VideoTrack::inputFrame(spsFrame);
xiongziliang committed
356 357 358
        }

        if (!_pps.empty()) {
xiongziliang committed
359
            auto ppsFrame = std::make_shared<H265Frame>();
360 361 362 363
            ppsFrame->_prefix_size = 4;
            ppsFrame->_buffer.assign("\x0\x0\x0\x1", 4);
            ppsFrame->_buffer.append(_pps);
            ppsFrame->_dts = frame->dts();
xiongziliang committed
364
            VideoTrack::inputFrame(ppsFrame);
xiongziliang committed
365 366
        }
    }
xiongziliang committed
367 368 369 370
private:
    string _vps;
    string _sps;
    string _pps;
zqsong committed
371 372 373
    int _width = 0;
    int _height = 0;	
    float _fps = 0;
xiongziliang committed
374
    bool _last_frame_is_idr = false;
375 376 377
};


378 379 380 381 382 383 384 385 386 387 388 389 390
/**
* h265类型sdp
*/
class H265Sdp : public Sdp {
public:

    /**
     *
     * @param sps 265 sps,不带0x00000001头
     * @param pps 265 pps,不带0x00000001头
     * @param playload_type  rtp playload type 默认96
     * @param bitrate 比特率
     */
xiongziliang committed
391 392
    H265Sdp(const string &strVPS,
            const string &strSPS,
393 394 395 396 397 398 399
            const string &strPPS,
            int playload_type = 96,
            int bitrate = 4000) : Sdp(90000,playload_type) {
        //视频通道
        _printer << "m=video 0 RTP/AVP " << playload_type << "\r\n";
        _printer << "b=AS:" << bitrate << "\r\n";
        _printer << "a=rtpmap:" << playload_type << " H265/" << 90000 << "\r\n";
xiongziliang committed
400 401 402 403
        _printer << "a=fmtp:" << playload_type << " ";
        _printer << "sprop-vps=";
        _printer << encodeBase64(strVPS) << "; ";
        _printer << "sprop-sps=";
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
        _printer << encodeBase64(strSPS) << "; ";
        _printer << "sprop-pps=";
        _printer << encodeBase64(strPPS) << "\r\n";
        _printer << "a=control:trackID=" << getTrackType() << "\r\n";
    }

    string getSdp() const override {
        return _printer;
    }

    TrackType getTrackType() const override {
        return TrackVideo;
    }

    CodecId getCodecId() const override {
        return CodecH265;
    }
private:
    _StrPrinter _printer;
};


    
427 428 429 430
}//namespace mediakit


#endif //ZLMEDIAKIT_H265_H