H265.h 9.43 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 33 34
#include "Util/base64.h"
using namespace toolkit;
#define H265_TYPE(v) (((uint8_t)(v) >> 1) & 0x3f)
35

xiongziliang committed
36 37
namespace mediakit {

38 39 40 41 42 43 44
/**
* 265帧类
*/
class H265Frame : public Frame {
public:
    typedef std::shared_ptr<H265Frame> Ptr;

xiongziliang committed
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
    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();
75
    }
xiongziliang committed
76

77 78 79
    uint32_t size() const override {
        return buffer.size();
    }
xiongziliang committed
80

xiongziliang committed
81
    uint32_t dts() const override {
82 83
        return timeStamp;
    }
xiongziliang committed
84 85

    uint32_t prefixSize() const override {
86 87 88
        return iPrefixSize;
    }

xiongziliang committed
89
    TrackType getTrackType() const override {
90 91 92
        return TrackVideo;
    }

xiongziliang committed
93
    CodecId getCodecId() const override {
94 95 96 97
        return CodecH265;
    }

    bool keyFrame() const override {
xiongziliang committed
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
        return isKeyFrame(type);
    }

    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;
        }
113
    }
xiongziliang committed
114

115 116 117 118 119 120 121 122 123 124 125 126 127
public:
    uint16_t sequence;
    uint32_t timeStamp;
    unsigned char type;
    string buffer;
    uint32_t iPrefixSize = 4;
};


class H265FrameNoCopyAble : public FrameNoCopyAble {
public:
    typedef std::shared_ptr<H265FrameNoCopyAble> Ptr;

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

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

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

    bool keyFrame() const override {
xiongziliang committed
145
        int type = H265_TYPE(((uint8_t *) _ptr)[_prefixSize]);
xiongziliang committed
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
        return H265Frame::isKeyFrame(type);
    }
};


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

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

    /**
     * 构造h265类型的媒体
xiongziliang committed
166
     * @param vps vps帧数据
xiongziliang committed
167 168
     * @param sps sps帧数据
     * @param pps pps帧数据
xiongziliang committed
169
     * @param vps_prefix_len 265头长度,可以为3个或4个字节,一般为0x00 00 00 01
xiongziliang committed
170 171 172
     * @param sps_prefix_len 265头长度,可以为3个或4个字节,一般为0x00 00 00 01
     * @param pps_prefix_len 265头长度,可以为3个或4个字节,一般为0x00 00 00 01
     */
xiongziliang committed
173 174
    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
175 176 177 178 179
        _sps = sps.substr(sps_prefix_len);
        _pps = pps.substr(pps_prefix_len);
    }

    /**
xiongziliang committed
180 181
     * 返回不带0x00 00 00 01头的vps
     * @return
xiongziliang committed
182
     */
xiongziliang committed
183 184
    const string &getVps() const {
        return _vps;
xiongziliang committed
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
    }

    /**
     * 返回不带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;
    }

    bool ready() override {
xiongziliang committed
208
        return !_vps.empty() && !_sps.empty() && !_pps.empty();
209
    }
xiongziliang committed
210 211 212 213 214 215 216 217 218


    /**
     * 输入数据帧,并获取sps pps
     * @param frame 数据帧
     */
    void inputFrame(const Frame::Ptr &frame) override {
        int type = H265_TYPE(((uint8_t *) frame->data() + frame->prefixSize())[0]);
        if (H265Frame::isKeyFrame(type)) {
xiongziliang committed
219
            insertConfigFrame(frame);
xiongziliang committed
220
            VideoTrack::inputFrame(frame);
xiongziliang committed
221
            _last_frame_is_idr = true;
xiongziliang committed
222 223 224
            return;
        }

xiongziliang committed
225 226
        _last_frame_is_idr = false;

xiongziliang committed
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
        //非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;
        }
    }
private:
    Track::Ptr clone() override {
        return std::make_shared<std::remove_reference<decltype(*this)>::type>(*this);
    }

xiongziliang committed
258 259 260
    //生成sdp
    Sdp::Ptr getSdp() override ;

xiongziliang committed
261 262 263 264 265 266
    //在idr帧前插入vps sps pps帧
    void insertConfigFrame(const Frame::Ptr &frame){
        if(_last_frame_is_idr){
            return;
        }
        if(!_vps.empty()){
xiongziliang committed
267 268 269 270 271 272 273
            auto vpsFrame = std::make_shared<H265Frame>();
            vpsFrame->type = H265Frame::NAL_VPS;
            vpsFrame->iPrefixSize = 4;
            vpsFrame->buffer.assign("\x0\x0\x0\x1", 4);
            vpsFrame->buffer.append(_vps);
            vpsFrame->timeStamp = frame->stamp();
            VideoTrack::inputFrame(vpsFrame);
xiongziliang committed
274 275
        }
        if (!_sps.empty()) {
xiongziliang committed
276 277 278 279 280 281 282
            auto spsFrame = std::make_shared<H265Frame>();
            spsFrame->type = H265Frame::NAL_SPS;
            spsFrame->iPrefixSize = 4;
            spsFrame->buffer.assign("\x0\x0\x0\x1", 4);
            spsFrame->buffer.append(_sps);
            spsFrame->timeStamp = frame->stamp();
            VideoTrack::inputFrame(spsFrame);
xiongziliang committed
283 284 285
        }

        if (!_pps.empty()) {
xiongziliang committed
286 287 288 289 290 291 292
            auto ppsFrame = std::make_shared<H265Frame>();
            ppsFrame->type = H265Frame::NAL_PPS;
            ppsFrame->iPrefixSize = 4;
            ppsFrame->buffer.assign("\x0\x0\x0\x1", 4);
            ppsFrame->buffer.append(_pps);
            ppsFrame->timeStamp = frame->stamp();
            VideoTrack::inputFrame(ppsFrame);
xiongziliang committed
293 294
        }
    }
xiongziliang committed
295 296 297 298
private:
    string _vps;
    string _sps;
    string _pps;
xiongziliang committed
299
    bool _last_frame_is_idr = false;
300 301 302
};


303 304 305 306 307 308 309 310 311 312 313 314 315
/**
* 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
316 317
    H265Sdp(const string &strVPS,
            const string &strSPS,
318 319 320 321 322 323 324
            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
325 326 327 328
        _printer << "a=fmtp:" << playload_type << " ";
        _printer << "sprop-vps=";
        _printer << encodeBase64(strVPS) << "; ";
        _printer << "sprop-sps=";
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
        _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;
};


    
352 353 354 355
}//namespace mediakit


#endif //ZLMEDIAKIT_H265_H