diff --git a/CMakeLists.txt b/CMakeLists.txt index 6bf1a35..b079433 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,6 +82,7 @@ target_sources(${PROJECT_NAME} PRIVATE src/formats/h264.cc src/formats/h265.cc src/formats/h266.cc + src/formats/v3c.cc src/zrtp/zrtp_receiver.cc src/zrtp/hello.cc @@ -130,6 +131,7 @@ target_sources(${PROJECT_NAME} PRIVATE src/formats/h265.hh src/formats/h266.hh src/formats/media.hh + src/formats/v3c.hh src/srtp/base.hh src/srtp/srtcp.hh diff --git a/include/uvgrtp/util.hh b/include/uvgrtp/util.hh index 0812c53..04cf5e3 100644 --- a/include/uvgrtp/util.hh +++ b/include/uvgrtp/util.hh @@ -123,7 +123,8 @@ typedef enum RTP_FORMAT { // H263-1998 is unsupported in uvgRTP RTP_FORMAT_H264 = 106, ///< H.264/AVC, see RFC 6184 RTP_FORMAT_H265 = 107, ///< H.265/HEVC, see RFC 7798 - RTP_FORMAT_H266 = 108 ///< H.266/VVC + RTP_FORMAT_H266 = 108, ///< H.266/VVC + RTP_FORMAT_V3C = 109 ///< V3C } rtp_format_t; diff --git a/src/formats/v3c.cc b/src/formats/v3c.cc new file mode 100644 index 0000000..bc2cee4 --- /dev/null +++ b/src/formats/v3c.cc @@ -0,0 +1,118 @@ +#include "v3c.hh" + +#include "uvgrtp/frame.hh" + +#include "../rtp.hh" +#include "../frame_queue.hh" +#include "debug.hh" + +#include +#include +#include +#include +#include +#include +#include + + +#ifndef _WIN32 +#include +#endif + + + +uvgrtp::formats::v3c::v3c(std::shared_ptr socket, std::shared_ptr rtp, int rce_flags) : + h26x(socket, rtp, rce_flags) +{} + +uvgrtp::formats::v3c::~v3c() +{ +} + +uint8_t uvgrtp::formats::v3c::get_payload_header_size() const +{ + return HEADER_SIZE_V3C_PAYLOAD; +} + +uint8_t uvgrtp::formats::v3c::get_nal_header_size() const +{ + return HEADER_SIZE_V3C_NAL; +} + +uint8_t uvgrtp::formats::v3c::get_fu_header_size() const +{ + return HEADER_SIZE_V3C_FU; +} + +uint8_t uvgrtp::formats::v3c::get_start_code_range() const +{ + return 4; +} + +uvgrtp::formats::NAL_TYPE uvgrtp::formats::v3c::get_nal_type(uvgrtp::frame::rtp_frame* frame) const +{ + uint8_t nal_type = frame->payload[2] & 0x3f; + /* + if (nal_type == H266_IDR_W_RADL) + return uvgrtp::formats::NAL_TYPE::NT_INTRA; + else if (nal_type == H266_TRAIL_NUT) + return uvgrtp::formats::NAL_TYPE::NT_INTER; + */ + return uvgrtp::formats::NAL_TYPE::NT_OTHER; +} + +uint8_t uvgrtp::formats::v3c::get_nal_type(uint8_t* data) const +{ + //return (data[1] >> 3) & 0x1f; + return data[0] & 0x10F447; +} + +uvgrtp::formats::FRAG_TYPE uvgrtp::formats::v3c::get_fragment_type(uvgrtp::frame::rtp_frame* frame) const +{ + // Same bits as in VVC FU headers + bool first_frag = frame->payload[2] & 0x80; + bool last_frag = frame->payload[2] & 0x40; + + if ((frame->payload[1] >> 3) != uvgrtp::formats::V3C_PKT_FRAG) + return uvgrtp::formats::FRAG_TYPE::FT_NOT_FRAG; // Single NAL unit + + if (first_frag && last_frag) + return uvgrtp::formats::FRAG_TYPE::FT_INVALID; + + if (first_frag) + return uvgrtp::formats::FRAG_TYPE::FT_START; + + if (last_frag) + return uvgrtp::formats::FRAG_TYPE::FT_END; + + return uvgrtp::formats::FRAG_TYPE::FT_MIDDLE; +} + +void uvgrtp::formats::v3c::get_nal_header_from_fu_headers(size_t fptr, uint8_t* frame_payload, uint8_t* complete_payload) +{ + uint8_t payload_header[2] = { + (uint8_t)((frame_payload[0])), + (uint8_t)((frame_payload[1] & 0x7) | ((frame_payload[2] & 0x3f) << 3)) + }; + + std::memcpy(&complete_payload[fptr], payload_header, get_payload_header_size()); +} + + +rtp_error_t uvgrtp::formats::v3c::fu_division(uint8_t* data, size_t data_len, size_t payload_size) +{ + auto headers = (uvgrtp::formats::v3c_headers*)fqueue_->get_media_headers(); + + headers->payload_header[0] = data[0]; + headers->payload_header[1] = (V3C_PKT_FRAG << 3) | (data[1] & 0x7); + + initialize_fu_headers(get_nal_type(data), headers->fu_headers); + + uvgrtp::buf_vec* buffers = fqueue_->get_buffer_vector(); + + buffers->push_back(std::make_pair(sizeof(headers->payload_header), headers->payload_header)); + buffers->push_back(std::make_pair(sizeof(uint8_t), &headers->fu_headers[0])); + buffers->push_back(std::make_pair(payload_size, nullptr)); + + return divide_frame_to_fus(data, data_len, payload_size, *buffers, headers->fu_headers); +} \ No newline at end of file diff --git a/src/formats/v3c.hh b/src/formats/v3c.hh new file mode 100644 index 0000000..118b95f --- /dev/null +++ b/src/formats/v3c.hh @@ -0,0 +1,73 @@ +#pragma once + +#include "uvgrtp/util.hh" +#include "uvgrtp/clock.hh" +#include "uvgrtp/frame.hh" + +#include "h26x.hh" +#include "socket.hh" + +#include +#include + +namespace uvgrtp { + + class rtp; + + namespace formats { + + constexpr uint8_t HEADER_SIZE_V3C_PAYLOAD = 2; + constexpr uint8_t HEADER_SIZE_V3C_NAL = 2; + constexpr uint8_t HEADER_SIZE_V3C_FU = 1; + + enum V3C_NAL_TYPES { + NAL_BLA_W_LP, + NAL_RSV_IRAP_ACL_29 + }; + + enum V3C_PKT_TYPES { + V3C_PKT_AGGR = 56, + V3C_PKT_FRAG = 58 + }; + + struct v3c_aggregation_packet { + uint8_t payload_header[HEADER_SIZE_V3C_PAYLOAD]; + uvgrtp::buf_vec nalus; /* discrete NAL units */ + uvgrtp::buf_vec aggr_pkt; /* crafted aggregation packet */ + }; + + struct v3c_headers { + uint8_t payload_header[HEADER_SIZE_V3C_PAYLOAD]; + + /* there are three types of Fragmentation Unit headers: + * - header for the first fragment + * - header for all middle fragments + * - header for the last fragment */ + uint8_t fu_headers[3 * HEADER_SIZE_V3C_FU]; + }; + + class v3c : public h26x { + public: + v3c(std::shared_ptr socket, std::shared_ptr rtp, int rce_flags); + ~v3c(); + + protected: + + // constructs v3c RTP header with correct values + virtual rtp_error_t fu_division(uint8_t* data, size_t data_len, size_t payload_size); + + virtual uint8_t get_nal_type(uint8_t* data) const; + + virtual void get_nal_header_from_fu_headers(size_t fptr, uint8_t* frame_payload, uint8_t* complete_payload); + + virtual uint8_t get_payload_header_size() const; + virtual uint8_t get_nal_header_size() const; + virtual uint8_t get_fu_header_size() const; + virtual uint8_t get_start_code_range() const; + virtual uvgrtp::formats::FRAG_TYPE get_fragment_type(uvgrtp::frame::rtp_frame* frame) const; + virtual uvgrtp::formats::NAL_TYPE get_nal_type(uvgrtp::frame::rtp_frame* frame) const; + }; + } +} + +namespace uvg_rtp = uvgrtp; diff --git a/src/media_stream.cc b/src/media_stream.cc index 095c746..761bc90 100644 --- a/src/media_stream.cc +++ b/src/media_stream.cc @@ -5,6 +5,7 @@ #include "formats/h264.hh" #include "formats/h265.hh" #include "formats/h266.hh" +#include "formats/v3c.hh" #include "debug.hh" #include "random.hh" #include "rtp.hh" @@ -224,6 +225,20 @@ rtp_error_t uvgrtp::media_stream::create_media(rtp_format_t fmt) media_.reset(format_266); break; } + case RTP_FORMAT_V3C: + { + uvgrtp::formats::v3c* format_v3c = new uvgrtp::formats::v3c(socket_, rtp_, rce_flags_); + reception_flow_->install_handler( + 5, remote_ssrc_, + std::bind(&uvgrtp::formats::v3c::packet_handler, format_v3c, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, + std::placeholders::_4, std::placeholders::_5), nullptr + ); + reception_flow_->install_getter(remote_ssrc_, + std::bind(&uvgrtp::formats::v3c::frame_getter, format_v3c, std::placeholders::_1)); + + media_.reset(format_v3c); + break; + } case RTP_FORMAT_OPUS: case RTP_FORMAT_PCMU: case RTP_FORMAT_GSM: