diff --git a/examples/v3c_receiver.cc b/examples/v3c_receiver.cc index 3d527a4..9c5d4ca 100644 --- a/examples/v3c_receiver.cc +++ b/examples/v3c_receiver.cc @@ -42,7 +42,7 @@ int main(void) uvgrtp::context ctx; uvgrtp::session* sess = ctx.create_session(LOCAL_ADDRESS, LOCAL_ADDRESS); - int flags = RCE_RECEIVE_ONLY; + int flags = RCE_RECEIVE_ONLY | RCE_NO_H26X_PREPEND_SC; uvgrtp::media_stream* v3c = sess->create_stream(7790, 8890, RTP_FORMAT_V3C, flags); uvgrtp::media_stream* avc = sess->create_stream(7792, 8892, RTP_FORMAT_H265, flags); vbytes_received = 0; @@ -74,6 +74,7 @@ int main(void) std::this_thread::sleep_for(RECEIVE_TIME_S); // lets this example run for some time std::cout << "V3C Total bytes received " << vbytes_received << std::endl; std::cout << "Video Total bytes received " << abytes_received << std::endl; + std::cout << "All Total bytes received " << abytes_received + vbytes_received << std::endl; cleanup(ctx, sess, v3c); cleanup(ctx, sess, avc); diff --git a/examples/v3c_sender.cc b/examples/v3c_sender.cc index b9b2d35..9f1333a 100644 --- a/examples/v3c_sender.cc +++ b/examples/v3c_sender.cc @@ -14,8 +14,8 @@ constexpr size_t PAYLOAD_LEN = 100; constexpr int AMOUNT_OF_TEST_PACKETS = 100; constexpr auto END_WAIT = std::chrono::seconds(5); -//std::string PATH = "C:\\Users\\ngheta\\Documents\\TMIV_A3_C_QP3.bit"; -std::string PATH = "C:\\Users\\ngheta\\Documents\\test_seq3.vpcc"; +std::string PATH = "C:\\Users\\ngheta\\Documents\\TMIV_A3_C_QP3.bit"; +//std::string PATH = "C:\\Users\\ngheta\\Documents\\test_seq3.vpcc"; int main(void) { @@ -23,11 +23,14 @@ int main(void) /* A V3C Sample stream is divided into 6 types of 'sub-bitstreams' + parameters. - The nal_map holds nal_info structs - - nal_info struct holds the format(V3C, H264, H265, H266), start position and size of the NAL unit + - nal_info struct holds the format(Atlas, H264, H265, H266), start position and size of the NAL unit - With this info you can send the data via different uvgRTP media streams. Usually 2 streams, one in RTP_FORMAT_V3C for - Atlas NAL units and a second one for the video NAL units in the correct format*/ + Atlas NAL units and a second one for the video NAL units in the correct format + + Note: Use RTP_NO_H26X_SCL when sending video frames, as there is no start codes in the video sub-streams */ std::vector nal_map = {}; + std::vector vps_map = {}; /* Fetch the file and its size */ uint64_t len = get_size(PATH); @@ -36,8 +39,7 @@ int main(void) cbuf = get_cmem(PATH, len); /* Map the locations and sizes of Atlas and video NAL units with the mmap_v3c_file function */ - vuh_vps parameters = {}; - mmap_v3c_file(cbuf, len, parameters, nal_map); + mmap_v3c_file(cbuf, len, nal_map, vps_map); std::cout << "Sending Atlas NAL units via uvgRTP" << std::endl; @@ -49,19 +51,19 @@ int main(void) rtp_format_t video_format = RTP_FORMAT_GENERIC; // Create the uvgRTP media stream with the correct RTP format - if (parameters.ptl.ptl_profile_codec_group_idc == CODEC_AVC) { + if (vps_map.begin()->ptl.ptl_profile_codec_group_idc == CODEC_AVC) { std::cout << "Video codec: AVC Progressive High" << std::endl; video_format = RTP_FORMAT_H264; } - else if (parameters.ptl.ptl_profile_codec_group_idc == CODEC_HEVC_MAIN10) { + else if (vps_map.begin()->ptl.ptl_profile_codec_group_idc == CODEC_HEVC_MAIN10) { std::cout << "Video codec: HEVC Main10" << std::endl; video_format = RTP_FORMAT_H265; } - else if (parameters.ptl.ptl_profile_codec_group_idc == CODEC_HEVC444) { + else if (vps_map.begin()->ptl.ptl_profile_codec_group_idc == CODEC_HEVC444) { std::cout << "Video codec: HEVC444" << std::endl; video_format = RTP_FORMAT_H265; } - else if (parameters.ptl.ptl_profile_codec_group_idc == CODEC_VVC_MAIN10) { + else if (vps_map.begin()->ptl.ptl_profile_codec_group_idc == CODEC_VVC_MAIN10) { std::cout << "Video codec: VVC Main10" << std::endl; video_format = RTP_FORMAT_H266; } diff --git a/include/uvgrtp/v3c_parser.hh b/include/uvgrtp/v3c_parser.hh index 527a433..1d65930 100644 --- a/include/uvgrtp/v3c_parser.hh +++ b/include/uvgrtp/v3c_parser.hh @@ -27,6 +27,14 @@ constexpr uint8_t VVC_SC = 0x00000001; // VVC Start Code struct profile_tier_level { uint8_t ptl_tier_flag = 0; uint8_t ptl_profile_codec_group_idc = 0; + uint8_t ptl_profile_toolset_idc = 0; + uint8_t ptl_profile_reconstruction_idc = 0; + uint8_t ptl_max_decodes_idc = 0; + uint8_t ptl_level_idc = 0; + uint8_t ptl_num_sub_profiles = 0; + bool ptl_extended_sub_profile_flag = 0; + std::vector ptl_sub_profile_idc; + bool ptl_toolset_constraints_present_flag = 0; }; struct vuh_vps { profile_tier_level ptl; @@ -72,6 +80,10 @@ struct v3c_unit_header { vuh_pvd pvd; vuh_cad cad; }; + ~v3c_unit_header() { + vps.~vuh_vps(); + } + }; struct nal_info { @@ -88,5 +100,5 @@ uint64_t get_size(std::string filename); char* get_cmem(std::string filename, const size_t& len); // ad is for AD and CAD substreams, vd is for all VD substreams -bool mmap_v3c_file(char* cbuf, uint64_t len, vuh_vps& param, std::vector& nal_map); +bool mmap_v3c_file(char* cbuf, uint64_t len, std::vector& nal_map, std::vector &vps_map); void parse_v3c_header(v3c_unit_header &hdr, char* buf, uint64_t ptr); \ No newline at end of file diff --git a/src/v3c_parser.cc b/src/v3c_parser.cc index 84f14f7..4aa9f61 100644 --- a/src/v3c_parser.cc +++ b/src/v3c_parser.cc @@ -18,7 +18,7 @@ uint32_t combineBytes(uint8_t byte1, uint8_t byte2) { (static_cast(byte2)); } -bool mmap_v3c_file(char* cbuf, uint64_t len, vuh_vps& param, std::vector& nal_map) +bool mmap_v3c_file(char* cbuf, uint64_t len, std::vector& nal_map, std::vector& vps_map) { uint64_t ptr = 0; @@ -32,7 +32,6 @@ bool mmap_v3c_file(char* cbuf, uint64_t len, vuh_vps& param, std::vector sizes = {}; uint8_t nal_size_precision = 0; while (true) { if (ptr >= len) { @@ -66,18 +65,12 @@ bool mmap_v3c_file(char* cbuf, uint64_t len, vuh_vps& param, std::vector> 7; @@ -171,8 +163,51 @@ void parse_v3c_header(v3c_unit_header &hdr, char* buf, uint64_t ptr) // 7 bits after hdr.vps.ptl.ptl_profile_codec_group_idc = buf[ptr + 4] & 0b01111111; std::cout << "-- ptl_profile_codec_group_idc: " << (uint32_t)hdr.vps.ptl.ptl_profile_codec_group_idc << std::endl; + // 8 bits after + hdr.vps.ptl.ptl_profile_toolset_idc = buf[ptr + 5]; + std::cout << "-- ptl_profile_toolset_idc: " << (uint32_t)hdr.vps.ptl.ptl_profile_toolset_idc << std::endl; + // 8 bits after + hdr.vps.ptl.ptl_profile_reconstruction_idc = buf[ptr + 6]; + std::cout << "-- ptl_profile_reconstruction_idc: " << (uint32_t)hdr.vps.ptl.ptl_profile_reconstruction_idc << std::endl; + // 16 reserved bits + //4 bits after + hdr.vps.ptl.ptl_max_decodes_idc = buf[ptr + 9] >> 4; + std::cout << "-- ptl_max_decodes_idc: " << (uint32_t)hdr.vps.ptl.ptl_max_decodes_idc << "+1 = " << + (uint32_t)hdr.vps.ptl.ptl_max_decodes_idc + 1 << std::endl; + // 12 reserved bits + // 8 bits after + hdr.vps.ptl.ptl_level_idc = buf[ptr + 11]; + std::cout << "-- ptl_level_idc: " << (uint32_t)hdr.vps.ptl.ptl_level_idc << "/30 = " << + (double)hdr.vps.ptl.ptl_level_idc / 30 << std::endl; + // 6 bits after + hdr.vps.ptl.ptl_num_sub_profiles = buf[ptr + 12] >> 2; + std::cout << "-- ptl_num_sub_profiles: " << (uint32_t)hdr.vps.ptl.ptl_num_sub_profiles << std::endl; + // 1 bit after + hdr.vps.ptl.ptl_extended_sub_profile_flag = (buf[ptr + 12] & 0b10) >> 1; + std::cout << "-- ptl_extended_sub_profile_flag: " << (uint32_t)hdr.vps.ptl.ptl_extended_sub_profile_flag << std::endl; + // next up are the sub-profile IDs. They can be either 32 or 64 bits long, indicated by ptl_extended_sub_profile_flag + // Note: This has not been tested. But it should work + ptr += 12; + uint64_t first_full_byte = ptr + 13; + if (hdr.vps.ptl.ptl_extended_sub_profile_flag == 1) { + for (int i = 0; i < hdr.vps.ptl.ptl_num_sub_profiles; i++) { + uint64_t sub_profile_id = (buf[first_full_byte] >> 1) | ((buf[first_full_byte - 1] & 0b1) << 63); + hdr.vps.ptl.ptl_sub_profile_idc.push_back(sub_profile_id); + first_full_byte += 8; + } + } + else { + for (int i = 0; i < hdr.vps.ptl.ptl_num_sub_profiles; i++) { + uint32_t sub_profile_id = (buf[first_full_byte] >> 1) | ((buf[first_full_byte - 1] & 0b1) << 31); + hdr.vps.ptl.ptl_sub_profile_idc.push_back((uint64_t)sub_profile_id); + first_full_byte += 4; + } + } + // 1 bit after + hdr.vps.ptl.ptl_toolset_constraints_present_flag = (buf[ptr] & 0b1); + std::cout << "-- ptl_toolset_constraints_present_flag: " << (uint32_t)hdr.vps.ptl.ptl_toolset_constraints_present_flag << std::endl; break; - + } case V3C_AD: hdr.ad = {}; hdr.ad.vuh_v3c_parameter_set_id = vuh_v3c_parameter_set_id;