diff --git a/examples/v3c_receiver.cc b/examples/v3c_receiver.cc index c5508709..414ed119 100644 --- a/examples/v3c_receiver.cc +++ b/examples/v3c_receiver.cc @@ -36,7 +36,6 @@ void ovd_receive_hook(void* arg, uvgrtp::frame::rtp_frame* frame); void gvd_receive_hook(void* arg, uvgrtp::frame::rtp_frame* frame); void avd_receive_hook(void* arg, uvgrtp::frame::rtp_frame* frame); -void copy_rtp_payload(std::vector &units, uint64_t max_size, uvgrtp::frame::rtp_frame* frame); uint64_t vps_count; constexpr int VPS_NALS = 1; @@ -48,57 +47,29 @@ std::string PATH = "C:\\Users\\ngheta\\Documents\\v3c_test_seq_2.vpcc"; int main(void) { - std::cout << "Starting uvgRTP RTP receive hook example" << std::endl; + std::cout << "Starting uvgRTP V3C receive hook example" << std::endl; /* Fetch the original file and its size */ uint64_t len = get_size(PATH); std::cout << "File size " << len << std::endl; char* original_buf = nullptr; - original_buf = get_cmem(PATH, len); + original_buf = get_cmem(PATH); uvgrtp::context ctx; uvgrtp::session* sess = ctx.create_session(LOCAL_ADDRESS, LOCAL_ADDRESS); - int flags = RCE_RECEIVE_ONLY | RCE_NO_H26X_PREPEND_SC; + int flags = RCE_RECEIVE_ONLY; // Create the uvgRTP media streams with the correct RTP format - uvgrtp::media_stream* vps = sess->create_stream(8891, 8890, RTP_FORMAT_GENERIC, flags); - uvgrtp::media_stream* ad = sess->create_stream(8893, 8892, RTP_FORMAT_ATLAS, flags); - uvgrtp::media_stream* ovd = sess->create_stream(8895, 8894, RTP_FORMAT_H265, flags); - uvgrtp::media_stream* gvd = sess->create_stream(8897, 8896, RTP_FORMAT_H265, flags); - uvgrtp::media_stream* avd = sess->create_stream(8899, 8898, RTP_FORMAT_H265, flags); - avd->configure_ctx(RCC_RING_BUFFER_SIZE, 40*1000*1000); + v3c_streams streams = init_v3c_streams(sess, 8890, 8892, flags, true); + //avd->configure_ctx(RCC_RING_BUFFER_SIZE, 40*1000*1000); + v3c_file_map mmap = init_mmap(); - char* out_buf = new char[len]; - v3c_file_map mmap = {}; - - - v3c_unit_header hdr = { V3C_AD }; - hdr.ad = { 0, 0 }; - v3c_unit_info unit = { hdr, {}, new char[40 * 1000 * 1000], 0, false }; - mmap.ad_units.push_back(unit); - - hdr = { V3C_OVD }; - hdr.ovd = { 0, 0 }; - unit = { hdr, {}, new char[40 * 1000 * 1000], 0, false }; - mmap.ovd_units.push_back(unit); - - hdr = { V3C_GVD }; - hdr.gvd = { 0, 0 }; - unit = { hdr, {}, new char[40 * 1000 * 1000], 0, false }; - mmap.gvd_units.push_back(unit); - - hdr = { V3C_AVD }; - hdr.avd = { 0, 0 }; - unit = { hdr, {}, new char[40 * 1000 * 1000], 0, false }; - mmap.avd_units.push_back(unit); - - - vps->install_receive_hook(&mmap.vps_units, vps_receive_hook); - ad->install_receive_hook(&mmap.ad_units, ad_receive_hook); - ovd->install_receive_hook(&mmap.ovd_units, ovd_receive_hook); - gvd->install_receive_hook(&mmap.gvd_units, gvd_receive_hook); - avd->install_receive_hook(&mmap.avd_units, avd_receive_hook); + streams.vps->install_receive_hook(&mmap.vps_units, vps_receive_hook); + streams.ad->install_receive_hook(&mmap.ad_units, ad_receive_hook); + streams.ovd->install_receive_hook(&mmap.ovd_units, ovd_receive_hook); + streams.gvd->install_receive_hook(&mmap.gvd_units, gvd_receive_hook); + streams.avd->install_receive_hook(&mmap.avd_units, avd_receive_hook); std::cout << "Waiting incoming packets for " << RECEIVE_TIME_S.count() << " s" << std::endl; @@ -106,11 +77,13 @@ int main(void) uint64_t bytes = 0; uint64_t ptr = 0; bool hdb = true; + char* out_buf = new char[len]; + while (ngops <= 1) { if (is_gop_ready(ngops, mmap)) { std::cout << "Full GoP received, num: " << ngops << std::endl; bytes += reconstruct_v3c_gop(hdb, out_buf, ptr, mmap, ngops - 1); - std::cout << "File size " << bytes << std::endl; + std::cout << "GoP size " << bytes << std::endl; ngops++; hdb = false; @@ -120,11 +93,11 @@ int main(void) std::this_thread::sleep_for(RECEIVE_TIME_S); // lets this example run for some time - sess->destroy_stream(vps); - sess->destroy_stream(ad); - sess->destroy_stream(ovd); - sess->destroy_stream(gvd); - sess->destroy_stream(avd); + sess->destroy_stream(streams.vps); + sess->destroy_stream(streams.ad); + sess->destroy_stream(streams.ovd); + sess->destroy_stream(streams.gvd); + sess->destroy_stream(streams.avd); ctx.destroy_session(sess); @@ -141,50 +114,6 @@ int main(void) return EXIT_SUCCESS; } -void copy_rtp_payload(std::vector &units, uint64_t max_size, uvgrtp::frame::rtp_frame *frame) -{ - if ((units.end() - 1)->nal_infos.size() == max_size) { - std::cout << "AD size == 35, adding new v3c_unit " << std::endl; - v3c_unit_header hdr = {(units.end()-1)->header.vuh_unit_type}; - switch ((units.end()-1)->header.vuh_unit_type) { - case V3C_AD: { - hdr.ad = { (uint8_t)units.size(), 0 }; - v3c_unit_info info = { hdr, {}, new char[400 * 1000], 0, false }; - units.push_back(info); - break; - } - case V3C_OVD: { - hdr.ovd = { (uint8_t)units.size(), 0 }; - v3c_unit_info info = { hdr, {}, new char[400 * 1000], 0, false }; - units.push_back(info); - break; - } - case V3C_GVD: { - hdr.gvd = { (uint8_t)units.size(), 0, 0, 0 }; - v3c_unit_info info = { hdr, {}, new char[400 * 1000], 0, false }; - units.push_back(info); - break; - } - case V3C_AVD: { - hdr.avd = { (uint8_t)units.size(), 0 }; - v3c_unit_info info = { hdr, {}, new char[40 * 1000 * 1000], 0, false }; - units.push_back(info); - break; - } - } - } - auto ¤t = units.end() - 1; - - if (current->nal_infos.size() <= max_size) { - memcpy(¤t->buf[current->ptr], frame->payload, frame->payload_len); - current->nal_infos.push_back({ current->ptr, frame->payload_len }); - current->ptr += frame->payload_len; - } - if (current->nal_infos.size() == max_size) { - current->ready = true; - } -} - void vps_receive_hook(void* arg, uvgrtp::frame::rtp_frame* frame) { std::cout << "Received VPS frame, size: " << frame->payload_len << " bytes" << std::endl; @@ -203,14 +132,10 @@ void ad_receive_hook(void* arg, uvgrtp::frame::rtp_frame* frame) std::vector* vec = (std::vector*)arg; copy_rtp_payload(*vec, AD_NALS, frame); - - //std::cout << "Done with AD frame, num: " << current->nal_infos.size() << std::endl; - (void)uvgrtp::frame::dealloc_frame(frame); } void ovd_receive_hook(void* arg, uvgrtp::frame::rtp_frame* frame) { - //std::cout << "Received OVD frame, size: " << frame->payload_len << " bytes" << std::endl; std::vector* vec = (std::vector*)arg; copy_rtp_payload(*vec, OVD_NALS, frame); @@ -218,16 +143,13 @@ void ovd_receive_hook(void* arg, uvgrtp::frame::rtp_frame* frame) } void gvd_receive_hook(void* arg, uvgrtp::frame::rtp_frame* frame) { - //std::cout << "Received GVD frame, size: " << frame->payload_len << " bytes" << std::endl; std::vector* vec = (std::vector*)arg; - copy_rtp_payload(*vec, GVD_NALS, frame); (void)uvgrtp::frame::dealloc_frame(frame); } void avd_receive_hook(void* arg, uvgrtp::frame::rtp_frame* frame) { - //std::cout << "Received AVD frame, size: " << frame->payload_len << " bytes" << std::endl; std::vector* vec = (std::vector*)arg; copy_rtp_payload(*vec, AVD_NALS, frame); diff --git a/examples/v3c_sender.cc b/examples/v3c_sender.cc index 8ed67b5b..362f659d 100644 --- a/examples/v3c_sender.cc +++ b/examples/v3c_sender.cc @@ -19,7 +19,6 @@ std::string PATH = "C:\\Users\\ngheta\\Documents\\v3c_test_seq_2.vpcc"; void sender_func(uvgrtp::media_stream* stream, const char* cbuf, const std::vector &units, rtp_flags_t flags, int fmt); - int main(void) { std::cout << "Parsing V3C file" << std::endl; @@ -36,45 +35,35 @@ int main(void) /* Fetch the file and its size */ uint64_t len = get_size(PATH); - uint64_t ptr = 0; - char* cbuf = nullptr; - cbuf = get_cmem(PATH, len); + char* cbuf = get_cmem(PATH); /* Map the locations and sizes of Atlas and video NAL units with the mmap_v3c_file function */ mmap_v3c_file(cbuf, len, mmap); - std::cout << "Sending Atlas NAL units via uvgRTP" << std::endl; + std::cout << "Sending V3C NAL units via uvgRTP" << std::endl; /* Create the necessary uvgRTP media streams */ uvgrtp::context ctx; uvgrtp::session* sess = ctx.create_session(REMOTE_ADDRESS, REMOTE_ADDRESS); - int flags = RCE_NO_FLAGS; - - // Create the uvgRTP media streams with the correct RTP format - uvgrtp::media_stream* vps = sess->create_stream(8890, 8891, RTP_FORMAT_GENERIC, flags); - uvgrtp::media_stream* ad = sess->create_stream(8892, 8893, RTP_FORMAT_ATLAS, flags); - uvgrtp::media_stream* ovd = sess->create_stream(8894, 8895, RTP_FORMAT_H265, flags); - uvgrtp::media_stream* gvd = sess->create_stream(8896, 8897, RTP_FORMAT_H265, flags); - uvgrtp::media_stream* avd = sess->create_stream(8898, 8899, RTP_FORMAT_H265, flags); - - uint64_t send_ptr = 0; + int flags = RCE_SEND_ONLY; + v3c_streams streams = init_v3c_streams(sess, 8892, 8890, flags, false); /* Start sending data */ std::unique_ptr vps_thread = - std::unique_ptr(new std::thread(sender_func, vps, cbuf, mmap.vps_units, RTP_NO_FLAGS, V3C_VPS)); + std::unique_ptr(new std::thread(sender_func, streams.vps, cbuf, mmap.vps_units, RTP_NO_FLAGS, V3C_VPS)); std::unique_ptr ad_thread = - std::unique_ptr(new std::thread(sender_func, ad, cbuf, mmap.ad_units, RTP_NO_FLAGS, V3C_AD)); + std::unique_ptr(new std::thread(sender_func, streams.ad, cbuf, mmap.ad_units, RTP_NO_FLAGS, V3C_AD)); std::unique_ptr ovd_thread = - std::unique_ptr(new std::thread(sender_func, ovd, cbuf, mmap.ovd_units, RTP_NO_H26X_SCL, V3C_OVD)); + std::unique_ptr(new std::thread(sender_func, streams.ovd, cbuf, mmap.ovd_units, RTP_NO_H26X_SCL, V3C_OVD)); std::unique_ptr gvd_thread = - std::unique_ptr(new std::thread(sender_func, gvd, cbuf, mmap.gvd_units, RTP_NO_H26X_SCL, V3C_GVD)); + std::unique_ptr(new std::thread(sender_func, streams.gvd, cbuf, mmap.gvd_units, RTP_NO_H26X_SCL, V3C_GVD)); std::unique_ptr avd_thread = - std::unique_ptr(new std::thread(sender_func, avd, cbuf, mmap.avd_units, RTP_NO_H26X_SCL, V3C_AVD)); + std::unique_ptr(new std::thread(sender_func, streams.avd, cbuf, mmap.avd_units, RTP_NO_H26X_SCL, V3C_AVD)); if (vps_thread && vps_thread->joinable()) { @@ -97,11 +86,11 @@ int main(void) avd_thread->join(); } - sess->destroy_stream(vps); - sess->destroy_stream(ad); - sess->destroy_stream(ovd); - sess->destroy_stream(gvd); - sess->destroy_stream(avd); + sess->destroy_stream(streams.vps); + sess->destroy_stream(streams.ad); + sess->destroy_stream(streams.ovd); + sess->destroy_stream(streams.gvd); + sess->destroy_stream(streams.avd); std::cout << "Sending finished" << std::endl; @@ -116,38 +105,16 @@ int main(void) void sender_func(uvgrtp::media_stream* stream, const char* cbuf, const std::vector &units, rtp_flags_t flags, int fmt) { - std::string filename = "results_" + std::to_string(fmt) + ".csv"; - //std::ofstream myfile; - //myfile.open(filename); - //myfile << "Stream " + std::to_string(fmt) + ";;;Send time (microseconds) \n"; - //myfile << "NAL number;NAL size(bytes);Cumulative bytes sent; Send time at 100 MBps;1 GBps; 10 GBps \n"; - int index = 0; - uint64_t bytes_sent = 0; - for (auto& p : units) { for (auto i : p.nal_infos) { rtp_error_t ret = RTP_OK; //std::cout << "Sending NAL unit in location " << i.location << " with size " << i.size << std::endl; ret = stream->push_frame((uint8_t*)cbuf + i.location, i.size, flags); - if (ret == RTP_OK) { - index++; - bytes_sent += i.size; - double time_100m = bytes_sent / 100; // us so dont multiply *1000 * 1000; - double time_1g = bytes_sent / (1 * 1000); // us so dont multiply *1000 * 1000; - double time_10g = bytes_sent / (10 * 1000); // us so dont multiply *1000 * 1000; - std::string line = std::to_string(index) + ";" + std::to_string(i.size) + ";" + std::to_string(bytes_sent) + ";" - + std::to_string(time_100m) + ";" - + std::to_string(time_1g) + ";" - + std::to_string(time_10g) + ";" + "\n"; - - //myfile << line; - } - else { + if (ret != RTP_OK) { std::cout << "Failed to send RTP frame!" << std::endl; } } } - //myfile.close(); } diff --git a/include/uvgrtp/v3c_parser.hh b/include/uvgrtp/v3c_parser.hh index bd34fb2d..d9395f13 100644 --- a/include/uvgrtp/v3c_parser.hh +++ b/include/uvgrtp/v3c_parser.hh @@ -1,5 +1,7 @@ #pragma once +#include + #include #include #include @@ -24,27 +26,8 @@ enum CODEC { CODEC_VVC_MAIN10 = 3 // VVC Main10 }; -constexpr int V3C_HDR_LEN = 4; // 32 bits for v3c unit header - -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 parameter_set { - profile_tier_level ptl; - uint8_t vps_v3c_parameter_set_id = 0; - uint8_t vps_atlas_count_minus1 = 0; -}; +constexpr int V3C_HDR_LEN = 4; // 32 bits for v3c unit header + struct vuh_ad { uint8_t vuh_v3c_parameter_set_id = 0; uint8_t vuh_atlas_id = 0; @@ -110,24 +93,46 @@ struct v3c_file_map { std::vector cad_units = {}; }; +struct v3c_streams { + uvgrtp::media_stream* vps = nullptr; + uvgrtp::media_stream* ad = nullptr; + uvgrtp::media_stream* ovd = nullptr; + uvgrtp::media_stream* gvd = nullptr; + uvgrtp::media_stream* avd = nullptr; +}; + uint32_t combineBytes(uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4); uint32_t combineBytes(uint8_t byte1, uint8_t byte2, uint8_t byte3); uint32_t combineBytes(uint8_t byte1, uint8_t byte2); void convert_size_little_endian(uint32_t in, uint8_t* out, size_t output_size); void convert_size_big_endian(uint32_t in, uint8_t* out, size_t output_size); +// Get size of a file in bytes 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 +// Get a pointer to a file +char* get_cmem(std::string filename); + +// Memory map a V3C file bool mmap_v3c_file(char* cbuf, uint64_t len, v3c_file_map &mmap); + +// Parse a V3C header into mmap void parse_v3c_header(v3c_unit_header &hdr, char* buf, uint64_t ptr); -void parse_vps_ptl(profile_tier_level &ptl, char* buf, uint64_t ptr); +// Initialize a media stream for all 5 components of a V3C Stream +v3c_streams init_v3c_streams(uvgrtp::session* sess, uint16_t src_port, uint16_t dst_port, int flags, bool rec); + +// Initialize a memory map of a V3C file +v3c_file_map init_mmap(); -// Receiver functions +// Used in receiver_hooks to copy the received data +void copy_rtp_payload(std::vector& units, uint64_t max_size, uvgrtp::frame::rtp_frame* frame); + +// Combine a complete V3C unit from received NAL units void create_v3c_unit(v3c_unit_info& current_unit, char* buf, uint64_t& ptr, uint64_t v3c_precision, uint32_t nal_precision); -uint64_t reconstruct_v3c_gop(bool hdr_byte, char* buf, uint64_t& ptr, v3c_file_map& mmap, uint64_t index); +// Reconstruct a whole GoP from V3C Units +uint64_t reconstruct_v3c_gop(bool hdr_byte, char* buf, uint64_t& ptr, v3c_file_map& mmap, uint64_t index); +// Check if there is a complete GoP in the memory map bool is_gop_ready(uint64_t index, v3c_file_map& mmap); diff --git a/src/v3c_parser.cc b/src/v3c_parser.cc index 19099dbf..ed2ce1ca 100644 --- a/src/v3c_parser.cc +++ b/src/v3c_parser.cc @@ -259,65 +259,10 @@ void parse_v3c_header(v3c_unit_header &hdr, char* buf, uint64_t ptr) return; } -void parse_vps_ptl(profile_tier_level &ptl, char* buf, uint64_t ptr) -{ - // first bit of first byte - ptl.ptl_tier_flag = buf[ptr + 4] >> 7; - std::cout << "-- ptl_tier_flag: " << (uint32_t)ptl.ptl_tier_flag << std::endl; - // 7 bits after - ptl.ptl_profile_codec_group_idc = buf[ptr + 4] & 0b01111111; - std::cout << "-- ptl_profile_codec_group_idc: " << (uint32_t)ptl.ptl_profile_codec_group_idc << std::endl; - // 8 bits after - ptl.ptl_profile_toolset_idc = buf[ptr + 5]; - std::cout << "-- ptl_profile_toolset_idc: " << (uint32_t)ptl.ptl_profile_toolset_idc << std::endl; - // 8 bits after - ptl.ptl_profile_reconstruction_idc = buf[ptr + 6]; - std::cout << "-- ptl_profile_reconstruction_idc: " << (uint32_t)ptl.ptl_profile_reconstruction_idc << std::endl; - // 16 reserved bits - //4 bits after - ptl.ptl_max_decodes_idc = buf[ptr + 9] >> 4; - std::cout << "-- ptl_max_decodes_idc: " << (uint32_t)ptl.ptl_max_decodes_idc << "+1 = " << - (uint32_t)ptl.ptl_max_decodes_idc + 1 << std::endl; - // 12 reserved bits - // 8 bits after - ptl.ptl_level_idc = buf[ptr + 11]; - std::cout << "-- ptl_level_idc: " << (uint32_t)ptl.ptl_level_idc << "/30 = " << - (double)ptl.ptl_level_idc / 30 << std::endl; - // 6 bits after - ptl.ptl_num_sub_profiles = buf[ptr + 12] >> 2; - std::cout << "-- ptl_num_sub_profiles: " << (uint32_t)ptl.ptl_num_sub_profiles << std::endl; - // 1 bit after - ptl.ptl_extended_sub_profile_flag = (buf[ptr + 12] & 0b10) >> 1; - std::cout << "-- ptl_extended_sub_profile_flag: " << (uint32_t)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 (ptl.ptl_extended_sub_profile_flag == 1) { - for (int i = 0; i < ptl.ptl_num_sub_profiles; i++) { - // TODO this isnt right... - uint64_t sub_profile_id = (buf[first_full_byte] >> 1) | ((buf[first_full_byte - 1] & 0b1) << 63); - ptl.ptl_sub_profile_idc.push_back(sub_profile_id); - first_full_byte += 8; - } - } - else { - for (int i = 0; i < ptl.ptl_num_sub_profiles; i++) { - uint32_t sub_profile_id = (buf[first_full_byte] >> 1) | ((buf[first_full_byte - 1] & 0b1) << 31); - ptl.ptl_sub_profile_idc.push_back((uint64_t)sub_profile_id); - first_full_byte += 4; - } - } - // 1 bit after - ptl.ptl_toolset_constraints_present_flag = (buf[ptr] & 0b1); - std::cout << "-- ptl_toolset_constraints_present_flag: " << (uint32_t)ptl.ptl_toolset_constraints_present_flag << std::endl; -} - uint64_t get_size(std::string filename) { std::ifstream infile(filename, std::ios_base::binary); - //get length of file infile.seekg(0, infile.end); size_t length = infile.tellg(); @@ -326,13 +271,18 @@ uint64_t get_size(std::string filename) return length; } -char* get_cmem(std::string filename, const size_t& len) +char* get_cmem(std::string filename) { std::ifstream infile(filename, std::ios_base::binary); - char* buf = new char[len]; + //get length of file + infile.seekg(0, infile.end); + size_t length = infile.tellg(); + infile.seekg(0, infile.beg); + + char* buf = new char[length]; // read into char* - if (!(infile.read(buf, len))) // read up to the size of the buffer + if (!(infile.read(buf, length))) // read up to the size of the buffer { if (!infile.eof()) { @@ -344,6 +294,59 @@ char* get_cmem(std::string filename, const size_t& len) return buf; } +v3c_streams init_v3c_streams(uvgrtp::session* sess, uint16_t src_port, uint16_t dst_port, int flags, bool rec) +{ + flags |= RCE_NO_H26X_PREPEND_SC; + v3c_streams streams = {}; + streams.vps = sess->create_stream(src_port, dst_port, RTP_FORMAT_GENERIC, flags); + streams.ad = sess->create_stream(src_port, dst_port, RTP_FORMAT_ATLAS, flags); + streams.ovd = sess->create_stream(src_port, dst_port, RTP_FORMAT_H265, flags); + streams.gvd = sess->create_stream(src_port, dst_port, RTP_FORMAT_H265, flags); + streams.avd = sess->create_stream(src_port, dst_port, RTP_FORMAT_H265, flags); + + if (rec) { + streams.vps->configure_ctx(RCC_REMOTE_SSRC, 1); + streams.ad->configure_ctx(RCC_REMOTE_SSRC, 2); + streams.ovd->configure_ctx(RCC_REMOTE_SSRC, 3); + streams.gvd->configure_ctx(RCC_REMOTE_SSRC, 4); + streams.avd->configure_ctx(RCC_REMOTE_SSRC, 5); + } + else { + streams.vps->configure_ctx(RCC_SSRC, 1); + streams.ad->configure_ctx(RCC_SSRC, 2); + streams.ovd->configure_ctx(RCC_SSRC, 3); + streams.gvd->configure_ctx(RCC_SSRC, 4); + streams.avd->configure_ctx(RCC_SSRC, 5); + } + return streams; +} + +v3c_file_map init_mmap() +{ + v3c_file_map mmap = {}; + + v3c_unit_header hdr = { V3C_AD }; + hdr.ad = { 0, 0 }; + v3c_unit_info unit = { hdr, {}, new char[40 * 1000 * 1000], 0, false }; + mmap.ad_units.push_back(unit); + + hdr = { V3C_OVD }; + hdr.ovd = { 0, 0 }; + unit = { hdr, {}, new char[40 * 1000 * 1000], 0, false }; + mmap.ovd_units.push_back(unit); + + hdr = { V3C_GVD }; + hdr.gvd = { 0, 0 }; + unit = { hdr, {}, new char[40 * 1000 * 1000], 0, false }; + mmap.gvd_units.push_back(unit); + + hdr = { V3C_AVD }; + hdr.avd = { 0, 0 }; + unit = { hdr, {}, new char[40 * 1000 * 1000], 0, false }; + mmap.avd_units.push_back(unit); + return mmap; +} + void create_v3c_unit(v3c_unit_info& current_unit, char* buf, uint64_t& ptr, uint64_t v3c_precision, uint32_t nal_precision) { uint8_t v3c_type = current_unit.header.vuh_unit_type; @@ -363,7 +366,7 @@ void create_v3c_unit(v3c_unit_info& current_unit, char* buf, uint64_t& ptr, uint // All V3C unit types have parameter_set_id in header uint8_t param_set_id = current_unit.header.ad.vuh_v3c_parameter_set_id; - std::cout << "VUH typ: " << (uint32_t)v3c_type << " param set id " << (uint32_t)param_set_id << std::endl; + //std::cout << "VUH typ: " << (uint32_t)v3c_type << " param set id " << (uint32_t)param_set_id << std::endl; v3c_header[0] = v3c_type << 3 | ((param_set_id & 0b1110) >> 1); v3c_header[1] = ((param_set_id & 0b1) << 7); @@ -524,4 +527,48 @@ bool is_gop_ready(uint64_t index, v3c_file_map& mmap) return false; return true; +} + +void copy_rtp_payload(std::vector& units, uint64_t max_size, uvgrtp::frame::rtp_frame* frame) +{ + if ((units.end() - 1)->nal_infos.size() == max_size) { + std::cout << "AD size == 35, adding new v3c_unit " << std::endl; + v3c_unit_header hdr = { (units.end() - 1)->header.vuh_unit_type }; + switch ((units.end() - 1)->header.vuh_unit_type) { + case V3C_AD: { + hdr.ad = { (uint8_t)units.size(), 0 }; + v3c_unit_info info = { hdr, {}, new char[400 * 1000], 0, false }; + units.push_back(info); + break; + } + case V3C_OVD: { + hdr.ovd = { (uint8_t)units.size(), 0 }; + v3c_unit_info info = { hdr, {}, new char[400 * 1000], 0, false }; + units.push_back(info); + break; + } + case V3C_GVD: { + hdr.gvd = { (uint8_t)units.size(), 0, 0, 0 }; + v3c_unit_info info = { hdr, {}, new char[400 * 1000], 0, false }; + units.push_back(info); + break; + } + case V3C_AVD: { + hdr.avd = { (uint8_t)units.size(), 0 }; + v3c_unit_info info = { hdr, {}, new char[40 * 1000 * 1000], 0, false }; + units.push_back(info); + break; + } + } + } + auto& current = units.end() - 1; + + if (current->nal_infos.size() <= max_size) { + memcpy(¤t->buf[current->ptr], frame->payload, frame->payload_len); + current->nal_infos.push_back({ current->ptr, frame->payload_len }); + current->ptr += frame->payload_len; + } + if (current->nal_infos.size() == max_size) { + current->ready = true; + } } \ No newline at end of file