H265.h 12.1 KB
Newer Older
1
/*
xiongziliang committed
2 3
* MIT License
*
xiongziliang committed
4
* Copyright (c) 2016-2019 xiongziliang <771730766@qq.com>
xiongziliang committed
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
*
* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
26 27 28 29 30 31

#ifndef ZLMEDIAKIT_H265_H
#define ZLMEDIAKIT_H265_H

#include "Frame.h"
#include "Track.h"
xiongziliang committed
32
#include "Util/base64.h"
33
#include "H264.h"
xiongziliang committed
34 35
using namespace toolkit;
#define H265_TYPE(v) (((uint8_t)(v) >> 1) & 0x3f)
36

xiongziliang committed
37 38
namespace mediakit {

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

41 42 43 44 45 46 47
/**
* 265帧类
*/
class H265Frame : public Frame {
public:
    typedef std::shared_ptr<H265Frame> Ptr;

xiongziliang committed
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
    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 {
        return (char *) buffer.data();
78
    }
xiongziliang committed
79

80 81 82
    uint32_t size() const override {
        return buffer.size();
    }
xiongziliang committed
83

xiongziliang committed
84
    uint32_t dts() const override {
85 86
        return timeStamp;
    }
xiongziliang committed
87

xiongziliang committed
88 89 90 91
    uint32_t pts() const override {
        return ptsStamp ? ptsStamp : timeStamp;
    }

xiongziliang committed
92
    uint32_t prefixSize() const override {
93 94 95
        return iPrefixSize;
    }

xiongziliang committed
96
    TrackType getTrackType() const override {
97 98 99
        return TrackVideo;
    }

xiongziliang committed
100
    CodecId getCodecId() const override {
101 102 103 104
        return CodecH265;
    }

    bool keyFrame() const override {
xiongziliang committed
105 106 107 108 109 110 111 112 113 114 115 116
        return isKeyFrame(H265_TYPE(buffer[iPrefixSize]));
    }

    bool configFrame() const override{
        switch(H265_TYPE(buffer[iPrefixSize])){
            case H265Frame::NAL_VPS:
            case H265Frame::NAL_SPS:
            case H265Frame::NAL_PPS:
                return true;
            default:
                return false;
        }
xiongziliang committed
117 118 119 120 121 122 123 124 125 126 127 128 129 130
    }

    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;
        }
131
    }
xiongziliang committed
132

133 134
public:
    uint32_t timeStamp;
xiongziliang committed
135
    uint32_t ptsStamp = 0;
136 137 138 139 140
    string buffer;
    uint32_t iPrefixSize = 4;
};


141
class H265FrameNoCacheAble : public FrameNoCacheAble {
142
public:
143
    typedef std::shared_ptr<H265FrameNoCacheAble> Ptr;
144

145
    H265FrameNoCacheAble(char *ptr, uint32_t size, uint32_t dts,uint32_t pts, int prefixeSize = 4) {
xiongziliang committed
146 147 148 149 150
        _ptr = ptr;
        _size = size;
        _dts = dts;
        _pts = pts;
        _prefixSize = prefixeSize;
151 152
    }

xiongziliang committed
153
    TrackType getTrackType() const override {
154 155 156
        return TrackVideo;
    }

xiongziliang committed
157
    CodecId getCodecId() const override {
158 159 160 161
        return CodecH265;
    }

    bool keyFrame() const override {
xiongziliang committed
162 163 164 165 166 167 168 169 170 171 172 173
        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
174 175 176
    }
};

177
typedef FrameInternal<H265FrameNoCacheAble> H265FrameInternal;
xiongziliang committed
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193

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

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

    /**
     * 构造h265类型的媒体
xiongziliang committed
194
     * @param vps vps帧数据
xiongziliang committed
195 196
     * @param sps sps帧数据
     * @param pps pps帧数据
xiongziliang committed
197
     * @param vps_prefix_len 265头长度,可以为3个或4个字节,一般为0x00 00 00 01
xiongziliang committed
198 199 200
     * @param sps_prefix_len 265头长度,可以为3个或4个字节,一般为0x00 00 00 01
     * @param pps_prefix_len 265头长度,可以为3个或4个字节,一般为0x00 00 00 01
     */
xiongziliang committed
201 202
    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
203 204
        _sps = sps.substr(sps_prefix_len);
        _pps = pps.substr(pps_prefix_len);
zqsong committed
205
		onReady();
xiongziliang committed
206 207 208
    }

    /**
xiongziliang committed
209 210
     * 返回不带0x00 00 00 01头的vps
     * @return
xiongziliang committed
211
     */
