v3c: Divide more code into functions

This commit is contained in:
Heikki Tampio 2023-08-23 09:36:17 +03:00
parent 822f5958c2
commit 3efbd098a6
4 changed files with 170 additions and 229 deletions

View File

@ -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 gvd_receive_hook(void* arg, uvgrtp::frame::rtp_frame* frame);
void avd_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<v3c_unit_info> &units, uint64_t max_size, uvgrtp::frame::rtp_frame* frame);
uint64_t vps_count; uint64_t vps_count;
constexpr int VPS_NALS = 1; constexpr int VPS_NALS = 1;
@ -48,57 +47,29 @@ std::string PATH = "C:\\Users\\ngheta\\Documents\\v3c_test_seq_2.vpcc";
int main(void) 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 */ /* Fetch the original file and its size */
uint64_t len = get_size(PATH); uint64_t len = get_size(PATH);
std::cout << "File size " << len << std::endl; std::cout << "File size " << len << std::endl;
char* original_buf = nullptr; char* original_buf = nullptr;
original_buf = get_cmem(PATH, len); original_buf = get_cmem(PATH);
uvgrtp::context ctx; uvgrtp::context ctx;
uvgrtp::session* sess = ctx.create_session(LOCAL_ADDRESS, LOCAL_ADDRESS); 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 // Create the uvgRTP media streams with the correct RTP format
uvgrtp::media_stream* vps = sess->create_stream(8891, 8890, RTP_FORMAT_GENERIC, flags); v3c_streams streams = init_v3c_streams(sess, 8890, 8892, flags, true);
uvgrtp::media_stream* ad = sess->create_stream(8893, 8892, RTP_FORMAT_ATLAS, flags); //avd->configure_ctx(RCC_RING_BUFFER_SIZE, 40*1000*1000);
uvgrtp::media_stream* ovd = sess->create_stream(8895, 8894, RTP_FORMAT_H265, flags); v3c_file_map mmap = init_mmap();
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);
char* out_buf = new char[len]; streams.vps->install_receive_hook(&mmap.vps_units, vps_receive_hook);
v3c_file_map mmap = {}; 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);
v3c_unit_header hdr = { V3C_AD }; streams.avd->install_receive_hook(&mmap.avd_units, avd_receive_hook);
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);
std::cout << "Waiting incoming packets for " << RECEIVE_TIME_S.count() << " s" << std::endl; 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 bytes = 0;
uint64_t ptr = 0; uint64_t ptr = 0;
bool hdb = true; bool hdb = true;
char* out_buf = new char[len];
while (ngops <= 1) { while (ngops <= 1) {
if (is_gop_ready(ngops, mmap)) { if (is_gop_ready(ngops, mmap)) {
std::cout << "Full GoP received, num: " << ngops << std::endl; std::cout << "Full GoP received, num: " << ngops << std::endl;
bytes += reconstruct_v3c_gop(hdb, out_buf, ptr, mmap, ngops - 1); 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++; ngops++;
hdb = false; hdb = false;
@ -120,11 +93,11 @@ int main(void)
std::this_thread::sleep_for(RECEIVE_TIME_S); // lets this example run for some time std::this_thread::sleep_for(RECEIVE_TIME_S); // lets this example run for some time
sess->destroy_stream(vps); sess->destroy_stream(streams.vps);
sess->destroy_stream(ad); sess->destroy_stream(streams.ad);
sess->destroy_stream(ovd); sess->destroy_stream(streams.ovd);
sess->destroy_stream(gvd); sess->destroy_stream(streams.gvd);
sess->destroy_stream(avd); sess->destroy_stream(streams.avd);
ctx.destroy_session(sess); ctx.destroy_session(sess);
@ -141,50 +114,6 @@ int main(void)
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
void copy_rtp_payload(std::vector<v3c_unit_info> &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(&current->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) void vps_receive_hook(void* arg, uvgrtp::frame::rtp_frame* frame)
{ {
std::cout << "Received VPS frame, size: " << frame->payload_len << " bytes" << std::endl; 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<v3c_unit_info>* vec = (std::vector<v3c_unit_info>*)arg; std::vector<v3c_unit_info>* vec = (std::vector<v3c_unit_info>*)arg;
copy_rtp_payload(*vec, AD_NALS, frame); 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)uvgrtp::frame::dealloc_frame(frame);
} }
void ovd_receive_hook(void* arg, uvgrtp::frame::rtp_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<v3c_unit_info>* vec = (std::vector<v3c_unit_info>*)arg; std::vector<v3c_unit_info>* vec = (std::vector<v3c_unit_info>*)arg;
copy_rtp_payload(*vec, OVD_NALS, frame); 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) 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<v3c_unit_info>* vec = (std::vector<v3c_unit_info>*)arg; std::vector<v3c_unit_info>* vec = (std::vector<v3c_unit_info>*)arg;
copy_rtp_payload(*vec, GVD_NALS, frame); copy_rtp_payload(*vec, GVD_NALS, frame);
(void)uvgrtp::frame::dealloc_frame(frame); (void)uvgrtp::frame::dealloc_frame(frame);
} }
void avd_receive_hook(void* arg, uvgrtp::frame::rtp_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<v3c_unit_info>* vec = (std::vector<v3c_unit_info>*)arg; std::vector<v3c_unit_info>* vec = (std::vector<v3c_unit_info>*)arg;
copy_rtp_payload(*vec, AVD_NALS, frame); copy_rtp_payload(*vec, AVD_NALS, frame);

View File

@ -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<v3c_unit_info> &units, rtp_flags_t flags, int fmt); void sender_func(uvgrtp::media_stream* stream, const char* cbuf, const std::vector<v3c_unit_info> &units, rtp_flags_t flags, int fmt);
int main(void) int main(void)
{ {
std::cout << "Parsing V3C file" << std::endl; std::cout << "Parsing V3C file" << std::endl;
@ -36,45 +35,35 @@ int main(void)
/* Fetch the file and its size */ /* Fetch the file and its size */
uint64_t len = get_size(PATH); uint64_t len = get_size(PATH);
uint64_t ptr = 0; char* cbuf = get_cmem(PATH);
char* cbuf = nullptr;
cbuf = get_cmem(PATH, len);
/* Map the locations and sizes of Atlas and video NAL units with the mmap_v3c_file function */ /* Map the locations and sizes of Atlas and video NAL units with the mmap_v3c_file function */
mmap_v3c_file(cbuf, len, mmap); 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 */ /* Create the necessary uvgRTP media streams */
uvgrtp::context ctx; uvgrtp::context ctx;
uvgrtp::session* sess = ctx.create_session(REMOTE_ADDRESS, REMOTE_ADDRESS); 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 int flags = RCE_SEND_ONLY;
uvgrtp::media_stream* vps = sess->create_stream(8890, 8891, RTP_FORMAT_GENERIC, flags); v3c_streams streams = init_v3c_streams(sess, 8892, 8890, flags, false);
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;
/* Start sending data */ /* Start sending data */
std::unique_ptr<std::thread> vps_thread = std::unique_ptr<std::thread> vps_thread =
std::unique_ptr<std::thread>(new std::thread(sender_func, vps, cbuf, mmap.vps_units, RTP_NO_FLAGS, V3C_VPS)); std::unique_ptr<std::thread>(new std::thread(sender_func, streams.vps, cbuf, mmap.vps_units, RTP_NO_FLAGS, V3C_VPS));
std::unique_ptr<std::thread> ad_thread = std::unique_ptr<std::thread> ad_thread =
std::unique_ptr<std::thread>(new std::thread(sender_func, ad, cbuf, mmap.ad_units, RTP_NO_FLAGS, V3C_AD)); std::unique_ptr<std::thread>(new std::thread(sender_func, streams.ad, cbuf, mmap.ad_units, RTP_NO_FLAGS, V3C_AD));
std::unique_ptr<std::thread> ovd_thread = std::unique_ptr<std::thread> ovd_thread =
std::unique_ptr<std::thread>(new std::thread(sender_func, ovd, cbuf, mmap.ovd_units, RTP_NO_H26X_SCL, V3C_OVD)); std::unique_ptr<std::thread>(new std::thread(sender_func, streams.ovd, cbuf, mmap.ovd_units, RTP_NO_H26X_SCL, V3C_OVD));
std::unique_ptr<std::thread> gvd_thread = std::unique_ptr<std::thread> gvd_thread =
std::unique_ptr<std::thread>(new std::thread(sender_func, gvd, cbuf, mmap.gvd_units, RTP_NO_H26X_SCL, V3C_GVD)); std::unique_ptr<std::thread>(new std::thread(sender_func, streams.gvd, cbuf, mmap.gvd_units, RTP_NO_H26X_SCL, V3C_GVD));
std::unique_ptr<std::thread> avd_thread = std::unique_ptr<std::thread> avd_thread =
std::unique_ptr<std::thread>(new std::thread(sender_func, avd, cbuf, mmap.avd_units, RTP_NO_H26X_SCL, V3C_AVD)); std::unique_ptr<std::thread>(new std::thread(sender_func, streams.avd, cbuf, mmap.avd_units, RTP_NO_H26X_SCL, V3C_AVD));
if (vps_thread && vps_thread->joinable()) if (vps_thread && vps_thread->joinable())
{ {
@ -97,11 +86,11 @@ int main(void)
avd_thread->join(); avd_thread->join();
} }
sess->destroy_stream(vps); sess->destroy_stream(streams.vps);
sess->destroy_stream(ad); sess->destroy_stream(streams.ad);
sess->destroy_stream(ovd); sess->destroy_stream(streams.ovd);
sess->destroy_stream(gvd); sess->destroy_stream(streams.gvd);
sess->destroy_stream(avd); sess->destroy_stream(streams.avd);
std::cout << "Sending finished" << std::endl; 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<v3c_unit_info> &units, rtp_flags_t flags, int fmt) void sender_func(uvgrtp::media_stream* stream, const char* cbuf, const std::vector<v3c_unit_info> &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& p : units) {
for (auto i : p.nal_infos) { for (auto i : p.nal_infos) {
rtp_error_t ret = RTP_OK; rtp_error_t ret = RTP_OK;
//std::cout << "Sending NAL unit in location " << i.location << " with size " << i.size << std::endl; //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); ret = stream->push_frame((uint8_t*)cbuf + i.location, i.size, flags);
if (ret == RTP_OK) { 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 {
std::cout << "Failed to send RTP frame!" << std::endl; std::cout << "Failed to send RTP frame!" << std::endl;
} }
} }
} }
//myfile.close();
} }

