From de460c2b0be879db2bccd68c9fdf2237392a6f32 Mon Sep 17 00:00:00 2001 From: Zita Liao Date: Thu, 20 Jul 2023 16:23:53 +1000 Subject: [PATCH 1/4] add H.265 Packetizer and related code in WebRTC support --- CMakeLists.txt | 6 + include/rtc/description.hpp | 1 + include/rtc/h265nalunit.hpp | 190 +++++++++++++++++++++++ include/rtc/h265packetizationhandler.hpp | 32 ++++ include/rtc/h265rtppacketizer.hpp | 61 ++++++++ include/rtc/rtc.h | 8 +- include/rtc/rtc.hpp | 3 +- src/capi.cpp | 27 ++++ src/description.cpp | 4 + src/h265nalunit.cpp | 100 ++++++++++++ src/h265packetizationhandler.cpp | 20 +++ src/h265rtppacketizer.cpp | 167 ++++++++++++++++++++ 12 files changed, 616 insertions(+), 3 deletions(-) create mode 100644 include/rtc/h265nalunit.hpp create mode 100644 include/rtc/h265packetizationhandler.hpp create mode 100644 include/rtc/h265rtppacketizer.hpp create mode 100644 src/h265nalunit.cpp create mode 100644 src/h265packetizationhandler.cpp create mode 100644 src/h265rtppacketizer.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b8295c303..8038bbe27 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,6 +79,9 @@ set(LIBDATACHANNEL_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/h264rtppacketizer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/nalunit.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/h264packetizationhandler.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/h265rtppacketizer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/h265nalunit.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/h265packetizationhandler.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/av1rtppacketizer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/av1packetizationhandler.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/mediachainablehandler.cpp @@ -116,6 +119,9 @@ set(LIBDATACHANNEL_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/h264rtppacketizer.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/nalunit.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/h264packetizationhandler.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/h265rtppacketizer.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/h265nalunit.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/h265packetizationhandler.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/av1rtppacketizer.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/av1packetizationhandler.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/mediachainablehandler.hpp diff --git a/include/rtc/description.hpp b/include/rtc/description.hpp index 07e6ea545..a0debe958 100644 --- a/include/rtc/description.hpp +++ b/include/rtc/description.hpp @@ -246,6 +246,7 @@ class RTC_CPP_EXPORT Description { void addVideoCodec(int payloadType, string codec, optional profile = std::nullopt); void addH264Codec(int payloadType, optional profile = DEFAULT_H264_VIDEO_PROFILE); + void addH265Codec(int payloadType, optional profile = std::nullopt); void addVP8Codec(int payloadType); void addVP9Codec(int payloadType); void addAV1Codec(int payloadType); diff --git a/include/rtc/h265nalunit.hpp b/include/rtc/h265nalunit.hpp new file mode 100644 index 000000000..792d8cfe3 --- /dev/null +++ b/include/rtc/h265nalunit.hpp @@ -0,0 +1,190 @@ +/** + * Copyright (c) 2020 Filip Klembara (in2core) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#ifndef RTC_H265_NAL_UNIT_H +#define RTC_H265_NAL_UNIT_H + +#if RTC_ENABLE_MEDIA + +#include "common.hpp" + +#include + +namespace rtc { + +#pragma pack(push, 1) + +#define H265_NAL_HEADER_SIZE 2 +#define H265_FU_HEADER_SIZE 1 +/// Nalu header +struct RTC_CPP_EXPORT H265NalUnitHeader { +/* +* nal_unit_header( ) { +* forbidden_zero_bit f(1) +* nal_unit_type u(6) +* nuh_layer_id u(6) +* nuh_temporal_id_plus1 u(3) +} +*/ + //H265NalUnitHeader(uint16_t nalHeader) + // : _first((nalHeader & 0xff00) >> 8) + // , _second(nalHeader & 0xff) + //{} + + //H265NalUnitHeader(uint8_t nalHeaderHi, unit8_t nalHeaderLow) + // : _first(nalHeaderHi) + // , _second(nalHeaderLow) + //{} + + uint8_t _first = 0; // high byte of header + uint8_t _second = 0; // low byte of header + + bool forbiddenBit() const { return _first >> 7; } + uint8_t unitType() const { return (_first & 0b0111'1110) >> 1; } + uint8_t nuhLayerId() const { return ((_first & 0x1) << 5) | ((_second & 0b1111'1000) >> 3); } + uint8_t nuhTempIdPlus1() const { return _second & 0b111;} + + void setForbiddenBit(bool isSet) { _first = (_first & 0x7F) | (isSet << 7); } + void setUnitType(uint8_t type) { _first = (_first & 0b1000'0001) | ((type & 0b11'1111) << 1); } + void setNuhLayerId(uint8_t nuhLayerId) { + _first = (_first & 0b1111'1110) | ((nuhLayerId & 0b10'0000) >> 5); + _second = (_second & 0b0000'0111) | ((nuhLayerId & 0b01'1111) << 3); } + void setNuhTempIdPlus1(uint8_t nuhTempIdPlus1) { _second = (_second & 0b1111'1000) | (nuhTempIdPlus1 & 0b111); } +}; + +/// Nalu fragment header +struct RTC_CPP_EXPORT H265NalUnitFragmentHeader { + /* + * +---------------+ + * |0|1|2|3|4|5|6|7| + * +-+-+-+-+-+-+-+-+ + * |S|E| FuType | + * +---------------+ + */ + uint8_t _first = 0; + + bool isStart() const { return _first >> 7; } + bool isEnd() const { return (_first >> 6) & 0x01; } + uint8_t unitType() const { return _first & 0b11'1111; } + + void setStart(bool isSet) { _first = (_first & 0x7F) | (isSet << 7); } + void setEnd(bool isSet) { _first = (_first & 0b1011'1111) | (isSet << 6); } + void setUnitType(uint8_t type) { _first = (_first & 0b1100'0000) | (type & 0b11'1111); } +}; + +#pragma pack(pop) + +/// Nal unit +struct RTC_CPP_EXPORT H265NalUnit : binary { + H265NalUnit(const H265NalUnit &unit) = default; + H265NalUnit(size_t size, bool includingHeader = true) : binary(size + (includingHeader ? 0 : H265_NAL_HEADER_SIZE)) {} + H265NalUnit(binary &&data) : binary(std::move(data)) {} + H265NalUnit() : binary(H265_NAL_HEADER_SIZE) {} + template H265NalUnit(Iterator begin_, Iterator end_) : binary(begin_, end_) {} + + bool forbiddenBit() const { return header()->forbiddenBit(); } + uint8_t unitType() const { return header()->unitType(); } + uint8_t nuhLayerId() const { return header()->nuhLayerId(); } + uint8_t nuhTempIdPlus1() const { return header()->nuhTempIdPlus1();} + + binary payload() const { + assert(size() >= H265_NAL_HEADER_SIZE); + return {begin() + H265_NAL_HEADER_SIZE, end()}; + } + + void setForbiddenBit(bool isSet) { header()->setForbiddenBit(isSet); } + void setUnitType(uint8_t type) { header()->setUnitType(type); } + void setNuhLayerId(uint8_t nuhLayerId) { header()->setNuhLayerId(nuhLayerId); } + void setNuhTempIdPlus1(uint8_t nuhTempIdPlus1) { header()->setNuhTempIdPlus1(nuhTempIdPlus1); } + + void setPayload(binary payload) { + assert(size() >= H265_NAL_HEADER_SIZE); + erase(begin() + H265_NAL_HEADER_SIZE, end()); + insert(end(), payload.begin(), payload.end()); + } + +protected: + const H265NalUnitHeader *header() const { + assert(size() >= H265_NAL_HEADER_SIZE); + return reinterpret_cast(data()); + } + + H265NalUnitHeader *header() { + assert(size() >= H265_NAL_HEADER_SIZE); + return reinterpret_cast(data()); + } +}; + +/// Nal unit fragment A +struct RTC_CPP_EXPORT H265NalUnitFragment : H265NalUnit { + static std::vector> fragmentsFrom(shared_ptr nalu, + uint16_t maximumFragmentSize); + + enum class FragmentType { Start, Middle, End }; + + H265NalUnitFragment(FragmentType type, bool forbiddenBit, uint8_t nuhLayerId, + uint8_t nuhTempIdPlus1, uint8_t unitType, binary data); + + uint8_t unitType() const { return fragmentHeader()->unitType(); } + + binary payload() const { + assert(size() >= H265_NAL_HEADER_SIZE + H265_FU_HEADER_SIZE); + return {begin() + H265_NAL_HEADER_SIZE + H265_FU_HEADER_SIZE, end()}; + } + + FragmentType type() const { + if (fragmentHeader()->isStart()) { + return FragmentType::Start; + } else if (fragmentHeader()->isEnd()) { + return FragmentType::End; + } else { + return FragmentType::Middle; + } + } + + void setUnitType(uint8_t type) { fragmentHeader()->setUnitType(type); } + + void setPayload(binary payload) { + assert(size() >= H265_NAL_HEADER_SIZE + H265_FU_HEADER_SIZE); + erase(begin() + H265_NAL_HEADER_SIZE + H265_FU_HEADER_SIZE, end()); + insert(end(), payload.begin(), payload.end()); + } + + void setFragmentType(FragmentType type); + +protected: + const uint8_t nal_type_fu = 49; + + H265NalUnitHeader *fragmentIndicator() { return reinterpret_cast(data()); } + + const H265NalUnitHeader *fragmentIndicator() const { + return reinterpret_cast(data()); + } + + H265NalUnitFragmentHeader *fragmentHeader() { + return reinterpret_cast(fragmentIndicator() + H265_NAL_HEADER_SIZE); + } + + const H265NalUnitFragmentHeader *fragmentHeader() const { + return reinterpret_cast(fragmentIndicator() + H265_NAL_HEADER_SIZE); + } +}; + +class RTC_CPP_EXPORT H265NalUnits : public std::vector> { +public: + static const uint16_t defaultMaximumFragmentSize = + uint16_t(RTC_DEFAULT_MTU - 12 - 8 - 40); // SRTP/UDP/IPv6 + + std::vector> generateFragments(uint16_t maximumFragmentSize); +}; + +} // namespace rtc + +#endif /* RTC_ENABLE_MEDIA */ + +#endif /* RTC_NAL_UNIT_H */ diff --git a/include/rtc/h265packetizationhandler.hpp b/include/rtc/h265packetizationhandler.hpp new file mode 100644 index 000000000..fb34ae450 --- /dev/null +++ b/include/rtc/h265packetizationhandler.hpp @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2020 Filip Klembara (in2core) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#ifndef RTC_H265_PACKETIZATION_HANDLER_H +#define RTC_H265_PACKETIZATION_HANDLER_H + +#if RTC_ENABLE_MEDIA + +#include "h265rtppacketizer.hpp" +#include "mediachainablehandler.hpp" +#include "h265nalunit.hpp" + +namespace rtc { + +/// Handler for H265 packetization +class RTC_CPP_EXPORT H265PacketizationHandler final : public MediaChainableHandler { +public: + /// Construct handler for H265 packetization. + /// @param packetizer RTP packetizer for h265 + H265PacketizationHandler(shared_ptr packetizer); +}; + +} // namespace rtc + +#endif /* RTC_ENABLE_MEDIA */ + +#endif /* RTC_H265_PACKETIZATION_HANDLER_H */ diff --git a/include/rtc/h265rtppacketizer.hpp b/include/rtc/h265rtppacketizer.hpp new file mode 100644 index 000000000..488df8fca --- /dev/null +++ b/include/rtc/h265rtppacketizer.hpp @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2020 Filip Klembara (in2core) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#ifndef RTC_H265_RTP_PACKETIZER_H +#define RTC_H265_RTP_PACKETIZER_H + +#if RTC_ENABLE_MEDIA + +#include "mediahandlerrootelement.hpp" +#include "h265nalunit.hpp" +#include "rtppacketizer.hpp" + +namespace rtc { + +/// RTP packetization of h265 payload +class RTC_CPP_EXPORT H265RtpPacketizer final : public RtpPacketizer, + public MediaHandlerRootElement { + shared_ptr splitMessage(binary_ptr message); + const uint16_t maximumFragmentSize; + +public: + /// Default clock rate for H265 in RTP + inline static const uint32_t defaultClockRate = 90 * 1000; + + /// NAL unit separator + enum class Separator { + Length = RTC_NAL_SEPARATOR_LENGTH, // first 4 bytes are NAL unit length + LongStartSequence = RTC_NAL_SEPARATOR_LONG_START_SEQUENCE, // 0x00, 0x00, 0x00, 0x01 + ShortStartSequence = RTC_NAL_SEPARATOR_SHORT_START_SEQUENCE, // 0x00, 0x00, 0x01 + StartSequence = RTC_NAL_SEPARATOR_START_SEQUENCE, // LongStartSequence or ShortStartSequence + }; + + H265RtpPacketizer(H265RtpPacketizer::Separator separator, + shared_ptr rtpConfig, + uint16_t maximumFragmentSize = H265NalUnits::defaultMaximumFragmentSize); + + /// Constructs h265 payload packetizer with given RTP configuration. + /// @note RTP configuration is used in packetization process which may change some configuration + /// properties such as sequence number. + /// @param rtpConfig RTP configuration + /// @param maximumFragmentSize maximum size of one NALU fragment + H265RtpPacketizer(shared_ptr rtpConfig, + uint16_t maximumFragmentSize = H265NalUnits::defaultMaximumFragmentSize); + + ChainedOutgoingProduct processOutgoingBinaryMessage(ChainedMessagesProduct messages, + message_ptr control) override; + +private: + const Separator separator; +}; + +} // namespace rtc + +#endif /* RTC_ENABLE_MEDIA */ + +#endif /* RTC_H265_RTP_PACKETIZER_H */ diff --git a/include/rtc/rtc.h b/include/rtc/rtc.h index ac60a041c..066ca7ed3 100644 --- a/include/rtc/rtc.h +++ b/include/rtc/rtc.h @@ -112,6 +112,7 @@ typedef enum { RTC_CODEC_H264 = 0, RTC_CODEC_VP8 = 1, RTC_CODEC_VP9 = 2, + RTC_CODEC_H265 = 3, // audio RTC_CODEC_OPUS = 128, @@ -294,7 +295,7 @@ typedef enum { RTC_OBU_PACKETIZED_TEMPORAL_UNIT = 1, } rtcObuPacketization; -// Define how NAL units are separated in a H264 sample +// Define how NAL units are separated in a H264/H265 sample typedef enum { RTC_NAL_SEPARATOR_LENGTH = 0, // first 4 bytes are NAL unit length RTC_NAL_SEPARATOR_LONG_START_SEQUENCE = 1, // 0x00, 0x00, 0x00, 0x01 @@ -310,7 +311,7 @@ typedef struct { uint16_t sequenceNumber; uint32_t timestamp; - // H264 + // H264/H265 rtcNalUnitSeparator nalSeparator; // NAL unit separator uint16_t maxFragmentSize; // Maximum NAL unit fragment size @@ -340,6 +341,9 @@ RTC_C_EXPORT int rtcSetMediaInterceptorCallback(int id, rtcInterceptorCallbackFu // Set H264PacketizationHandler for track RTC_C_EXPORT int rtcSetH264PacketizationHandler(int tr, const rtcPacketizationHandlerInit *init); +// Set H265PacketizationHandler for track +RTC_C_EXPORT int rtcSetH265PacketizationHandler(int tr, const rtcPacketizationHandlerInit *init); + // Set OpusPacketizationHandler for track RTC_C_EXPORT int rtcSetOpusPacketizationHandler(int tr, const rtcPacketizationHandlerInit *init); diff --git a/include/rtc/rtc.hpp b/include/rtc/rtc.hpp index 714799846..2b2a7999e 100644 --- a/include/rtc/rtc.hpp +++ b/include/rtc/rtc.hpp @@ -33,8 +33,9 @@ #include "rtcpreceivingsession.hpp" #include "rtcpsrreporter.hpp" -// Opus/h264/AV1 streaming +// Opus/h264/AV1/h265 streaming #include "h264packetizationhandler.hpp" +#include "h265packetizationhandler.hpp" #include "av1packetizationhandler.hpp" #include "opuspacketizationhandler.hpp" diff --git a/src/capi.cpp b/src/capi.cpp index 3379a7c53..a5c0839ec 100644 --- a/src/capi.cpp +++ b/src/capi.cpp @@ -1019,6 +1019,7 @@ int rtcAddTrackEx(int pc, const rtcTrackInit *init) { } else { switch (init->codec) { case RTC_CODEC_H264: + case RTC_CODEC_H265: case RTC_CODEC_VP8: case RTC_CODEC_VP9: mid = "video"; @@ -1038,6 +1039,7 @@ int rtcAddTrackEx(int pc, const rtcTrackInit *init) { switch (init->codec) { case RTC_CODEC_H264: + case RTC_CODEC_H265: case RTC_CODEC_VP8: case RTC_CODEC_VP9: { auto desc = Description::Video(mid, direction); @@ -1045,6 +1047,9 @@ int rtcAddTrackEx(int pc, const rtcTrackInit *init) { case RTC_CODEC_H264: desc.addH264Codec(init->payloadType); break; + case RTC_CODEC_H265: + desc.addH265Codec(init->payloadType); + break; case RTC_CODEC_VP8: desc.addVP8Codec(init->payloadType); break; @@ -1210,6 +1215,28 @@ int rtcSetH264PacketizationHandler(int tr, const rtcPacketizationHandlerInit *in }); } +int rtcSetH265PacketizationHandler(int tr, const rtcPacketizationHandlerInit *init) { + return wrap([&] { + auto track = getTrack(tr); + // create RTP configuration + auto rtpConfig = createRtpPacketizationConfig(init); + // create packetizer + auto nalSeparator = init ? init->nalSeparator : RTC_NAL_SEPARATOR_LENGTH; + auto maxFragmentSize = init && init->maxFragmentSize ? init->maxFragmentSize + : RTC_DEFAULT_MAXIMUM_FRAGMENT_SIZE; + auto packetizer = std::make_shared( + static_cast(nalSeparator), rtpConfig, + maxFragmentSize); + // create H265 handler + auto h265Handler = std::make_shared(packetizer); + emplaceMediaChainableHandler(h265Handler, tr); + emplaceRtpConfig(rtpConfig, tr); + // set handler + track->setMediaHandler(h265Handler); + return RTC_ERR_SUCCESS; + }); +} + int rtcSetOpusPacketizationHandler(int tr, const rtcPacketizationHandlerInit *init) { return wrap([&] { auto track = getTrack(tr); diff --git a/src/description.cpp b/src/description.cpp index 58b37f4c0..f357577f8 100644 --- a/src/description.cpp +++ b/src/description.cpp @@ -1175,6 +1175,10 @@ void Description::Video::addH264Codec(int pt, optional profile) { addVideoCodec(pt, "H264", profile); } +void Description::Video::addH265Codec(int pt, optional profile) { + addVideoCodec(pt, "H265", profile); +} + void Description::Video::addVP8Codec(int payloadType) { addVideoCodec(payloadType, "VP8", nullopt); } diff --git a/src/h265nalunit.cpp b/src/h265nalunit.cpp new file mode 100644 index 000000000..ab6ac7978 --- /dev/null +++ b/src/h265nalunit.cpp @@ -0,0 +1,100 @@ +/** + * Copyright (c) 2020 Filip Klembara (in2core) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#if RTC_ENABLE_MEDIA + +#include "h265nalunit.hpp" + +#include "impl/internals.hpp" + +#include + +namespace rtc { + +H265NalUnitFragment::H265NalUnitFragment(FragmentType type, bool forbiddenBit, uint8_t nuhLayerId, + uint8_t nuhTempIdPlus1, uint8_t unitType, binary data) + : H265NalUnit(data.size() + H265_NAL_HEADER_SIZE + H265_FU_HEADER_SIZE) { + setForbiddenBit(forbiddenBit); + setNuhLayerId(nuhLayerId); + setNuhTempIdPlus1(nuhTempIdPlus1); + fragmentIndicator()->setUnitType(H265NalUnitFragment::nal_type_fu); + setFragmentType(type); + setUnitType(unitType); + copy(data.begin(), data.end(), begin() + H265_NAL_HEADER_SIZE + H265_FU_HEADER_SIZE); +} + +std::vector> +H265NalUnitFragment::fragmentsFrom(shared_ptr nalu, uint16_t maximumFragmentSize) { + assert(nalu->size() > maximumFragmentSize); + auto fragments_count = ceil(double(nalu->size()) / maximumFragmentSize); + maximumFragmentSize = uint16_t(int(ceil(nalu->size() / fragments_count))); + + // 3 bytes for FU indicator and FU header + maximumFragmentSize -= (H265_NAL_HEADER_SIZE + H265_FU_HEADER_SIZE); + auto f = nalu->forbiddenBit(); + uint8_t nuhLayerId = nalu->nuhLayerId() & 0x3F; // 6 bits + uint8_t nuhTempIdPlus1 = nalu->nuhTempIdPlus1() & 0xE; // 3 bits + uint8_t naluType = nalu->unitType() & 0x3F; // 6 bits + auto payload = nalu->payload(); + vector> result{}; + uint64_t offset = 0; + while (offset < payload.size()) { + vector fragmentData; + FragmentType fragmentType; + if (offset == 0) { + fragmentType = FragmentType::Start; + } else if (offset + maximumFragmentSize < payload.size()) { + fragmentType = FragmentType::Middle; + } else { + if (offset + maximumFragmentSize > payload.size()) { + maximumFragmentSize = uint16_t(payload.size() - offset); + } + fragmentType = FragmentType::End; + } + fragmentData = {payload.begin() + offset, payload.begin() + offset + maximumFragmentSize}; + auto fragment = + std::make_shared(fragmentType, f, nuhLayerId, nuhTempIdPlus1, naluType, fragmentData); + result.push_back(fragment); + offset += maximumFragmentSize; + } + return result; +} + +void H265NalUnitFragment::setFragmentType(FragmentType type) { + switch (type) { + case FragmentType::Start: + fragmentHeader()->setStart(true); + fragmentHeader()->setEnd(false); + break; + case FragmentType::End: + fragmentHeader()->setStart(false); + fragmentHeader()->setEnd(true); + break; + default: + fragmentHeader()->setStart(false); + fragmentHeader()->setEnd(false); + } +} + +std::vector> H265NalUnits::generateFragments(uint16_t maximumFragmentSize) { + vector> result{}; + for (auto nalu : *this) { + if (nalu->size() > maximumFragmentSize) { + std::vector> fragments = + H265NalUnitFragment::fragmentsFrom(nalu, maximumFragmentSize); + result.insert(result.end(), fragments.begin(), fragments.end()); + } else { + result.push_back(nalu); + } + } + return result; +} + +} // namespace rtc + +#endif /* RTC_ENABLE_MEDIA */ diff --git a/src/h265packetizationhandler.cpp b/src/h265packetizationhandler.cpp new file mode 100644 index 000000000..d4ba59157 --- /dev/null +++ b/src/h265packetizationhandler.cpp @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2020 Filip Klembara (in2core) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#if RTC_ENABLE_MEDIA + +#include "h265packetizationhandler.hpp" + +namespace rtc { + +H265PacketizationHandler::H265PacketizationHandler(shared_ptr packetizer) + : MediaChainableHandler(packetizer) {} + +} // namespace rtc + +#endif /* RTC_ENABLE_MEDIA */ diff --git a/src/h265rtppacketizer.cpp b/src/h265rtppacketizer.cpp new file mode 100644 index 000000000..59a9fe69c --- /dev/null +++ b/src/h265rtppacketizer.cpp @@ -0,0 +1,167 @@ +/** + * Copyright (c) 2020 Filip Klembara (in2core) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#if RTC_ENABLE_MEDIA + +#include "h265rtppacketizer.hpp" + +#include "impl/internals.hpp" + +#include + +#ifdef _WIN32 +#include +#else +#include +#endif + +namespace rtc { + +typedef enum { + NUSM_noMatch, + NUSM_firstZero, + NUSM_secondZero, + NUSM_thirdZero, + NUSM_shortMatch, + NUSM_longMatch +} NalUnitStartSequenceMatch; + +NalUnitStartSequenceMatch StartSequenceMatchSucc(NalUnitStartSequenceMatch match, byte _byte, + H265RtpPacketizer::Separator separator) { + assert(separator != H265RtpPacketizer::Separator::Length); + auto byte = (uint8_t)_byte; + auto detectShort = separator == H265RtpPacketizer::Separator::ShortStartSequence || + separator == H265RtpPacketizer::Separator::StartSequence; + auto detectLong = separator == H265RtpPacketizer::Separator::LongStartSequence || + separator == H265RtpPacketizer::Separator::StartSequence; + switch (match) { + case NUSM_noMatch: + if (byte == 0x00) { + return NUSM_firstZero; + } + break; + case NUSM_firstZero: + if (byte == 0x00) { + return NUSM_secondZero; + } + break; + case NUSM_secondZero: + if (byte == 0x00 && detectLong) { + return NUSM_thirdZero; + } else if (byte == 0x00 && detectShort) { + return NUSM_secondZero; + } else if (byte == 0x01 && detectShort) { + return NUSM_shortMatch; + } + break; + case NUSM_thirdZero: + if (byte == 0x00 && detectLong) { + return NUSM_thirdZero; + } else if (byte == 0x01 && detectLong) { + return NUSM_longMatch; + } + break; + case NUSM_shortMatch: + return NUSM_shortMatch; + case NUSM_longMatch: + return NUSM_longMatch; + } + return NUSM_noMatch; +} + +shared_ptr H265RtpPacketizer::splitMessage(binary_ptr message) { + auto nalus = std::make_shared(); + if (separator == Separator::Length) { + size_t index = 0; + while (index < message->size()) { + assert(index + 4 < message->size()); + if (index + 4 >= message->size()) { + LOG_WARNING << "Invalid NAL Unit data (incomplete length), ignoring!"; + break; + } + auto lengthPtr = (uint32_t *)(message->data() + index); + uint32_t length = ntohl(*lengthPtr); + auto naluStartIndex = index + 4; + auto naluEndIndex = naluStartIndex + length; + + assert(naluEndIndex <= message->size()); + if (naluEndIndex > message->size()) { + LOG_WARNING << "Invalid NAL Unit data (incomplete unit), ignoring!"; + break; + } + auto begin = message->begin() + naluStartIndex; + auto end = message->begin() + naluEndIndex; + nalus->push_back(std::make_shared(begin, end)); + index = naluEndIndex; + } + } else { + NalUnitStartSequenceMatch match = NUSM_noMatch; + size_t index = 0; + while (index < message->size()) { + match = StartSequenceMatchSucc(match, (*message)[index++], separator); + if (match == NUSM_longMatch || match == NUSM_shortMatch) { + match = NUSM_noMatch; + break; + } + } + + size_t naluStartIndex = index; + + while (index < message->size()) { + match = StartSequenceMatchSucc(match, (*message)[index], separator); + if (match == NUSM_longMatch || match == NUSM_shortMatch) { + auto sequenceLength = match == NUSM_longMatch ? 4 : 3; + size_t naluEndIndex = index - sequenceLength; + match = NUSM_noMatch; + auto begin = message->begin() + naluStartIndex; + auto end = message->begin() + naluEndIndex + 1; + nalus->push_back(std::make_shared(begin, end)); + naluStartIndex = index + 1; + } + index++; + } + auto begin = message->begin() + naluStartIndex; + auto end = message->end(); + nalus->push_back(std::make_shared(begin, end)); + } + return nalus; +} + +H265RtpPacketizer::H265RtpPacketizer(shared_ptr rtpConfig, + uint16_t maximumFragmentSize) + : RtpPacketizer(rtpConfig), MediaHandlerRootElement(), maximumFragmentSize(maximumFragmentSize), + separator(Separator::Length) {} + +H265RtpPacketizer::H265RtpPacketizer(H265RtpPacketizer::Separator separator, + shared_ptr rtpConfig, + uint16_t maximumFragmentSize) + : RtpPacketizer(rtpConfig), MediaHandlerRootElement(), maximumFragmentSize(maximumFragmentSize), + separator(separator) {} + +ChainedOutgoingProduct +H265RtpPacketizer::processOutgoingBinaryMessage(ChainedMessagesProduct messages, + message_ptr control) { + ChainedMessagesProduct packets = std::make_shared>(); + for (auto message : *messages) { + auto nalus = splitMessage(message); + auto fragments = nalus->generateFragments(maximumFragmentSize); + if (fragments.size() == 0) { + return ChainedOutgoingProduct(); + } + unsigned i = 0; + for (; i < fragments.size() - 1; i++) { + packets->push_back(packetize(fragments[i], false)); + } + packets->push_back(packetize(fragments[i], true)); + } + return {packets, control}; +} + +} // namespace rtc + +#endif /* RTC_ENABLE_MEDIA */ From d8f85150c17149862012d64d0cba62af309754ad Mon Sep 17 00:00:00 2001 From: Zita Liao Date: Mon, 21 Aug 2023 16:30:15 +1000 Subject: [PATCH 2/4] fix review comment --- include/rtc/h264rtppacketizer.hpp | 12 +----- include/rtc/h265nalunit.hpp | 23 +++------- include/rtc/h265rtppacketizer.hpp | 12 +----- include/rtc/nalunit.hpp | 72 ++++++++++++++++++++++++++++++- src/capi.cpp | 4 +- src/h264rtppacketizer.cpp | 62 +++----------------------- src/h265rtppacketizer.cpp | 62 +++----------------------- 7 files changed, 93 insertions(+), 154 deletions(-) diff --git a/include/rtc/h264rtppacketizer.hpp b/include/rtc/h264rtppacketizer.hpp index 38c547a84..28b9ba262 100644 --- a/include/rtc/h264rtppacketizer.hpp +++ b/include/rtc/h264rtppacketizer.hpp @@ -27,15 +27,7 @@ class RTC_CPP_EXPORT H264RtpPacketizer final : public RtpPacketizer, /// Default clock rate for H264 in RTP inline static const uint32_t defaultClockRate = 90 * 1000; - /// NAL unit separator - enum class Separator { - Length = RTC_NAL_SEPARATOR_LENGTH, // first 4 bytes are NAL unit length - LongStartSequence = RTC_NAL_SEPARATOR_LONG_START_SEQUENCE, // 0x00, 0x00, 0x00, 0x01 - ShortStartSequence = RTC_NAL_SEPARATOR_SHORT_START_SEQUENCE, // 0x00, 0x00, 0x01 - StartSequence = RTC_NAL_SEPARATOR_START_SEQUENCE, // LongStartSequence or ShortStartSequence - }; - - H264RtpPacketizer(H264RtpPacketizer::Separator separator, + H264RtpPacketizer(NalUnit::Separator separator, shared_ptr rtpConfig, uint16_t maximumFragmentSize = NalUnits::defaultMaximumFragmentSize); @@ -51,7 +43,7 @@ class RTC_CPP_EXPORT H264RtpPacketizer final : public RtpPacketizer, message_ptr control) override; private: - const Separator separator; + const NalUnit::Separator separator; }; } // namespace rtc diff --git a/include/rtc/h265nalunit.hpp b/include/rtc/h265nalunit.hpp index 792d8cfe3..4e66c38fc 100644 --- a/include/rtc/h265nalunit.hpp +++ b/include/rtc/h265nalunit.hpp @@ -12,6 +12,7 @@ #if RTC_ENABLE_MEDIA #include "common.hpp" +#include "nalunit.hpp" #include @@ -19,7 +20,6 @@ namespace rtc { #pragma pack(push, 1) -#define H265_NAL_HEADER_SIZE 2 #define H265_FU_HEADER_SIZE 1 /// Nalu header struct RTC_CPP_EXPORT H265NalUnitHeader { @@ -31,16 +31,6 @@ struct RTC_CPP_EXPORT H265NalUnitHeader { * nuh_temporal_id_plus1 u(3) } */ - //H265NalUnitHeader(uint16_t nalHeader) - // : _first((nalHeader & 0xff00) >> 8) - // , _second(nalHeader & 0xff) - //{} - - //H265NalUnitHeader(uint8_t nalHeaderHi, unit8_t nalHeaderLow) - // : _first(nalHeaderHi) - // , _second(nalHeaderLow) - //{} - uint8_t _first = 0; // high byte of header uint8_t _second = 0; // low byte of header @@ -80,12 +70,13 @@ struct RTC_CPP_EXPORT H265NalUnitFragmentHeader { #pragma pack(pop) /// Nal unit -struct RTC_CPP_EXPORT H265NalUnit : binary { +struct RTC_CPP_EXPORT H265NalUnit : NalUnit { H265NalUnit(const H265NalUnit &unit) = default; - H265NalUnit(size_t size, bool includingHeader = true) : binary(size + (includingHeader ? 0 : H265_NAL_HEADER_SIZE)) {} - H265NalUnit(binary &&data) : binary(std::move(data)) {} - H265NalUnit() : binary(H265_NAL_HEADER_SIZE) {} - template H265NalUnit(Iterator begin_, Iterator end_) : binary(begin_, end_) {} + H265NalUnit(size_t size, bool includingHeader = true) : NalUnit(size, includingHeader, NalUnit::Type::H265) {} + H265NalUnit(binary &&data) : NalUnit(std::move(data)) {} + H265NalUnit() : NalUnit(NalUnit::Type::H265) {} + + template H265NalUnit(Iterator begin_, Iterator end_) : NalUnit(begin_, end_) {} bool forbiddenBit() const { return header()->forbiddenBit(); } uint8_t unitType() const { return header()->unitType(); } diff --git a/include/rtc/h265rtppacketizer.hpp b/include/rtc/h265rtppacketizer.hpp index 488df8fca..a2ca5bf6f 100644 --- a/include/rtc/h265rtppacketizer.hpp +++ b/include/rtc/h265rtppacketizer.hpp @@ -27,15 +27,7 @@ class RTC_CPP_EXPORT H265RtpPacketizer final : public RtpPacketizer, /// Default clock rate for H265 in RTP inline static const uint32_t defaultClockRate = 90 * 1000; - /// NAL unit separator - enum class Separator { - Length = RTC_NAL_SEPARATOR_LENGTH, // first 4 bytes are NAL unit length - LongStartSequence = RTC_NAL_SEPARATOR_LONG_START_SEQUENCE, // 0x00, 0x00, 0x00, 0x01 - ShortStartSequence = RTC_NAL_SEPARATOR_SHORT_START_SEQUENCE, // 0x00, 0x00, 0x01 - StartSequence = RTC_NAL_SEPARATOR_START_SEQUENCE, // LongStartSequence or ShortStartSequence - }; - - H265RtpPacketizer(H265RtpPacketizer::Separator separator, + H265RtpPacketizer(NalUnit::Separator separator, shared_ptr rtpConfig, uint16_t maximumFragmentSize = H265NalUnits::defaultMaximumFragmentSize); @@ -51,7 +43,7 @@ class RTC_CPP_EXPORT H265RtpPacketizer final : public RtpPacketizer, message_ptr control) override; private: - const Separator separator; + const NalUnit::Separator separator; }; } // namespace rtc diff --git a/include/rtc/nalunit.hpp b/include/rtc/nalunit.hpp index cc8de7a1f..60ed7672e 100644 --- a/include/rtc/nalunit.hpp +++ b/include/rtc/nalunit.hpp @@ -49,12 +49,29 @@ struct RTC_CPP_EXPORT NalUnitFragmentHeader { #pragma pack(pop) +typedef enum { + NUSM_noMatch, + NUSM_firstZero, + NUSM_secondZero, + NUSM_thirdZero, + NUSM_shortMatch, + NUSM_longMatch +} NalUnitStartSequenceMatch; + +static const size_t H264_NAL_HEADER_SIZE = 1; +static const size_t H265_NAL_HEADER_SIZE = 2; /// Nal unit struct RTC_CPP_EXPORT NalUnit : binary { + typedef enum { + H264, + H265 + } Type; + NalUnit(const NalUnit &unit) = default; - NalUnit(size_t size, bool includingHeader = true) : binary(size + (includingHeader ? 0 : 1)) {} + NalUnit(size_t size, bool includingHeader = true, Type type = H264) + : binary(size + (includingHeader ? 0 : (type == H264? H264_NAL_HEADER_SIZE: H265_NAL_HEADER_SIZE))) {} NalUnit(binary &&data) : binary(std::move(data)) {} - NalUnit() : binary(1) {} + NalUnit(Type type = H264) : binary( type == H264? H264_NAL_HEADER_SIZE: H265_NAL_HEADER_SIZE) {} template NalUnit(Iterator begin_, Iterator end_) : binary(begin_, end_) {} bool forbiddenBit() const { return header()->forbiddenBit(); } @@ -76,6 +93,57 @@ struct RTC_CPP_EXPORT NalUnit : binary { insert(end(), payload.begin(), payload.end()); } + /// NAL unit separator + enum class Separator { + Length = RTC_NAL_SEPARATOR_LENGTH, // first 4 bytes are NAL unit length + LongStartSequence = RTC_NAL_SEPARATOR_LONG_START_SEQUENCE, // 0x00, 0x00, 0x00, 0x01 + ShortStartSequence = RTC_NAL_SEPARATOR_SHORT_START_SEQUENCE, // 0x00, 0x00, 0x01 + StartSequence = RTC_NAL_SEPARATOR_START_SEQUENCE, // LongStartSequence or ShortStartSequence + }; + + static NalUnitStartSequenceMatch StartSequenceMatchSucc(NalUnitStartSequenceMatch match, std::byte _byte, Separator separator) + { + assert(separator != Separator::Length); + auto byte = (uint8_t)_byte; + auto detectShort = separator == Separator::ShortStartSequence || + separator == Separator::StartSequence; + auto detectLong = separator == Separator::LongStartSequence || + separator == Separator::StartSequence; + switch (match) { + case NUSM_noMatch: + if (byte == 0x00) { + return NUSM_firstZero; + } + break; + case NUSM_firstZero: + if (byte == 0x00) { + return NUSM_secondZero; + } + break; + case NUSM_secondZero: + if (byte == 0x00 && detectLong) { + return NUSM_thirdZero; + } else if (byte == 0x00 && detectShort) { + return NUSM_secondZero; + } else if (byte == 0x01 && detectShort) { + return NUSM_shortMatch; + } + break; + case NUSM_thirdZero: + if (byte == 0x00 && detectLong) { + return NUSM_thirdZero; + } else if (byte == 0x01 && detectLong) { + return NUSM_longMatch; + } + break; + case NUSM_shortMatch: + return NUSM_shortMatch; + case NUSM_longMatch: + return NUSM_longMatch; + } + return NUSM_noMatch; + } + protected: const NalUnitHeader *header() const { assert(size() >= 1); diff --git a/src/capi.cpp b/src/capi.cpp index a5c0839ec..15a7f4025 100644 --- a/src/capi.cpp +++ b/src/capi.cpp @@ -1203,7 +1203,7 @@ int rtcSetH264PacketizationHandler(int tr, const rtcPacketizationHandlerInit *in auto maxFragmentSize = init && init->maxFragmentSize ? init->maxFragmentSize : RTC_DEFAULT_MAXIMUM_FRAGMENT_SIZE; auto packetizer = std::make_shared( - static_cast(nalSeparator), rtpConfig, + static_cast(nalSeparator), rtpConfig, maxFragmentSize); // create H264 handler auto h264Handler = std::make_shared(packetizer); @@ -1225,7 +1225,7 @@ int rtcSetH265PacketizationHandler(int tr, const rtcPacketizationHandlerInit *in auto maxFragmentSize = init && init->maxFragmentSize ? init->maxFragmentSize : RTC_DEFAULT_MAXIMUM_FRAGMENT_SIZE; auto packetizer = std::make_shared( - static_cast(nalSeparator), rtpConfig, + static_cast(nalSeparator), rtpConfig, maxFragmentSize); // create H265 handler auto h265Handler = std::make_shared(packetizer); diff --git a/src/h264rtppacketizer.cpp b/src/h264rtppacketizer.cpp index ef142b332..458487886 100644 --- a/src/h264rtppacketizer.cpp +++ b/src/h264rtppacketizer.cpp @@ -22,61 +22,9 @@ namespace rtc { -typedef enum { - NUSM_noMatch, - NUSM_firstZero, - NUSM_secondZero, - NUSM_thirdZero, - NUSM_shortMatch, - NUSM_longMatch -} NalUnitStartSequenceMatch; - -NalUnitStartSequenceMatch StartSequenceMatchSucc(NalUnitStartSequenceMatch match, byte _byte, - H264RtpPacketizer::Separator separator) { - assert(separator != H264RtpPacketizer::Separator::Length); - auto byte = (uint8_t)_byte; - auto detectShort = separator == H264RtpPacketizer::Separator::ShortStartSequence || - separator == H264RtpPacketizer::Separator::StartSequence; - auto detectLong = separator == H264RtpPacketizer::Separator::LongStartSequence || - separator == H264RtpPacketizer::Separator::StartSequence; - switch (match) { - case NUSM_noMatch: - if (byte == 0x00) { - return NUSM_firstZero; - } - break; - case NUSM_firstZero: - if (byte == 0x00) { - return NUSM_secondZero; - } - break; - case NUSM_secondZero: - if (byte == 0x00 && detectLong) { - return NUSM_thirdZero; - } else if (byte == 0x00 && detectShort) { - return NUSM_secondZero; - } else if (byte == 0x01 && detectShort) { - return NUSM_shortMatch; - } - break; - case NUSM_thirdZero: - if (byte == 0x00 && detectLong) { - return NUSM_thirdZero; - } else if (byte == 0x01 && detectLong) { - return NUSM_longMatch; - } - break; - case NUSM_shortMatch: - return NUSM_shortMatch; - case NUSM_longMatch: - return NUSM_longMatch; - } - return NUSM_noMatch; -} - shared_ptr H264RtpPacketizer::splitMessage(binary_ptr message) { auto nalus = std::make_shared(); - if (separator == Separator::Length) { + if (separator == NalUnit::Separator::Length) { size_t index = 0; while (index < message->size()) { assert(index + 4 < message->size()); @@ -103,7 +51,7 @@ shared_ptr H264RtpPacketizer::splitMessage(binary_ptr message) { NalUnitStartSequenceMatch match = NUSM_noMatch; size_t index = 0; while (index < message->size()) { - match = StartSequenceMatchSucc(match, (*message)[index++], separator); + match = NalUnit::StartSequenceMatchSucc(match, (*message)[index++], separator); if (match == NUSM_longMatch || match == NUSM_shortMatch) { match = NUSM_noMatch; break; @@ -113,7 +61,7 @@ shared_ptr H264RtpPacketizer::splitMessage(binary_ptr message) { size_t naluStartIndex = index; while (index < message->size()) { - match = StartSequenceMatchSucc(match, (*message)[index], separator); + match = NalUnit::StartSequenceMatchSucc(match, (*message)[index], separator); if (match == NUSM_longMatch || match == NUSM_shortMatch) { auto sequenceLength = match == NUSM_longMatch ? 4 : 3; size_t naluEndIndex = index - sequenceLength; @@ -135,9 +83,9 @@ shared_ptr H264RtpPacketizer::splitMessage(binary_ptr message) { H264RtpPacketizer::H264RtpPacketizer(shared_ptr rtpConfig, uint16_t maximumFragmentSize) : RtpPacketizer(rtpConfig), MediaHandlerRootElement(), maximumFragmentSize(maximumFragmentSize), - separator(Separator::Length) {} + separator(NalUnit::Separator::Length) {} -H264RtpPacketizer::H264RtpPacketizer(H264RtpPacketizer::Separator separator, +H264RtpPacketizer::H264RtpPacketizer(NalUnit::Separator separator, shared_ptr rtpConfig, uint16_t maximumFragmentSize) : RtpPacketizer(rtpConfig), MediaHandlerRootElement(), maximumFragmentSize(maximumFragmentSize), diff --git a/src/h265rtppacketizer.cpp b/src/h265rtppacketizer.cpp index 59a9fe69c..1f40c6a41 100644 --- a/src/h265rtppacketizer.cpp +++ b/src/h265rtppacketizer.cpp @@ -22,61 +22,9 @@ namespace rtc { -typedef enum { - NUSM_noMatch, - NUSM_firstZero, - NUSM_secondZero, - NUSM_thirdZero, - NUSM_shortMatch, - NUSM_longMatch -} NalUnitStartSequenceMatch; - -NalUnitStartSequenceMatch StartSequenceMatchSucc(NalUnitStartSequenceMatch match, byte _byte, - H265RtpPacketizer::Separator separator) { - assert(separator != H265RtpPacketizer::Separator::Length); - auto byte = (uint8_t)_byte; - auto detectShort = separator == H265RtpPacketizer::Separator::ShortStartSequence || - separator == H265RtpPacketizer::Separator::StartSequence; - auto detectLong = separator == H265RtpPacketizer::Separator::LongStartSequence || - separator == H265RtpPacketizer::Separator::StartSequence; - switch (match) { - case NUSM_noMatch: - if (byte == 0x00) { - return NUSM_firstZero; - } - break; - case NUSM_firstZero: - if (byte == 0x00) { - return NUSM_secondZero; - } - break; - case NUSM_secondZero: - if (byte == 0x00 && detectLong) { - return NUSM_thirdZero; - } else if (byte == 0x00 && detectShort) { - return NUSM_secondZero; - } else if (byte == 0x01 && detectShort) { - return NUSM_shortMatch; - } - break; - case NUSM_thirdZero: - if (byte == 0x00 && detectLong) { - return NUSM_thirdZero; - } else if (byte == 0x01 && detectLong) { - return NUSM_longMatch; - } - break; - case NUSM_shortMatch: - return NUSM_shortMatch; - case NUSM_longMatch: - return NUSM_longMatch; - } - return NUSM_noMatch; -} - shared_ptr H265RtpPacketizer::splitMessage(binary_ptr message) { auto nalus = std::make_shared(); - if (separator == Separator::Length) { + if (separator == NalUnit::Separator::Length) { size_t index = 0; while (index < message->size()) { assert(index + 4 < message->size()); @@ -103,7 +51,7 @@ shared_ptr H265RtpPacketizer::splitMessage(binary_ptr message) { NalUnitStartSequenceMatch match = NUSM_noMatch; size_t index = 0; while (index < message->size()) { - match = StartSequenceMatchSucc(match, (*message)[index++], separator); + match = NalUnit::StartSequenceMatchSucc(match, (*message)[index++], separator); if (match == NUSM_longMatch || match == NUSM_shortMatch) { match = NUSM_noMatch; break; @@ -113,7 +61,7 @@ shared_ptr H265RtpPacketizer::splitMessage(binary_ptr message) { size_t naluStartIndex = index; while (index < message->size()) { - match = StartSequenceMatchSucc(match, (*message)[index], separator); + match = NalUnit::StartSequenceMatchSucc(match, (*message)[index], separator); if (match == NUSM_longMatch || match == NUSM_shortMatch) { auto sequenceLength = match == NUSM_longMatch ? 4 : 3; size_t naluEndIndex = index - sequenceLength; @@ -135,9 +83,9 @@ shared_ptr H265RtpPacketizer::splitMessage(binary_ptr message) { H265RtpPacketizer::H265RtpPacketizer(shared_ptr rtpConfig, uint16_t maximumFragmentSize) : RtpPacketizer(rtpConfig), MediaHandlerRootElement(), maximumFragmentSize(maximumFragmentSize), - separator(Separator::Length) {} + separator(NalUnit::Separator::Length) {} -H265RtpPacketizer::H265RtpPacketizer(H265RtpPacketizer::Separator separator, +H265RtpPacketizer::H265RtpPacketizer(NalUnit::Separator separator, shared_ptr rtpConfig, uint16_t maximumFragmentSize) : RtpPacketizer(rtpConfig), MediaHandlerRootElement(), maximumFragmentSize(maximumFragmentSize), From 3ab9d06829e0967678efa48a22c420ce493fbfbb Mon Sep 17 00:00:00 2001 From: Zita Liao Date: Mon, 21 Aug 2023 16:54:09 +1000 Subject: [PATCH 3/4] fix build error --- examples/streamer/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/streamer/main.cpp b/examples/streamer/main.cpp index b14398516..ecdbfe168 100644 --- a/examples/streamer/main.cpp +++ b/examples/streamer/main.cpp @@ -210,7 +210,7 @@ shared_ptr addVideo(const shared_ptr pc, const // create RTP configuration auto rtpConfig = make_shared(ssrc, cname, payloadType, H264RtpPacketizer::defaultClockRate); // create packetizer - auto packetizer = make_shared(H264RtpPacketizer::Separator::Length, rtpConfig); + auto packetizer = make_shared(NalUnit::Separator::Length, rtpConfig); // create H264 handler auto h264Handler = make_shared(packetizer); // add RTCP SR handler From 43c9ea315a8d83eeb124181774053e7eb3275373 Mon Sep 17 00:00:00 2001 From: Zita Liao Date: Thu, 31 Aug 2023 12:18:13 +1000 Subject: [PATCH 4/4] Fix for review comment --- include/rtc/h264rtppacketizer.hpp | 6 ++++-- include/rtc/h265nalunit.hpp | 2 +- include/rtc/h265packetizationhandler.hpp | 2 +- include/rtc/h265rtppacketizer.hpp | 2 +- src/h264rtppacketizer.cpp | 6 +++--- src/h265nalunit.cpp | 2 +- src/h265packetizationhandler.cpp | 2 +- src/h265rtppacketizer.cpp | 2 +- 8 files changed, 13 insertions(+), 11 deletions(-) diff --git a/include/rtc/h264rtppacketizer.hpp b/include/rtc/h264rtppacketizer.hpp index 28b9ba262..8f7282e76 100644 --- a/include/rtc/h264rtppacketizer.hpp +++ b/include/rtc/h264rtppacketizer.hpp @@ -23,11 +23,13 @@ class RTC_CPP_EXPORT H264RtpPacketizer final : public RtpPacketizer, shared_ptr splitMessage(binary_ptr message); const uint16_t maximumFragmentSize; +using Separator=NalUnit::Separator; + public: /// Default clock rate for H264 in RTP inline static const uint32_t defaultClockRate = 90 * 1000; - H264RtpPacketizer(NalUnit::Separator separator, + H264RtpPacketizer(Separator separator, shared_ptr rtpConfig, uint16_t maximumFragmentSize = NalUnits::defaultMaximumFragmentSize); @@ -43,7 +45,7 @@ class RTC_CPP_EXPORT H264RtpPacketizer final : public RtpPacketizer, message_ptr control) override; private: - const NalUnit::Separator separator; + const Separator separator; }; } // namespace rtc diff --git a/include/rtc/h265nalunit.hpp b/include/rtc/h265nalunit.hpp index 4e66c38fc..911996e2f 100644 --- a/include/rtc/h265nalunit.hpp +++ b/include/rtc/h265nalunit.hpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2020 Filip Klembara (in2core) + * Copyright (c) 2023 Zita Liao (Dolby) * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/include/rtc/h265packetizationhandler.hpp b/include/rtc/h265packetizationhandler.hpp index fb34ae450..11009d7d7 100644 --- a/include/rtc/h265packetizationhandler.hpp +++ b/include/rtc/h265packetizationhandler.hpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2020 Filip Klembara (in2core) + * Copyright (c) 2023 Zita Liao (Dolby) * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/include/rtc/h265rtppacketizer.hpp b/include/rtc/h265rtppacketizer.hpp index a2ca5bf6f..29a3b7d0a 100644 --- a/include/rtc/h265rtppacketizer.hpp +++ b/include/rtc/h265rtppacketizer.hpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2020 Filip Klembara (in2core) + * Copyright (c) 2023 Zita Liao (Dolby) * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/src/h264rtppacketizer.cpp b/src/h264rtppacketizer.cpp index 458487886..e64b983c7 100644 --- a/src/h264rtppacketizer.cpp +++ b/src/h264rtppacketizer.cpp @@ -24,7 +24,7 @@ namespace rtc { shared_ptr H264RtpPacketizer::splitMessage(binary_ptr message) { auto nalus = std::make_shared(); - if (separator == NalUnit::Separator::Length) { + if (separator == Separator::Length) { size_t index = 0; while (index < message->size()) { assert(index + 4 < message->size()); @@ -83,9 +83,9 @@ shared_ptr H264RtpPacketizer::splitMessage(binary_ptr message) { H264RtpPacketizer::H264RtpPacketizer(shared_ptr rtpConfig, uint16_t maximumFragmentSize) : RtpPacketizer(rtpConfig), MediaHandlerRootElement(), maximumFragmentSize(maximumFragmentSize), - separator(NalUnit::Separator::Length) {} + separator(Separator::Length) {} -H264RtpPacketizer::H264RtpPacketizer(NalUnit::Separator separator, +H264RtpPacketizer::H264RtpPacketizer(Separator separator, shared_ptr rtpConfig, uint16_t maximumFragmentSize) : RtpPacketizer(rtpConfig), MediaHandlerRootElement(), maximumFragmentSize(maximumFragmentSize), diff --git a/src/h265nalunit.cpp b/src/h265nalunit.cpp index ab6ac7978..369d80269 100644 --- a/src/h265nalunit.cpp +++ b/src/h265nalunit.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2020 Filip Klembara (in2core) + * Copyright (c) 2023 Zita Liao (Dolby) * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/src/h265packetizationhandler.cpp b/src/h265packetizationhandler.cpp index d4ba59157..e0783b6c7 100644 --- a/src/h265packetizationhandler.cpp +++ b/src/h265packetizationhandler.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2020 Filip Klembara (in2core) + * Copyright (c) 2023 Zita Liao (Dolby) * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/src/h265rtppacketizer.cpp b/src/h265rtppacketizer.cpp index 1f40c6a41..514aeeb18 100644 --- a/src/h265rtppacketizer.cpp +++ b/src/h265rtppacketizer.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2020 Filip Klembara (in2core) + * Copyright (c) 2023 Zita Liao (Dolby) * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this