xiongziliang committed
212 213
    const string &getVps() const {
        return _vps;
xiongziliang committed
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
    }

    /**
     * 返回不带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
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
    /**
     * 返回视频高度
     * @return
     */
    int getVideoHeight() const override{
        return _height ;
    }

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

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

xiongziliang committed
260
    bool ready() override {
xiongziliang committed
261
        return !_vps.empty() && !_sps.empty() && !_pps.empty();
262
    }
xiongziliang committed
263 264 265


    /**
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
    * 输入数据帧,并获取sps pps
    * @param frame 数据帧
    */
    void inputFrame(const Frame::Ptr &frame) override{
        bool  first_frame = true;
        splitH264(frame->data() + frame->prefixSize(),
                  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);
                      }
                  });
    }

private:
    /**
xiongziliang committed
293 294 295
     * 输入数据帧,并获取sps pps
     * @param frame 数据帧
     */
296
    void inputFrame_l(const Frame::Ptr &frame) {
xiongziliang committed
297 298
        int type = H265_TYPE(((uint8_t *) frame->data() + frame->prefixSize())[0]);
        if (H265Frame::isKeyFrame(type)) {
xiongziliang committed
299
            insertConfigFrame(frame);
xiongziliang committed
300
            VideoTrack::inputFrame(frame);
xiongziliang committed
301
            _last_frame_is_idr = true;
xiongziliang committed
302 303 304
            return;
        }

xiongziliang committed
305 306
        _last_frame_is_idr = false;

xiongziliang committed
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
        //非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;
        }
    }
333

zqsong committed
334 335 336 337
	/**
     * 解析sps获取宽高fps
     */
    void onReady(){
xiongziliang committed
338
        getHEVCInfo(_vps, _sps, _width, _height, _fps);
zqsong committed
339
    }
xiongziliang committed
340 341 342 343
    Track::Ptr clone() override {
        return std::make_shared<std::remove_reference<decltype(*this)>::type>(*this);
    }

xiongziliang committed
344 345 346
    //生成sdp
    Sdp::Ptr getSdp() override ;

xiongziliang committed
347 348 349 350 351 352
    //在idr帧前插入vps sps pps帧
    void insertConfigFrame(const Frame::Ptr &frame){
        if(_last_frame_is_idr){
            return;
        }
        if(!_vps.empty()){
xiongziliang committed
353 354 355 356 357 358
            auto vpsFrame = std::make_shared<H265Frame>();
            vpsFrame->iPrefixSize = 4;
            vpsFrame->buffer.assign("\x0\x0\x0\x1", 4);
            vpsFrame->buffer.append(_vps);
            vpsFrame->timeStamp = frame->stamp();
            VideoTrack::inputFrame(vpsFrame);
xiongziliang committed
359 360
        }
        if (!_sps.empty()) {
xiongziliang committed
361 362 363 364 365 366
            auto spsFrame = std::make_shared<H265Frame>();
            spsFrame->iPrefixSize = 4;
            spsFrame->buffer.assign("\x0\x0\x0\x1", 4);
            spsFrame->buffer.append(_sps);
            spsFrame->timeStamp = frame->stamp();
            VideoTrack::inputFrame(spsFrame);
xiongziliang committed
367 368 369
        }

        if (!_pps.empty()) {
xiongziliang committed
370 371 372 373 374 375
            auto ppsFrame = std::make_shared<H265Frame>();
            ppsFrame->iPrefixSize = 4;
            ppsFrame->buffer.assign("\x0\x0\x0\x1", 4);
            ppsFrame->buffer.append(_pps);
            ppsFrame->timeStamp = frame->stamp();
            VideoTrack::inputFrame(ppsFrame);
xiongziliang committed
376 377
        }
    }
xiongziliang committed
378 379 380 381
private:
    string _vps;
    string _sps;
    string _pps;
zqsong committed
382 383 384
    int _width = 0;
    int _height = 0;	
    float _fps = 0;
xiongziliang committed
385
    bool _last_frame_is_idr = false;
386 387 388
};


389 390 391 392 393 394 395 396 397 398 399 400 401
/**
* 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
402 403
    H265Sdp(const string &strVPS,
            const string &strSPS,
404 405 406 407 408 409 410
            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
411 412 413 414
        _printer << "a=fmtp:" << playload_type << " ";
        _printer << "sprop-vps=";
        _printer << encodeBase64(strVPS) << "; ";
        _printer << "sprop-sps=";
415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437
        _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;
};


    
438 439 440 441
}//namespace mediakit


#endif //ZLMEDIAKIT_H265_H