View File

@ -1,5 +1,7 @@
#pragma once #pragma once
#include <uvgrtp/lib.hh>
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <cstring> #include <cstring>
@ -24,27 +26,8 @@ enum CODEC {
CODEC_VVC_MAIN10 = 3 // VVC Main10 CODEC_VVC_MAIN10 = 3 // VVC Main10
}; };
constexpr int V3C_HDR_LEN = 4; // 32 bits for v3c unit header 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<uint64_t> 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;
};
struct vuh_ad { struct vuh_ad {
uint8_t vuh_v3c_parameter_set_id = 0; uint8_t vuh_v3c_parameter_set_id = 0;
uint8_t vuh_atlas_id = 0; uint8_t vuh_atlas_id = 0;
@ -110,24 +93,46 @@ struct v3c_file_map {
std::vector<v3c_unit_info> cad_units = {}; std::vector<v3c_unit_info> 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, uint8_t byte4);
uint32_t combineBytes(uint8_t byte1, uint8_t byte2, uint8_t byte3); uint32_t combineBytes(uint8_t byte1, uint8_t byte2, uint8_t byte3);
uint32_t combineBytes(uint8_t byte1, uint8_t byte2); 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_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); 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); 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); 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_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);
// Receiver functions // Initialize a memory map of a V3C file
v3c_file_map init_mmap();
// Used in receiver_hooks to copy the received data
void copy_rtp_payload(std::vector<v3c_unit_info>& 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); void create_v3c_unit(v3c_unit_info& current_unit, char* buf, uint64_t& ptr, uint64_t v3c_precision, uint32_t nal_precision);
// 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); 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); bool is_gop_ready(uint64_t index, v3c_file_map& mmap);

View File

@ -259,65 +259,10 @@ void parse_v3c_header(v3c_unit_header &hdr, char* buf, uint64_t ptr)
return; 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) uint64_t get_size(std::string filename)
{ {
std::ifstream infile(filename, std::ios_base::binary); std::ifstream infile(filename, std::ios_base::binary);
//get length of file //get length of file
infile.seekg(0, infile.end); infile.seekg(0, infile.end);
size_t length = infile.tellg(); size_t length = infile.tellg();
@ -326,13 +271,18 @@ uint64_t get_size(std::string filename)
return length; 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); 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* // 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()) if (!infile.eof())
{ {
@ -344,6 +294,59 @@ char* get_cmem(std::string filename, const size_t& len)
return buf; 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) 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; 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 // All V3C unit types have parameter_set_id in header
uint8_t param_set_id = current_unit.header.ad.vuh_v3c_parameter_set_id; 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[0] = v3c_type << 3 | ((param_set_id & 0b1110) >> 1);
v3c_header[1] = ((param_set_id & 0b1) << 7); 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 false;
return true; return true;
}
void copy_rtp_payload(std::vector<v3c_unit_info>& 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(&current->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;
}
} }