1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-03-09 15:49:59 +00:00

rtmp2rtc: support hevc

This commit is contained in:
chenhaibo 2025-02-16 09:19:48 +08:00
parent 13597d1b7f
commit 1a224c77de
12 changed files with 933 additions and 139 deletions

View file

@ -758,7 +758,7 @@ SrsRtpPacket::SrsRtpPacket()
shared_buffer_ = NULL;
actual_buffer_size_ = 0;
nalu_type = SrsAvcNaluTypeReserved;
nalu_type = 0;
frame_type = SrsFrameTypeReserved;
cached_payload_size = 0;
decode_handler = NULL;
@ -961,6 +961,23 @@ bool SrsRtpPacket::is_keyframe()
if((SrsAvcNaluTypeIDR == nalu_type) || (SrsAvcNaluTypeSPS == nalu_type) || (SrsAvcNaluTypePPS == nalu_type)) {
return true;
}
#ifdef SRS_H265
if(nalu_type == kStapHevc) {
SrsRtpSTAPPayloadHevc* stap_payload = dynamic_cast<SrsRtpSTAPPayloadHevc*>(payload_);
if(NULL != stap_payload->get_vps() || NULL != stap_payload->get_sps() || NULL != stap_payload->get_pps()) {
return true;
}
} else if(nalu_type == kFuHevc) {
SrsRtpFUAPayloadHevc2* fua_payload = dynamic_cast<SrsRtpFUAPayloadHevc2*>(payload_);
if(fua_payload->nalu_type >= SrsHevcNaluType_CODED_SLICE_BLA && fua_payload->nalu_type <= SrsHevcNaluType_RESERVED_23) {
return true;
}
} else {
if((SrsHevcNaluType_VPS == nalu_type) || (SrsHevcNaluType_SPS == nalu_type) || (SrsHevcNaluType_PPS == nalu_type)) {
return true;
}
}
#endif
}
return false;
@ -1061,10 +1078,10 @@ void SrsRtpRawNALUs::push_back(SrsSample* sample)
nalus.push_back(sample);
}
uint8_t SrsRtpRawNALUs::skip_first_byte()
uint8_t SrsRtpRawNALUs::skip_bytes(int count)
{
srs_assert (cursor >= 0 && nn_bytes > 0 && cursor < nn_bytes);
cursor++;
srs_assert (cursor >= 0 && nn_bytes > 0 && cursor + count < nn_bytes);
cursor += count;
return uint8_t(nalus[0]->bytes[0]);
}
@ -1522,3 +1539,361 @@ ISrsRtpPayloader* SrsRtpFUAPayload2::copy()
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++) {
SrsSample* p = nalus[i];
srs_freep(p);
}
}
SrsSample* SrsRtpSTAPPayloadHevc::get_vps()
{
int nn_nalus = (int)nalus.size();
for (int i = 0; i < nn_nalus; i++) {
SrsSample* p = nalus[i];
if (!p || !p->size) {
continue;
}
SrsHevcNaluType nalu_type = SrsHevcNaluTypeParse(p->bytes[0]);
if (nalu_type == SrsHevcNaluType_VPS) {
return p;
}
}
return NULL;
}
SrsSample* SrsRtpSTAPPayloadHevc::get_sps()
{
int nn_nalus = (int)nalus.size();
for (int i = 0; i < nn_nalus; i++) {
SrsSample* p = nalus[i];
if (!p || !p->size) {
continue;
}
SrsHevcNaluType nalu_type = SrsHevcNaluTypeParse(p->bytes[0]);
if (nalu_type == SrsHevcNaluType_SPS) {
return p;
}
}
return NULL;
}
SrsSample* SrsRtpSTAPPayloadHevc::get_pps()
{
int nn_nalus = (int)nalus.size();
for (int i = 0; i < nn_nalus; i++) {
SrsSample* p = nalus[i];
if (!p || !p->size) {
continue;
}
SrsHevcNaluType nalu_type = SrsHevcNaluTypeParse(p->bytes[0]);
if (nalu_type == SrsHevcNaluType_PPS) {
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++) {
SrsSample* 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++) {
SrsSample* 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();
// 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);
}
SrsSample* sample = new SrsSample();
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++) {
SrsSample* 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++) {
SrsSample* 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++) {
SrsSample* 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++) {
SrsSample* 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);
}
uint8_t payload_hdr1 = buf->read_1bytes();
uint8_t payload_hdr2 = buf->read_1bytes();
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);
}
SrsSample* sample = new SrsSample();
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++) {
SrsSample* 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");
}
uint8_t payload_hdr1 = buf->read_1bytes();
uint8_t payload_hdr2 = buf->read_1bytes();
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;
}