v3c: Add parsing of the profile_tier_level fields in V3C VPS units
This commit is contained in:
parent
1d5d1fa1a9
commit
0e8c52aa77
|
@ -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);
|
||||
|
|
|
@ -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_info> nal_map = {};
|
||||
std::vector<vuh_vps> 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;
|
||||
}
|
||||
|
|
|
@ -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<uint64_t> 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_info>& nal_map);
|
||||
bool mmap_v3c_file(char* cbuf, uint64_t len, std::vector<nal_info>& nal_map, std::vector<vuh_vps> &vps_map);
|
||||
void parse_v3c_header(v3c_unit_header &hdr, char* buf, uint64_t ptr);
|
|
@ -18,7 +18,7 @@ uint32_t combineBytes(uint8_t byte1, uint8_t byte2) {
|
|||
(static_cast<uint32_t>(byte2));
|
||||
}
|
||||
|
||||
bool mmap_v3c_file(char* cbuf, uint64_t len, vuh_vps& param, std::vector<nal_info>& nal_map)
|
||||
bool mmap_v3c_file(char* cbuf, uint64_t len, std::vector<nal_info>& nal_map, std::vector<vuh_vps>& vps_map)
|
||||
{
|
||||
uint64_t ptr = 0;
|
||||
|
||||
|
@ -32,7 +32,6 @@ bool mmap_v3c_file(char* cbuf, uint64_t len, vuh_vps& param, std::vector<nal_inf
|
|||
|
||||
uint8_t* v3c_size = new uint8_t[v3c_size_precision];
|
||||
|
||||
std::vector<uint32_t> 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<nal_inf
|
|||
// Parameter set contains no NAL units, skip over
|
||||
std::cout << "-- Parameter set V3C unit" << std::endl;
|
||||
ptr += combined_v3c_size;
|
||||
sizes.push_back(combined_v3c_size);
|
||||
param = v3c_hdr.vps;
|
||||
vps_map.push_back(v3c_hdr.vps);
|
||||
std::cout << std::endl;
|
||||
continue;
|
||||
}
|
||||
else if (vuh_t == V3C_OVD || vuh_t == V3C_GVD || vuh_t == V3C_AVD || vuh_t == V3C_PVD) {
|
||||
// Video data, map start and size
|
||||
std::cout << "-- Video data V3C unit, " << std::endl;
|
||||
//vd.push_back({ ptr + V3C_HDR_LEN, combined_v3c_size });
|
||||
//ptr += combined_v3c_size;
|
||||
//std::cout << std::endl;
|
||||
//continue;
|
||||
}
|
||||
|
||||
// Rest of the function goes inside the V3C unit payload and parses NAL it into NAL units
|
||||
|
@ -131,7 +124,6 @@ bool mmap_v3c_file(char* cbuf, uint64_t len, vuh_vps& param, std::vector<nal_inf
|
|||
|
||||
std::cout << std::endl;
|
||||
ptr += combined_v3c_size;
|
||||
sizes.push_back(combined_v3c_size);
|
||||
}
|
||||
std::cout << "File parsed" << std::endl;
|
||||
return true;
|
||||
|
@ -163,7 +155,7 @@ void parse_v3c_header(v3c_unit_header &hdr, char* buf, uint64_t ptr)
|
|||
}
|
||||
|
||||
switch (hdr.vuh_unit_type) {
|
||||
case V3C_VPS:
|
||||
case V3C_VPS: {
|
||||
hdr.vps = {};
|
||||
// first bit of first byte
|
||||
hdr.vps.ptl.ptl_tier_flag = buf[ptr + 4] >> 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;
|
||||
|
|
Loading…
Reference in New Issue