// // Copyright (c) 2013-2025 The SRS Authors // // SPDX-License-Identifier: MIT // #include #include #include #include using namespace std; #include #include #include #include #include #include SrsPps *_srs_pps_objs_rtps = NULL; SrsPps *_srs_pps_objs_rraw = NULL; SrsPps *_srs_pps_objs_rfua = NULL; SrsPps *_srs_pps_objs_rbuf = NULL; SrsPps *_srs_pps_objs_rothers = NULL; /* @see https://tools.ietf.org/html/rfc1889#section-5.1 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |V=2|P|X| CC |M| PT | sequence number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | timestamp | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | synchronization source (SSRC) identifier | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ | contributing source (CSRC) identifiers | | .... | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ uint32_t srs_rtp_fast_parse_ssrc(char *buf, int size) { if (size < 12) { return 0; } uint32_t value = 0; char *pp = (char *)&value; char *p = buf + 8; pp[3] = *p++; pp[2] = *p++; pp[1] = *p++; pp[0] = *p++; return value; } uint16_t srs_rtp_fast_parse_seq(char *buf, int size) { if (size < 4) { return 0; } return ((uint8_t)buf[2] << 8) | (uint8_t)buf[3]; } uint8_t srs_rtp_fast_parse_pt(char *buf, int size) { if (size < 12) { return 0; } return buf[1] & 0x7f; } srs_error_t srs_rtp_fast_parse_twcc(char *buf, int size, uint8_t twcc_id, uint16_t &twcc_sn) { srs_error_t err = srs_success; int need_size = 12 /*rtp head fix len*/ + 4 /* extension header len*/ + 3 /* twcc extension len*/; if (size < (need_size)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "required %d bytes, actual %d", need_size, size); } uint8_t first = buf[0]; bool extension = (first & 0x10); uint8_t cc = (first & 0x0F); if (!extension) { return srs_error_new(ERROR_RTC_RTP, "no extension in rtp"); } need_size += cc * 4; // csrc size if (size < (need_size)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "required %d bytes, actual %d", need_size, size); } buf += 12 + 4 * cc; uint16_t value = *((uint16_t *)buf); value = ntohs(value); if (0xBEDE != value) { return srs_error_new(ERROR_RTC_RTP_MUXER, "no support this type(0x%02x) extension", value); } buf += 2; uint16_t extension_length = ntohs(*((uint16_t *)buf)); buf += 2; extension_length *= 4; need_size += extension_length; // entension size if (size < (need_size)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "required %d bytes, actual %d", need_size, size); } while (extension_length > 0) { uint8_t v = buf[0]; buf++; extension_length--; if (0 == v) { continue; } uint8_t id = (v & 0xF0) >> 4; uint8_t len = (v & 0x0F) + 1; if (id == twcc_id) { twcc_sn = ntohs(*((uint16_t *)buf)); return err; } else { buf += len; extension_length -= len; } } return err; } // If value is newer than pre_value,return true; otherwise false bool srs_seq_is_newer(uint16_t value, uint16_t pre_value) { return srs_rtp_seq_distance(pre_value, value) > 0; } bool srs_seq_is_rollback(uint16_t value, uint16_t pre_value) { if (srs_seq_is_newer(value, pre_value)) { return pre_value > value; } return false; } // If value is newer then pre_value, return positive, otherwise negative. int32_t srs_seq_distance(uint16_t value, uint16_t pre_value) { return srs_rtp_seq_distance(pre_value, value); } SrsRtpExtensionTypes::SrsRtpExtensionTypes() { memset(ids_, kRtpExtensionNone, sizeof(ids_)); } SrsRtpExtensionTypes::~SrsRtpExtensionTypes() { } bool SrsRtpExtensionTypes::register_by_uri(int id, std::string uri) { for (int i = 0; i < (int)(sizeof(kExtensions) / sizeof(kExtensions[0])); ++i) { if (kExtensions[i].uri == uri) { return register_id(id, kExtensions[i].type, kExtensions[i].uri); } } return false; } bool SrsRtpExtensionTypes::register_id(int id, SrsRtpExtensionType type, std::string uri) { if (id < 1 || id > 255) { return false; } ids_[type] = static_cast(id); return true; } SrsRtpExtensionType SrsRtpExtensionTypes::get_type(int id) const { for (int type = kRtpExtensionNone + 1; type < kRtpExtensionNumberOfExtensions; ++type) { if (ids_[type] == id) { return static_cast(type); } } return kInvalidType; } SrsRtpExtensionTwcc::SrsRtpExtensionTwcc() { has_twcc_ = false; id_ = 0; sn_ = 0; } SrsRtpExtensionTwcc::~SrsRtpExtensionTwcc() { } srs_error_t SrsRtpExtensionTwcc::decode(SrsBuffer *buf) { srs_error_t err = srs_success; // 0 1 2 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ID | L=1 |transport wide sequence number | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ if (!buf->require(1)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 1); } uint8_t v = buf->read_1bytes(); id_ = (v & 0xF0) >> 4; uint8_t len = (v & 0x0F); if (!id_ || len != 1) { return srs_error_new(ERROR_RTC_RTP, "invalid twcc id=%d, len=%d", id_, len); } if (!buf->require(2)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 2); } sn_ = buf->read_2bytes(); has_twcc_ = true; return err; } uint64_t SrsRtpExtensionTwcc::nb_bytes() { return 3; } srs_error_t SrsRtpExtensionTwcc::encode(SrsBuffer *buf) { srs_error_t err = srs_success; if (!buf->require(3)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 3); } uint8_t id_len = (id_ & 0x0F) << 4 | 0x01; buf->write_1bytes(id_len); buf->write_2bytes(sn_); return err; } uint8_t SrsRtpExtensionTwcc::get_id() { return id_; } void SrsRtpExtensionTwcc::set_id(uint8_t id) { id_ = id; has_twcc_ = true; } uint16_t SrsRtpExtensionTwcc::get_sn() { return sn_; } void SrsRtpExtensionTwcc::set_sn(uint16_t sn) { sn_ = sn; has_twcc_ = true; } SrsRtpExtensionOneByte::SrsRtpExtensionOneByte() { has_ext_ = false; id_ = 0; value_ = 0; } SrsRtpExtensionOneByte::~SrsRtpExtensionOneByte() { } void SrsRtpExtensionOneByte::set_id(int id) { id_ = id; has_ext_ = true; } void SrsRtpExtensionOneByte::set_value(uint8_t value) { value_ = value; has_ext_ = true; } srs_error_t SrsRtpExtensionOneByte::decode(SrsBuffer *buf) { srs_error_t err = srs_success; if (!buf->require(2)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 2); } uint8_t v = buf->read_1bytes(); id_ = (v & 0xF0) >> 4; uint8_t len = (v & 0x0F); if (!id_ || len != 0) { return srs_error_new(ERROR_RTC_RTP, "invalid rtp extension id=%d, len=%d", id_, len); } value_ = buf->read_1bytes(); has_ext_ = true; return err; } srs_error_t SrsRtpExtensionOneByte::encode(SrsBuffer *buf) { srs_error_t err = srs_success; if (!buf->require(2)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 2); } uint8_t id_len = (id_ & 0x0F) << 4 | 0x00; buf->write_1bytes(id_len); buf->write_1bytes(value_); return err; } SrsRtpExtensions::SrsRtpExtensions() { types_ = NULL; has_ext_ = false; decode_twcc_extension_ = false; } SrsRtpExtensions::~SrsRtpExtensions() { } srs_error_t SrsRtpExtensions::decode(SrsBuffer *buf) { srs_error_t err = srs_success; /* @see https://tools.ietf.org/html/rfc3550#section-5.3.1 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | defined by profile | length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | header extension | | .... | */ if (!buf->require(4)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires 4 bytes"); } uint16_t profile_id = buf->read_2bytes(); uint16_t extension_length = buf->read_2bytes(); // @see: https://tools.ietf.org/html/rfc5285#section-4.2 if (profile_id == 0xBEDE) { SrsBuffer xbuf(buf->head(), extension_length * 4); buf->skip(extension_length * 4); return decode_0xbede(&xbuf); } else if (profile_id == 0x1000) { buf->skip(extension_length * 4); } else { return srs_error_new(ERROR_RTC_RTP_MUXER, "fail to parse extension"); } return err; } srs_error_t SrsRtpExtensions::decode_0xbede(SrsBuffer *buf) { srs_error_t err = srs_success; while (!buf->empty()) { // The first byte maybe padding or id+len. if (!buf->require(1)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 1); } uint8_t v = *((uint8_t *)buf->head()); // Padding, ignore if (v == 0) { buf->skip(1); continue; } // 0 // 0 1 2 3 4 5 6 7 // +-+-+-+-+-+-+-+-+ // | ID | len | // +-+-+-+-+-+-+-+-+ // Note that 'len' is the header extension element length, which is the // number of bytes - 1. uint8_t id = (v & 0xF0) >> 4; uint8_t len = (v & 0x0F) + 1; SrsRtpExtensionType xtype = types_ ? types_->get_type(id) : kRtpExtensionNone; if (xtype == kRtpExtensionTransportSequenceNumber) { if (decode_twcc_extension_) { if ((err = twcc_.decode(buf)) != srs_success) { return srs_error_wrap(err, "decode twcc extension"); } has_ext_ = true; } else { if (!buf->require(len + 1)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", len + 1); } buf->skip(len + 1); } } else if (xtype == kRtpExtensionAudioLevel) { if ((err = audio_level_.decode(buf)) != srs_success) { return srs_error_wrap(err, "decode audio level extension"); } has_ext_ = true; } else { buf->skip(1 + len); } } return err; } uint64_t SrsRtpExtensions::nb_bytes() { int size = 4 + (twcc_.exists() ? twcc_.nb_bytes() : 0); size += (audio_level_.exists() ? audio_level_.nb_bytes() : 0); // add padding size += (size % 4 == 0) ? 0 : (4 - size % 4); return size; } srs_error_t SrsRtpExtensions::encode(SrsBuffer *buf) { srs_error_t err = srs_success; buf->write_2bytes(0xBEDE); // Write length. int len = 0; if (twcc_.exists()) { len += twcc_.nb_bytes(); } if (audio_level_.exists()) { len += audio_level_.nb_bytes(); } int padding_count = (len % 4 == 0) ? 0 : (4 - len % 4); len += padding_count; if (!buf->require(len)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", len); } buf->write_2bytes(len / 4); // Write extensions. if (twcc_.exists()) { if ((err = twcc_.encode(buf)) != srs_success) { return srs_error_wrap(err, "encode twcc extension"); } } if (audio_level_.exists()) { if (srs_success != (err = audio_level_.encode(buf))) { return srs_error_wrap(err, "encode audio level extension"); } } // add padding if (padding_count) { memset(buf->head(), 0, padding_count); buf->skip(padding_count); } return err; } void SrsRtpExtensions::set_types_(SrsRtpExtensionTypes *types) { types_ = types; } srs_error_t SrsRtpExtensions::get_twcc_sequence_number(uint16_t &twcc_sn) { if (twcc_.exists()) { twcc_sn = twcc_.get_sn(); return srs_success; } return srs_error_new(ERROR_RTC_RTP_MUXER, "not find twcc sequence number"); } srs_error_t SrsRtpExtensions::set_twcc_sequence_number(uint8_t id, uint16_t sn) { has_ext_ = true; twcc_.set_id(id); twcc_.set_sn(sn); return srs_success; } srs_error_t SrsRtpExtensions::get_audio_level(uint8_t &level) { if (audio_level_.exists()) { level = audio_level_.get_value(); return srs_success; } return srs_error_new(ERROR_RTC_RTP_MUXER, "not find rtp extension audio level"); } srs_error_t SrsRtpExtensions::set_audio_level(int id, uint8_t level) { has_ext_ = true; audio_level_.set_id(id); audio_level_.set_value(level); return srs_success; } SrsRtpHeader::SrsRtpHeader() { cc_ = 0; marker_ = false; payload_type_ = 0; sequence_ = 0; timestamp_ = 0; ssrc_ = 0; padding_length_ = 0; ignore_padding_ = false; memset(csrc_, 0, sizeof(csrc_)); } SrsRtpHeader::~SrsRtpHeader() { } srs_error_t SrsRtpHeader::decode(SrsBuffer *buf) { srs_error_t err = srs_success; if (!buf->require(kRtpHeaderFixedSize)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d+ bytes", kRtpHeaderFixedSize); } /* @see https://tools.ietf.org/html/rfc1889#section-5.1 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |V=2|P|X| CC |M| PT | sequence number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | timestamp | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | synchronization source (SSRC) identifier | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ | contributing source (CSRC) identifiers | | .... | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ uint8_t first = buf->read_1bytes(); bool padding = (first & 0x20); bool extension = (first & 0x10); cc_ = (first & 0x0F); uint8_t second = buf->read_1bytes(); marker_ = (second & 0x80); payload_type_ = (second & 0x7F); sequence_ = buf->read_2bytes(); timestamp_ = buf->read_4bytes(); ssrc_ = buf->read_4bytes(); int ext_bytes = nb_bytes() - kRtpHeaderFixedSize; if (!buf->require(ext_bytes)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d+ bytes", ext_bytes); } for (uint8_t i = 0; i < cc_; ++i) { csrc_[i] = buf->read_4bytes(); } if (extension) { if ((err = parse_extensions(buf)) != srs_success) { return srs_error_wrap(err, "fail to parse extension"); } } if (padding && !ignore_padding_ && !buf->empty()) { padding_length_ = *(reinterpret_cast(buf->data() + buf->size() - 1)); if (!buf->require(padding_length_)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "padding requires %d bytes", padding_length_); } } return err; } srs_error_t SrsRtpHeader::parse_extensions(SrsBuffer *buf) { srs_error_t err = srs_success; if (srs_success != (err = extensions_.decode(buf))) { return srs_error_wrap(err, "decode rtp extension"); } return err; } srs_error_t SrsRtpHeader::encode(SrsBuffer *buf) { srs_error_t err = srs_success; // Encode the RTP fix header, 12bytes. // @see https://tools.ietf.org/html/rfc1889#section-5.1 // The version, padding, extension and cc, total 1 byte. uint8_t v = 0x80 | cc_; if (padding_length_ > 0) { v |= 0x20; } if (extensions_.exists()) { v |= 0x10; } buf->write_1bytes(v); // The marker and payload type, total 1 byte. v = payload_type_; if (marker_) { v |= kRtpMarker; } buf->write_1bytes(v); // The sequence number, 2 bytes. buf->write_2bytes(sequence_); // The timestamp, 4 bytes. buf->write_4bytes(timestamp_); // The SSRC, 4 bytes. buf->write_4bytes(ssrc_); // The CSRC list: 0 to 15 items, each is 4 bytes. for (size_t i = 0; i < cc_; ++i) { buf->write_4bytes(csrc_[i]); } if (extensions_.exists()) { if (srs_success != (err = extensions_.encode(buf))) { return srs_error_wrap(err, "encode rtp extension"); } } return err; } void SrsRtpHeader::set_extensions(SrsRtpExtensionTypes *extmap) { if (extmap) { extensions_.set_types_(extmap); } } void SrsRtpHeader::ignore_padding(bool v) { ignore_padding_ = v; } srs_error_t SrsRtpHeader::get_twcc_sequence_number(uint16_t &twcc_sn) { if (extensions_.exists()) { return extensions_.get_twcc_sequence_number(twcc_sn); } return srs_error_new(ERROR_RTC_RTP_MUXER, "no rtp extension"); } srs_error_t SrsRtpHeader::set_twcc_sequence_number(uint8_t id, uint16_t sn) { return extensions_.set_twcc_sequence_number(id, sn); } uint64_t SrsRtpHeader::nb_bytes() { return kRtpHeaderFixedSize + cc_ * 4 + (extensions_.exists() ? extensions_.nb_bytes() : 0); } void SrsRtpHeader::set_marker(bool v) { marker_ = v; } bool SrsRtpHeader::get_marker() const { return marker_; } void SrsRtpHeader::set_payload_type(uint8_t v) { payload_type_ = v; } uint8_t SrsRtpHeader::get_payload_type() const { return payload_type_; } void SrsRtpHeader::set_sequence(uint16_t v) { sequence_ = v; } uint16_t SrsRtpHeader::get_sequence() const { return sequence_; } void SrsRtpHeader::set_timestamp(uint32_t v) { timestamp_ = v; } uint32_t SrsRtpHeader::get_timestamp() const { return timestamp_; } void SrsRtpHeader::set_ssrc(uint32_t v) { ssrc_ = v; } void SrsRtpHeader::set_padding(uint8_t v) { padding_length_ = v; } uint8_t SrsRtpHeader::get_padding() const { return padding_length_; } ISrsRtpPayloader::ISrsRtpPayloader() { } ISrsRtpPayloader::~ISrsRtpPayloader() { } ISrsRtpPacketDecodeHandler::ISrsRtpPacketDecodeHandler() { } ISrsRtpPacketDecodeHandler::~ISrsRtpPacketDecodeHandler() { } SrsRtpPacket::SrsRtpPacket() { payload_ = NULL; payload_type_ = SrsRtpPacketPayloadTypeUnknown; shared_buffer_ = SrsSharedPtr(NULL); actual_buffer_size_ = 0; nalu_type_ = 0; frame_type_ = SrsFrameTypeReserved; cached_payload_size_ = 0; decode_handler_ = NULL; avsync_time_ = -1; ++_srs_pps_objs_rtps->sugar_; } SrsRtpPacket::~SrsRtpPacket() { srs_freep(payload_); // shared_buffer_ automatically cleaned up by SrsSharedPtr } char *SrsRtpPacket::wrap(int size) { // The buffer size is larger or equals to the size of packet. actual_buffer_size_ = size; // If the buffer is large enough, reuse it. if (shared_buffer_.get() && shared_buffer_->size() >= size) { return shared_buffer_->payload(); } // Create a large enough memory block, with under-layer buffer. shared_buffer_ = SrsSharedPtr(new SrsMemoryBlock()); // Create under-layer buffer for new memory block // For RTC, we use larger under-layer buffer for each packet. int nb_buffer = srs_max(size, kRtpPacketSize); char *buf = new char[nb_buffer]; shared_buffer_->attach(buf, nb_buffer); ++_srs_pps_objs_rbuf->sugar_; return shared_buffer_->payload(); } char *SrsRtpPacket::wrap(char *data, int size) { char *buf = wrap(size); memcpy(buf, data, size); return buf; } char *SrsRtpPacket::wrap(SrsSharedPtr block) { // Copy the shared memory block. shared_buffer_ = block; // If we wrap a memory block, the size of packet equals to the block size. actual_buffer_size_ = shared_buffer_.get() ? shared_buffer_->size() : 0; return shared_buffer_.get() ? shared_buffer_->payload() : NULL; } SrsRtpPacket *SrsRtpPacket::copy() { SrsRtpPacket *cp = new SrsRtpPacket(); cp->header_ = header_; cp->payload_ = payload_ ? payload_->copy() : NULL; cp->payload_type_ = payload_type_; cp->nalu_type_ = nalu_type_; cp->shared_buffer_ = shared_buffer_; // Copy shared pointer cp->actual_buffer_size_ = actual_buffer_size_; cp->frame_type_ = frame_type_; cp->cached_payload_size_ = cached_payload_size_; // For performance issue, do not copy the unused field. cp->decode_handler_ = decode_handler_; cp->avsync_time_ = avsync_time_; return cp; } void SrsRtpPacket::set_padding(int size) { header_.set_padding(size); if (cached_payload_size_) { cached_payload_size_ += size - header_.get_padding(); } } void SrsRtpPacket::add_padding(int size) { header_.set_padding(header_.get_padding() + size); if (cached_payload_size_) { cached_payload_size_ += size; } } void SrsRtpPacket::set_decode_handler(ISrsRtpPacketDecodeHandler *h) { decode_handler_ = h; } bool SrsRtpPacket::is_audio() { return frame_type_ == SrsFrameTypeAudio; } void SrsRtpPacket::set_extension_types(SrsRtpExtensionTypes *v) { return header_.set_extensions(v); } uint64_t SrsRtpPacket::nb_bytes() { if (!cached_payload_size_) { int nn_payload = (payload_ ? payload_->nb_bytes() : 0); cached_payload_size_ = header_.nb_bytes() + nn_payload + header_.get_padding(); } return cached_payload_size_; } srs_error_t SrsRtpPacket::encode(SrsBuffer *buf) { srs_error_t err = srs_success; if ((err = header_.encode(buf)) != srs_success) { return srs_error_wrap(err, "rtp header"); } if (payload_ && (err = payload_->encode(buf)) != srs_success) { return srs_error_wrap(err, "rtp payload"); } if (header_.get_padding() > 0) { uint8_t padding = header_.get_padding(); if (!buf->require(padding)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", padding); } memset(buf->head(), padding, padding); buf->skip(padding); } return err; } srs_error_t SrsRtpPacket::decode(SrsBuffer *buf) { srs_error_t err = srs_success; if ((err = header_.decode(buf)) != srs_success) { return srs_error_wrap(err, "rtp header"); } // We must skip the padding bytes before parsing payload. uint8_t padding = header_.get_padding(); if (!buf->require(padding)) { return srs_error_wrap(err, "requires padding %d bytes", padding); } buf->set_size(buf->size() - padding); // TODO: FIXME: We should keep payload to NULL and return if buffer is empty. // If user set the decode handler, call it to set the payload. if (decode_handler_) { decode_handler_->on_before_decode_payload(this, buf, &payload_, &payload_type_); } // By default, we always use the RAW payload. if (!payload_) { payload_ = new SrsRtpRawPayload(); payload_type_ = SrsRtpPacketPayloadTypeRaw; } if ((err = payload_->decode(buf)) != srs_success) { return srs_error_wrap(err, "rtp payload"); } return err; } bool srs_rtp_packet_h264_is_keyframe(uint8_t nalu_type, ISrsRtpPayloader *payload) { if (nalu_type == kStapA) { SrsRtpSTAPPayload *stap_payload = dynamic_cast(payload); if (NULL != stap_payload->get_sps() || NULL != stap_payload->get_pps()) { return true; } } else if (nalu_type == kFuA) { SrsRtpFUAPayload2 *fua_payload = dynamic_cast(payload); if (SrsAvcNaluTypeIDR == fua_payload->nalu_type_) { return true; } } else { if ((SrsAvcNaluTypeIDR == nalu_type) || (SrsAvcNaluTypeSPS == nalu_type) || (SrsAvcNaluTypePPS == nalu_type)) { return true; } } return false; } bool srs_rtp_packet_h265_is_keyframe(uint8_t nalu_type, ISrsRtpPayloader *payload) { if (nalu_type == kStapHevc) { SrsRtpSTAPPayloadHevc *stap_payload = dynamic_cast(payload); if (stap_payload->get_vps() || stap_payload->get_sps() || stap_payload->get_pps()) { return true; } } else if (nalu_type == kFuHevc) { SrsRtpFUAPayloadHevc2 *fua_payload = dynamic_cast(payload); if (SrsIsIRAP(fua_payload->nalu_type_)) { return true; } } else { if (SrsIsIRAP(nalu_type) || (SrsHevcNaluType_VPS == nalu_type) || (SrsHevcNaluType_SPS == nalu_type) || (SrsHevcNaluType_PPS == nalu_type)) { return true; } } return false; } bool SrsRtpPacket::is_keyframe(SrsVideoCodecId codec_id) { // False if audio packet if (SrsFrameTypeAudio == frame_type_) { return false; } // For H264 video rtp packet if (codec_id == SrsVideoCodecIdAVC) { return srs_rtp_packet_h264_is_keyframe(nalu_type_, payload_); } // For H265 video rtp packet if (codec_id == SrsVideoCodecIdHEVC) { return srs_rtp_packet_h265_is_keyframe(nalu_type_, payload_); } return false; } SrsRtpRawPayload::SrsRtpRawPayload() { payload_ = NULL; nn_payload_ = 0; sample_ = new SrsNaluSample(); ++_srs_pps_objs_rraw->sugar_; } SrsRtpRawPayload::~SrsRtpRawPayload() { srs_freep(sample_); } uint64_t SrsRtpRawPayload::nb_bytes() { return nn_payload_; } srs_error_t SrsRtpRawPayload::encode(SrsBuffer *buf) { if (nn_payload_ <= 0) { return srs_success; } if (!buf->require(nn_payload_)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", nn_payload_); } buf->write_bytes(payload_, nn_payload_); return srs_success; } srs_error_t SrsRtpRawPayload::decode(SrsBuffer *buf) { if (buf->empty()) { return srs_success; } payload_ = buf->head(); nn_payload_ = buf->left(); sample_->bytes_ = payload_; sample_->size_ = nn_payload_; return srs_success; } ISrsRtpPayloader *SrsRtpRawPayload::copy() { SrsRtpRawPayload *cp = new SrsRtpRawPayload(); cp->payload_ = payload_; cp->nn_payload_ = nn_payload_; // free sample to prevent memory leak. srs_freep(cp->sample_); cp->sample_ = sample_->copy(); return cp; } SrsRtpRawNALUs::SrsRtpRawNALUs() { cursor_ = 0; nn_bytes_ = 0; ++_srs_pps_objs_rothers->sugar_; } SrsRtpRawNALUs::~SrsRtpRawNALUs() { int nn_nalus = (int)nalus_.size(); for (int i = 0; i < nn_nalus; i++) { SrsNaluSample *p = nalus_[i]; srs_freep(p); } } void SrsRtpRawNALUs::push_back(SrsNaluSample *sample) { if (sample->size_ <= 0) { return; } if (!nalus_.empty()) { SrsNaluSample *p = new SrsNaluSample(); p->bytes_ = (char *)"\0\0\1"; p->size_ = 3; nn_bytes_ += 3; nalus_.push_back(p); } nn_bytes_ += sample->size_; nalus_.push_back(sample); } uint8_t SrsRtpRawNALUs::skip_bytes(int count) { srs_assert(cursor_ >= 0 && nn_bytes_ > 0 && cursor_ + count < nn_bytes_); cursor_ += count; return uint8_t(nalus_[0]->bytes_[0]); } srs_error_t SrsRtpRawNALUs::read_samples(vector &samples, int packet_size) { if (cursor_ + packet_size < 0 || cursor_ + packet_size > nn_bytes_) { return srs_error_new(ERROR_RTC_RTP_MUXER, "cursor=%d, max=%d, size=%d", cursor_, nn_bytes_, packet_size); } int pos = cursor_; cursor_ += packet_size; int left = packet_size; int nn_nalus = (int)nalus_.size(); for (int i = 0; left > 0 && i < nn_nalus; i++) { SrsNaluSample *p = nalus_[i]; // Ignore previous consumed samples. if (pos && pos - p->size_ >= 0) { pos -= p->size_; continue; } // Now, we are working at the sample. int nn = srs_min(left, p->size_ - pos); srs_assert(nn > 0); SrsNaluSample *sample = new SrsNaluSample(); samples.push_back(sample); sample->bytes_ = p->bytes_ + pos; sample->size_ = nn; left -= nn; pos = 0; } return srs_success; } uint64_t SrsRtpRawNALUs::nb_bytes() { int size = 0; int nn_nalus = (int)nalus_.size(); for (int i = 0; i < nn_nalus; i++) { SrsNaluSample *p = nalus_[i]; size += p->size_; } return size; } srs_error_t SrsRtpRawNALUs::encode(SrsBuffer *buf) { int nn_nalus = (int)nalus_.size(); for (int i = 0; i < nn_nalus; i++) { SrsNaluSample *p = nalus_[i]; if (!buf->require(p->size_)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", p->size_); } buf->write_bytes(p->bytes_, p->size_); } return srs_success; } srs_error_t SrsRtpRawNALUs::decode(SrsBuffer *buf) { if (buf->empty()) { return srs_success; } SrsNaluSample *sample = new SrsNaluSample(); sample->bytes_ = buf->head(); sample->size_ = buf->left(); buf->skip(sample->size_); nalus_.push_back(sample); return srs_success; } ISrsRtpPayloader *SrsRtpRawNALUs::copy() { SrsRtpRawNALUs *cp = new SrsRtpRawNALUs(); cp->nn_bytes_ = nn_bytes_; cp->cursor_ = cursor_; int nn_nalus = (int)nalus_.size(); for (int i = 0; i < nn_nalus; i++) { SrsNaluSample *p = nalus_[i]; cp->nalus_.push_back(p->copy()); } return cp; } SrsRtpSTAPPayload::SrsRtpSTAPPayload() { nri_ = (SrsAvcNaluType)0; ++_srs_pps_objs_rothers->sugar_; } SrsRtpSTAPPayload::~SrsRtpSTAPPayload() { int nn_nalus = (int)nalus_.size(); for (int i = 0; i < nn_nalus; i++) { SrsNaluSample *p = nalus_[i]; srs_freep(p); } } SrsNaluSample *SrsRtpSTAPPayload::get_sps() { int nn_nalus = (int)nalus_.size(); for (int i = 0; i < nn_nalus; i++) { SrsNaluSample *p = nalus_[i]; if (!p || !p->size_) { continue; } SrsAvcNaluType nalu_type = SrsAvcNaluTypeParse(p->bytes_[0]); if (nalu_type == SrsAvcNaluTypeSPS) { return p; } } return NULL; } SrsNaluSample *SrsRtpSTAPPayload::get_pps() { int nn_nalus = (int)nalus_.size(); for (int i = 0; i < nn_nalus; i++) { SrsNaluSample *p = nalus_[i]; if (!p || !p->size_) { continue; } SrsAvcNaluType nalu_type = SrsAvcNaluTypeParse(p->bytes_[0]); if (nalu_type == SrsAvcNaluTypePPS) { return p; } } return NULL; } SrsNaluSample *SrsRtpSTAPPayload::get_idr() { int nn_nalus = (int)nalus_.size(); for (int i = 0; i < nn_nalus; i++) { SrsNaluSample *p = nalus_[i]; if (!p || !p->size_) { continue; } SrsAvcNaluType nalu_type = SrsAvcNaluTypeParse(p->bytes_[0]); if (nalu_type == SrsAvcNaluTypeIDR) { return p; } } return NULL; } uint64_t SrsRtpSTAPPayload::nb_bytes() { int size = 1; int nn_nalus = (int)nalus_.size(); for (int i = 0; i < nn_nalus; i++) { SrsNaluSample *p = nalus_[i]; size += 2 + p->size_; } return size; } srs_error_t SrsRtpSTAPPayload::encode(SrsBuffer *buf) { if (!buf->require(1)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 1); } // STAP header, RTP payload format for aggregation packets // @see https://tools.ietf.org/html/rfc6184#section-5.7 uint8_t v = kStapA; v |= (nri_ & (~kNalTypeMask)); buf->write_1bytes(v); // NALUs. int nn_nalus = (int)nalus_.size(); for (int i = 0; i < nn_nalus; i++) { SrsNaluSample *p = nalus_[i]; if (!buf->require(2 + p->size_)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 2 + p->size_); } buf->write_2bytes(p->size_); buf->write_bytes(p->bytes_, p->size_); } return srs_success; } srs_error_t SrsRtpSTAPPayload::decode(SrsBuffer *buf) { if (!buf->require(1)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 1); } // STAP header, RTP payload format for aggregation packets // @see https://tools.ietf.org/html/rfc6184#section-5.7 uint8_t v = buf->read_1bytes(); // forbidden_zero_bit shoul be zero. // @see https://tools.ietf.org/html/rfc6184#section-5.3 uint8_t f = (v & 0x80); if (f == 0x80) { return srs_error_new(ERROR_RTC_RTP_MUXER, "forbidden_zero_bit should be zero"); } nri_ = SrsAvcNaluType(v & (~kNalTypeMask)); // NALUs. while (!buf->empty()) { if (!buf->require(2)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 2); } int size = buf->read_2bytes(); if (!buf->require(size)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", size); } SrsNaluSample *sample = new SrsNaluSample(); sample->bytes_ = buf->head(); sample->size_ = size; buf->skip(size); nalus_.push_back(sample); } return srs_success; } ISrsRtpPayloader *SrsRtpSTAPPayload::copy() { SrsRtpSTAPPayload *cp = new SrsRtpSTAPPayload(); cp->nri_ = nri_; int nn_nalus = (int)nalus_.size(); for (int i = 0; i < nn_nalus; i++) { SrsNaluSample *p = nalus_[i]; cp->nalus_.push_back(p->copy()); } return cp; } SrsRtpFUAPayload::SrsRtpFUAPayload() { start_ = end_ = false; nri_ = nalu_type_ = (SrsAvcNaluType)0; ++_srs_pps_objs_rothers->sugar_; } SrsRtpFUAPayload::~SrsRtpFUAPayload() { int nn_nalus = (int)nalus_.size(); for (int i = 0; i < nn_nalus; i++) { SrsNaluSample *p = nalus_[i]; srs_freep(p); } } uint64_t SrsRtpFUAPayload::nb_bytes() { int size = 2; int nn_nalus = (int)nalus_.size(); for (int i = 0; i < nn_nalus; i++) { SrsNaluSample *p = nalus_[i]; size += p->size_; } return size; } srs_error_t SrsRtpFUAPayload::encode(SrsBuffer *buf) { if (!buf->require(2)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 1); } // FU indicator, @see https://tools.ietf.org/html/rfc6184#section-5.8 uint8_t fu_indicate = kFuA; fu_indicate |= (nri_ & (~kNalTypeMask)); buf->write_1bytes(fu_indicate); // FU header, @see https://tools.ietf.org/html/rfc6184#section-5.8 uint8_t fu_header = nalu_type_; if (start_) { fu_header |= kStart; } if (end_) { fu_header |= kEnd; } buf->write_1bytes(fu_header); // FU payload, @see https://tools.ietf.org/html/rfc6184#section-5.8 int nn_nalus = (int)nalus_.size(); for (int i = 0; i < nn_nalus; i++) { SrsNaluSample *p = nalus_[i]; if (!buf->require(p->size_)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", p->size_); } buf->write_bytes(p->bytes_, p->size_); } return srs_success; } srs_error_t SrsRtpFUAPayload::decode(SrsBuffer *buf) { if (!buf->require(2)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 2); } // FU indicator, @see https://tools.ietf.org/html/rfc6184#section-5.8 uint8_t v = buf->read_1bytes(); nri_ = SrsAvcNaluType(v & (~kNalTypeMask)); // FU header, @see https://tools.ietf.org/html/rfc6184#section-5.8 v = buf->read_1bytes(); start_ = v & kStart; end_ = v & kEnd; nalu_type_ = SrsAvcNaluTypeParse(v); if (!buf->require(1)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 1); } SrsNaluSample *sample = new SrsNaluSample(); sample->bytes_ = buf->head(); sample->size_ = buf->left(); buf->skip(sample->size_); nalus_.push_back(sample); return srs_success; } ISrsRtpPayloader *SrsRtpFUAPayload::copy() { SrsRtpFUAPayload *cp = new SrsRtpFUAPayload(); cp->nri_ = nri_; cp->start_ = start_; cp->end_ = end_; cp->nalu_type_ = nalu_type_; int nn_nalus = (int)nalus_.size(); for (int i = 0; i < nn_nalus; i++) { SrsNaluSample *p = nalus_[i]; cp->nalus_.push_back(p->copy()); } return cp; } SrsRtpFUAPayload2::SrsRtpFUAPayload2() { start_ = end_ = false; nri_ = nalu_type_ = (SrsAvcNaluType)0; payload_ = NULL; size_ = 0; ++_srs_pps_objs_rfua->sugar_; } SrsRtpFUAPayload2::~SrsRtpFUAPayload2() { } uint64_t SrsRtpFUAPayload2::nb_bytes() { return 2 + size_; } srs_error_t SrsRtpFUAPayload2::encode(SrsBuffer *buf) { if (!buf->require(2 + size_)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 1); } // Fast encoding. char *p = buf->head(); // FU indicator, @see https://tools.ietf.org/html/rfc6184#section-5.8 uint8_t fu_indicate = kFuA; fu_indicate |= (nri_ & (~kNalTypeMask)); *p++ = fu_indicate; // FU header, @see https://tools.ietf.org/html/rfc6184#section-5.8 uint8_t fu_header = nalu_type_; if (start_) { fu_header |= kStart; } if (end_) { fu_header |= kEnd; } *p++ = fu_header; // FU payload, @see https://tools.ietf.org/html/rfc6184#section-5.8 memcpy(p, payload_, size_); // Consume bytes. buf->skip(2 + size_); return srs_success; } srs_error_t SrsRtpFUAPayload2::decode(SrsBuffer *buf) { if (!buf->require(2)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 2); } // FU indicator, @see https://tools.ietf.org/html/rfc6184#section-5.8 uint8_t v = buf->read_1bytes(); nri_ = SrsAvcNaluType(v & (~kNalTypeMask)); // FU header, @see https://tools.ietf.org/html/rfc6184#section-5.8 v = buf->read_1bytes(); start_ = v & kStart; end_ = v & kEnd; nalu_type_ = SrsAvcNaluTypeParse(v); if (!buf->require(1)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 1); } payload_ = buf->head(); size_ = buf->left(); buf->skip(size_); return srs_success; } ISrsRtpPayloader *SrsRtpFUAPayload2::copy() { SrsRtpFUAPayload2 *cp = new SrsRtpFUAPayload2(); cp->nri_ = nri_; cp->start_ = start_; cp->end_ = end_; cp->nalu_type_ = nalu_type_; cp->payload_ = payload_; cp->size_ = size_; return cp; } SrsRtpSTAPPayloadHevc::SrsRtpSTAPPayloadHevc() { ++_srs_pps_objs_rothers->sugar_; } SrsRtpSTAPPayloadHevc::~SrsRtpSTAPPayloadHevc() { int nn_nalus = (int)nalus_.size(); for (int i = 0; i < nn_nalus; i++) { SrsNaluSample *p = nalus_[i]; srs_freep(p); } } SrsNaluSample *SrsRtpSTAPPayloadHevc::get_vps() { int nn_nalus = (int)nalus_.size(); for (int i = 0; i < nn_nalus; i++) { SrsNaluSample *p = nalus_[i]; if (!p || !p->size_) { continue; } SrsHevcNaluType nalu_type = SrsHevcNaluTypeParse(p->bytes_[0]); if (nalu_type == SrsHevcNaluType_VPS) { return p; } } return NULL; } SrsNaluSample *SrsRtpSTAPPayloadHevc::get_sps() { int nn_nalus = (int)nalus_.size(); for (int i = 0; i < nn_nalus; i++) { SrsNaluSample *p = nalus_[i]; if (!p || !p->size_) { continue; } SrsHevcNaluType nalu_type = SrsHevcNaluTypeParse(p->bytes_[0]); if (nalu_type == SrsHevcNaluType_SPS) { return p; } } return NULL; } SrsNaluSample *SrsRtpSTAPPayloadHevc::get_pps() { int nn_nalus = (int)nalus_.size(); for (int i = 0; i < nn_nalus; i++) { SrsNaluSample *p = nalus_[i]; if (!p || !p->size_) { continue; } SrsHevcNaluType nalu_type = SrsHevcNaluTypeParse(p->bytes_[0]); if (nalu_type == SrsHevcNaluType_PPS) { return p; } } return NULL; } SrsNaluSample *SrsRtpSTAPPayloadHevc::get_idr() { int nn_nalus = (int)nalus_.size(); for (int i = 0; i < nn_nalus; i++) { SrsNaluSample *p = nalus_[i]; if (!p || !p->size_) { continue; } SrsHevcNaluType nalu_type = SrsHevcNaluTypeParse(p->bytes_[0]); if (SrsIsIRAP(nalu_type)) { return p; } } return NULL; } uint64_t SrsRtpSTAPPayloadHevc::nb_bytes() { int size = 2; int nn_nalus = (int)nalus_.size(); for (int i = 0; i < nn_nalus; i++) { SrsNaluSample *p = nalus_[i]; size += 2 + p->size_; } return size; } srs_error_t SrsRtpSTAPPayloadHevc::encode(SrsBuffer *buf) { if (!buf->require(2)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 2); } // STAP header, RTP payload format for aggregation packets // @see https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.2 buf->write_1bytes(kStapHevc << 1); buf->write_1bytes(1); // NALUs. int nn_nalus = (int)nalus_.size(); for (int i = 0; i < nn_nalus; i++) { SrsNaluSample *p = nalus_[i]; if (!buf->require(2 + p->size_)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 2 + p->size_); } buf->write_2bytes(p->size_); buf->write_bytes(p->bytes_, p->size_); } return srs_success; } srs_error_t SrsRtpSTAPPayloadHevc::decode(SrsBuffer *buf) { if (!buf->require(2)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 2); } // STAP header, RTP payload format for aggregation packets // @see https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.2 uint8_t v = buf->read_1bytes(); buf->skip(1); // forbidden_zero_bit shoul be zero. // @see https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.2 uint8_t f = (v & 0x80); if (f == 0x80) { return srs_error_new(ERROR_RTC_RTP_MUXER, "forbidden_zero_bit should be zero"); } // NALUs. while (!buf->empty()) { if (!buf->require(2)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 2); } int size = buf->read_2bytes(); if (!buf->require(size)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", size); } SrsNaluSample *sample = new SrsNaluSample(); sample->bytes_ = buf->head(); sample->size_ = size; buf->skip(size); nalus_.push_back(sample); } return srs_success; } ISrsRtpPayloader *SrsRtpSTAPPayloadHevc::copy() { SrsRtpSTAPPayloadHevc *cp = new SrsRtpSTAPPayloadHevc(); int nn_nalus = (int)nalus_.size(); for (int i = 0; i < nn_nalus; i++) { SrsNaluSample *p = nalus_[i]; cp->nalus_.push_back(p->copy()); } return cp; } SrsRtpFUAPayloadHevc::SrsRtpFUAPayloadHevc() { start_ = end_ = false; nalu_type_ = (SrsHevcNaluType)0; ++_srs_pps_objs_rothers->sugar_; } SrsRtpFUAPayloadHevc::~SrsRtpFUAPayloadHevc() { int nn_nalus = (int)nalus_.size(); for (int i = 0; i < nn_nalus; i++) { SrsNaluSample *p = nalus_[i]; srs_freep(p); } } uint64_t SrsRtpFUAPayloadHevc::nb_bytes() { int size = 3; int nn_nalus = (int)nalus_.size(); for (int i = 0; i < nn_nalus; i++) { SrsNaluSample *p = nalus_[i]; size += p->size_; } return size; } srs_error_t SrsRtpFUAPayloadHevc::encode(SrsBuffer *buf) { if (!buf->require(3)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 3); } // PayloadHdr, @see: https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.3 buf->write_1bytes(kFuHevc << 1); buf->write_1bytes(1); // FU header, @see https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.3 uint8_t fu_header = (start_ ? kStart : 0) | (end_ ? kEnd : 0); fu_header |= nalu_type_; buf->write_1bytes(fu_header); int nn_nalus = (int)nalus_.size(); for (int i = 0; i < nn_nalus; i++) { SrsNaluSample *p = nalus_[i]; if (!buf->require(p->size_)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", p->size_); } buf->write_bytes(p->bytes_, p->size_); } return srs_success; } srs_error_t SrsRtpFUAPayloadHevc::decode(SrsBuffer *buf) { if (!buf->require(3)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 3); } // skip PayloadHdr, 2 bytes buf->skip(2); uint8_t fu_header = buf->read_1bytes(); start_ = fu_header & kStart; end_ = fu_header & kEnd; nalu_type_ = SrsHevcNaluType(fu_header & 0x3F); if (!buf->require(1)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 1); } SrsNaluSample *sample = new SrsNaluSample(); sample->bytes_ = buf->head(); sample->size_ = buf->left(); buf->skip(sample->size_); nalus_.push_back(sample); return srs_success; } ISrsRtpPayloader *SrsRtpFUAPayloadHevc::copy() { SrsRtpFUAPayloadHevc *cp = new SrsRtpFUAPayloadHevc(); cp->start_ = start_; cp->end_ = end_; cp->nalu_type_ = nalu_type_; int nn_nalus = (int)nalus_.size(); for (int i = 0; i < nn_nalus; i++) { SrsNaluSample *p = nalus_[i]; cp->nalus_.push_back(p->copy()); } return cp; } SrsRtpFUAPayloadHevc2::SrsRtpFUAPayloadHevc2() { start_ = end_ = false; nalu_type_ = (SrsHevcNaluType)0; payload_ = NULL; size_ = 0; ++_srs_pps_objs_rfua->sugar_; } SrsRtpFUAPayloadHevc2::~SrsRtpFUAPayloadHevc2() { } uint64_t SrsRtpFUAPayloadHevc2::nb_bytes() { // PayloadHdr(2) + FU header(1) return 3 + size_; } srs_error_t SrsRtpFUAPayloadHevc2::encode(SrsBuffer *buf) { if (!buf->require(3 + size_)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 3 + size_); } // Fast encoding. char *p = buf->head(); // PayloadHdr, @see: https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.3 /* * create the HEVC payload header and transmit the buffer as fragmentation units (FU) * * 0 1 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |F| Type | LayerId | TID | * +-------------+-----------------+ * * F = 0 * Type = 49 (fragmentation unit (FU)) * LayerId = 0 * TID = 1 */ *p++ = kFuHevc << 1; *p++ = 1; // FU header, @see https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.3 uint8_t fu_header = (start_ ? kStart : 0) | (end_ ? kEnd : 0); fu_header |= nalu_type_; *p++ = fu_header; memcpy(p, payload_, size_); // Consume bytes. buf->skip(3 + size_); return srs_success; } srs_error_t SrsRtpFUAPayloadHevc2::decode(SrsBuffer *buf) { if (!buf->require(3)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "requires 3 bytes"); } // skip PayloadHdr, 2 bytes buf->skip(2); uint8_t fu_header = buf->read_1bytes(); start_ = fu_header & kStart; end_ = fu_header & kEnd; nalu_type_ = SrsHevcNaluType(fu_header & 0x3F); payload_ = buf->head(); size_ = buf->left(); buf->skip(size_); return srs_success; } ISrsRtpPayloader *SrsRtpFUAPayloadHevc2::copy() { SrsRtpFUAPayloadHevc2 *cp = new SrsRtpFUAPayloadHevc2(); cp->start_ = start_; cp->end_ = end_; cp->nalu_type_ = nalu_type_; cp->payload_ = payload_; cp->size_ = size_; return cp; }