v3c: Divide more code into functions
This commit is contained in:
parent
822f5958c2
commit
3efbd098a6
|
@ -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 ¤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)
|
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);
|
||||||
|
|
|
@ -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();
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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(¤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;
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue