mirror of
https://gitlab.com/mbunkus/mkvtoolnix.git
synced 2024-12-25 04:11:44 +00:00
hevcc_dump: new tool for dumping a HEVCC from the middle of a file (incomplete)
This commit is contained in:
parent
97b304708c
commit
f12df7396f
1
.gitignore
vendored
1
.gitignore
vendored
@ -70,6 +70,7 @@
|
||||
/src/tools/diracparser
|
||||
/src/tools/ebml_validator
|
||||
/src/tools/hevc_dump
|
||||
/src/tools/hevcc_dump
|
||||
/src/tools/mpls_dump
|
||||
/src/tools/vc1parser
|
||||
/tests/data
|
||||
|
12
Rakefile
12
Rakefile
@ -65,7 +65,7 @@ def setup_globals
|
||||
$programs = %w{mkvmerge mkvinfo mkvextract mkvpropedit}
|
||||
$programs << "mkvinfo-gui" if $build_mkvinfo_gui
|
||||
$programs << "mkvtoolnix-gui" if $build_mkvtoolnix_gui
|
||||
$tools = %w{ac3parser base64tool checksum diracparser ebml_validator hevc_dump mpls_dump vc1parser}
|
||||
$tools = %w{ac3parser base64tool checksum diracparser ebml_validator hevc_dump hevcc_dump mpls_dump vc1parser}
|
||||
|
||||
$application_subdirs = { "mkvtoolnix-gui" => "mkvtoolnix-gui/" }
|
||||
$applications = $programs.collect { |name| "src/#{$application_subdirs[name]}#{name}" + c(:EXEEXT) }
|
||||
@ -1071,6 +1071,16 @@ Application.new("src/tools/hevc_dump").
|
||||
libraries($common_libs).
|
||||
create
|
||||
|
||||
#
|
||||
# tools: hevcs_dump
|
||||
#
|
||||
Application.new("src/tools/hevcc_dump").
|
||||
description("Build the hevcc_dump executable").
|
||||
aliases("tools:hevcc_dump").
|
||||
sources("src/tools/hevcc_dump.cpp").
|
||||
libraries($common_libs).
|
||||
create
|
||||
|
||||
#
|
||||
# tools: mpls_dump
|
||||
#
|
||||
|
681
src/tools/hevcc_dump.cpp
Normal file
681
src/tools/hevcc_dump.cpp
Normal file
@ -0,0 +1,681 @@
|
||||
/*
|
||||
hevcc_dump - A tool for dumping the HEVCC element from the middle of a file
|
||||
|
||||
Distributed under the GPL v2
|
||||
see the file COPYING for details
|
||||
or visit http://www.gnu.org/copyleft/gpl.html
|
||||
|
||||
Written by Moritz Bunkus <moritz@bunkus.org>.
|
||||
*/
|
||||
|
||||
#include "common/common_pch.h"
|
||||
|
||||
#include "common/bit_cursor.h"
|
||||
#include "common/command_line.h"
|
||||
#include "common/hevc.h"
|
||||
#include "common/mm_io_x.h"
|
||||
#include "common/mpeg.h"
|
||||
#include "common/strings/parsing.h"
|
||||
|
||||
static void
|
||||
v(std::string::size_type indent,
|
||||
std::string const &label) {
|
||||
mxinfo(boost::format("%1%%2%\n") % std::string(indent, ' ') % label);
|
||||
}
|
||||
|
||||
static void
|
||||
v(std::string::size_type indent,
|
||||
std::string const &label,
|
||||
std::string const &value) {
|
||||
auto width = 60 - indent;
|
||||
auto fmt = (boost::format("%%1%%%%|2$-%1%s| %%3%%\n") % width).str();
|
||||
mxinfo(boost::format(fmt) % std::string(indent, ' ') % (label + ':') % value);
|
||||
}
|
||||
|
||||
static void
|
||||
v(std::string::size_type indent,
|
||||
std::string const &label,
|
||||
uint64_t value) {
|
||||
v(indent, label, (boost::format("%1%") % value).str());
|
||||
}
|
||||
|
||||
static void
|
||||
v(std::string::size_type indent,
|
||||
std::size_t sub_idx,
|
||||
std::string const &label,
|
||||
std::string const &value) {
|
||||
v(indent, (boost::format("%1%[%2%]") % label % sub_idx).str(), value);
|
||||
}
|
||||
|
||||
static void
|
||||
v(std::string::size_type indent,
|
||||
std::size_t sub_idx,
|
||||
std::string const &label,
|
||||
uint64_t value) {
|
||||
v(indent, sub_idx, label, (boost::format("%1%") % value).str());
|
||||
}
|
||||
|
||||
static void
|
||||
v(std::string::size_type indent,
|
||||
std::size_t sub_idx1,
|
||||
std::size_t sub_idx2,
|
||||
std::string const &label,
|
||||
std::string const &value) {
|
||||
v(indent, (boost::format("%1%[%2%][%3%]") % label % sub_idx1 % sub_idx2).str(), value);
|
||||
}
|
||||
|
||||
static void
|
||||
v(std::string::size_type indent,
|
||||
std::size_t sub_idx1,
|
||||
std::size_t sub_idx2,
|
||||
std::string const &label,
|
||||
uint64_t value) {
|
||||
v(indent, sub_idx1, sub_idx2, label, (boost::format("%1%") % value).str());
|
||||
}
|
||||
|
||||
static void
|
||||
v(std::string::size_type indent,
|
||||
std::size_t sub_idx1,
|
||||
std::size_t sub_idx2,
|
||||
std::size_t sub_idx3,
|
||||
std::string const &label,
|
||||
std::string const &value) {
|
||||
v(indent, (boost::format("%1%[%2%][%3%][%4%]") % label % sub_idx1 % sub_idx2 % sub_idx3).str(), value);
|
||||
}
|
||||
|
||||
static void
|
||||
v(std::string::size_type indent,
|
||||
std::size_t sub_idx1,
|
||||
std::size_t sub_idx2,
|
||||
std::size_t sub_idx3,
|
||||
std::string const &label,
|
||||
uint64_t value) {
|
||||
v(indent, sub_idx1, sub_idx2, sub_idx3, label, (boost::format("%1%") % value).str());
|
||||
}
|
||||
|
||||
static std::string
|
||||
x(std::size_t width,
|
||||
uint64_t value) {
|
||||
auto fmt = (boost::format("0x%%|1$0%1%x|") % width).str();
|
||||
return (boost::format(fmt) % value).str();
|
||||
}
|
||||
|
||||
static void
|
||||
show_help() {
|
||||
mxinfo("hevcc_dump [options] input_file_name position_in_file\n"
|
||||
"\n"
|
||||
"General options:\n"
|
||||
"\n"
|
||||
" -h, --help This help text\n"
|
||||
" -V, --version Print version information\n");
|
||||
mxexit();
|
||||
}
|
||||
|
||||
static void
|
||||
show_version() {
|
||||
mxinfo("hevcc_dump v" PACKAGE_VERSION "\n");
|
||||
mxexit();
|
||||
}
|
||||
|
||||
static std::pair<std::string, uint64_t>
|
||||
parse_args(std::vector<std::string> &args) {
|
||||
std::string file_name;
|
||||
uint64_t file_pos = 0;
|
||||
|
||||
for (auto const &arg: args) {
|
||||
if ((arg == "-h") || (arg == "--help"))
|
||||
show_help();
|
||||
|
||||
else if ((arg == "-V") || (arg == "--version"))
|
||||
show_version();
|
||||
|
||||
else if (file_name.empty())
|
||||
file_name = arg;
|
||||
|
||||
else if (file_pos != 0)
|
||||
mxerror("Superfluous arguments given.\n");
|
||||
|
||||
else if (!parse_number(arg, file_pos))
|
||||
mxerror("The file position is not a valid number.\n");
|
||||
}
|
||||
|
||||
if (file_name.empty())
|
||||
mxerror("No file name given\n");
|
||||
|
||||
if (!file_pos)
|
||||
mxerror("No file position given\n");
|
||||
|
||||
return { file_name, file_pos };
|
||||
}
|
||||
|
||||
static void
|
||||
parse_profile_tier_level(std::size_t indent,
|
||||
bit_reader_c &r,
|
||||
bool profile_present_flag,
|
||||
unsigned int max_num_sub_layers_minus_1) {
|
||||
v(indent, "profile tier level");
|
||||
indent += 2;
|
||||
|
||||
if (profile_present_flag) {
|
||||
unsigned int general_profile_idc, general_profile_compatibility_flag;
|
||||
|
||||
v(indent, "general_profile_space", r.get_bits(2));
|
||||
v(indent, "general_tier_flag", r.get_bits(1));
|
||||
v(indent, "general_profile_idc", general_profile_idc = r.get_bits(5));
|
||||
v(indent, "general_profile_compatibility_flag", x(8, general_profile_compatibility_flag = r.get_bits(32)));
|
||||
v(indent, "general_progressive_source_flag", r.get_bits(1));
|
||||
v(indent, "general_interlaced_source_flag", r.get_bits(1));
|
||||
v(indent, "general_non_packed_constraint_flag", r.get_bits(1));
|
||||
v(indent, "general_frame_only_constraint_flag", r.get_bits(1));
|
||||
|
||||
// 3 2 2 1 1 1
|
||||
// 1 7 3 9 5 1 7 3
|
||||
// 00000000 00000000 00000000 00000000
|
||||
// flags 4...10 == bits 27...21
|
||||
// bits 27...24 == 0x0f
|
||||
// bits 23...21 == 0xe0
|
||||
if ( ((general_profile_idc >= 4) && (general_profile_idc <= 10))
|
||||
|| (general_profile_compatibility_flag & 0x0fe00000) != 0) {
|
||||
v(indent, "general_max_12bit_constraint_flag", r.get_bits(1));
|
||||
v(indent, "general_max_10bit_constraint_flag", r.get_bits(1));
|
||||
v(indent, "general_max_8bit_constraint_flag", r.get_bits(1));
|
||||
v(indent, "general_max_422chroma_constraint_flag", r.get_bits(1));
|
||||
v(indent, "general_max_420chroma_constraint_flag", r.get_bits(1));
|
||||
v(indent, "general_max_monochrome_constraint_flag", r.get_bits(1));
|
||||
v(indent, "general_intra_constraint_flag", r.get_bits(1));
|
||||
v(indent, "general_one_picture_only_constraint_flag", r.get_bits(1));
|
||||
v(indent, "general_lower_bit_rate_constraint_flag", r.get_bits(1));
|
||||
|
||||
// flags 5, 9, 10 == bits 26, 22, 21
|
||||
// bit 26 == 0x04
|
||||
// bits 22, 21 == 0x60
|
||||
if ( (general_profile_idc == 5)
|
||||
|| (general_profile_idc == 9)
|
||||
|| (general_profile_idc == 10)
|
||||
|| (general_profile_compatibility_flag & 0x04600000) != 0) {
|
||||
v(indent, "general_max_14bit_constraint_flag", r.get_bits(1));
|
||||
v(indent, "general_reserved_zero_33bits", x(9, r.get_bits(33)));
|
||||
} else
|
||||
v(indent, "general_reserved_zero_34bits", x(9, r.get_bits(34)));
|
||||
} else
|
||||
v(indent, "general_reserved_zero_43bits", x(11, r.get_bits(43)));
|
||||
|
||||
// flags 1, 2, 3, 4, 5, 9 == bits 30..26, 22
|
||||
// bits 30..26 == 0x7c
|
||||
// bit 22 == 0x40
|
||||
if ( ((general_profile_idc >= 1) && (general_profile_idc <= 5))
|
||||
|| (general_profile_idc == 9)
|
||||
|| (general_profile_compatibility_flag & 0x7c400000) != 0)
|
||||
v(indent, "general_inbld_flag", r.get_bits(1));
|
||||
else
|
||||
v(indent, "general_reserved_zero_bit", r.get_bits(1));
|
||||
}
|
||||
|
||||
v(indent, "general_level_idc", r.get_bits(8));
|
||||
|
||||
std::vector<unsigned int> sub_layer_profile_present_flag, sub_layer_level_present_flag;
|
||||
for (auto i = 0u; i < max_num_sub_layers_minus_1; i++) {
|
||||
v(indent, i, "sub_layer_profile_present_flag", sub_layer_profile_present_flag[i] = r.get_bits(1));
|
||||
v(indent, i, "sub_layer_level_present_flag", sub_layer_level_present_flag[i] = r.get_bits(1));
|
||||
}
|
||||
|
||||
if (max_num_sub_layers_minus_1 > 0)
|
||||
for (auto i = max_num_sub_layers_minus_1; i < 8; ++i)
|
||||
v(indent, i, "reserved_zero_2bits", r.get_bits(2));
|
||||
|
||||
for (auto i = 0u; i < max_num_sub_layers_minus_1; i++) {
|
||||
if (sub_layer_profile_present_flag[i]) {
|
||||
unsigned int sub_layer_profile_idc, sub_layer_profile_compatibility_flag;
|
||||
|
||||
v(indent, i, "sub_layer_profile_space", r.get_bits(2));
|
||||
v(indent, i, "sub_layer_tier_flag", r.get_bits(1));
|
||||
v(indent, i, "sub_layer_profile_idc", (sub_layer_profile_idc = r.get_bits(5)));
|
||||
v(indent, i, "sub_layer_profile_compatibility_flag", x(8, sub_layer_profile_compatibility_flag = r.get_bits(32)));
|
||||
|
||||
// Flags 4...10 == bits 27...21
|
||||
// bits 27...24 == 0x0f
|
||||
// bits 23...21 == 0xe0
|
||||
if ( ((sub_layer_profile_idc >= 4) && (sub_layer_profile_idc <= 10))
|
||||
|| (sub_layer_profile_compatibility_flag & 0x0fe00000) != 0) {
|
||||
v(indent, i, "sub_layer_max_12bit_constraint_flag", r.get_bits(1));
|
||||
v(indent, i, "sub_layer_max_10bit_constraint_flag", r.get_bits(1));
|
||||
v(indent, i, "sub_layer_max_8bit_constraint_flag", r.get_bits(1));
|
||||
v(indent, i, "sub_layer_max_422chroma_constraint_flag", r.get_bits(1));
|
||||
v(indent, i, "sub_layer_max_420chroma_constraint_flag", r.get_bits(1));
|
||||
v(indent, i, "sub_layer_max_monochrome_constraint_flag", r.get_bits(1));
|
||||
v(indent, i, "sub_layer_intra_constraint_flag", r.get_bits(1));
|
||||
v(indent, i, "sub_layer_one_picture_only_constraint_flag", r.get_bits(1));
|
||||
v(indent, i, "sub_layer_lower_bit_rate_constraint_flag", r.get_bits(1));
|
||||
|
||||
// flags 5 == bit 26
|
||||
// bit 26 == 0x04
|
||||
if ( (sub_layer_profile_idc == 5)
|
||||
|| (sub_layer_profile_compatibility_flag & 0x04000000) != 0) {
|
||||
v(indent, i, "sub_layer_max_14bit_constraint_flag", r.get_bits(1));
|
||||
v(indent, i, "sub_layer_reserved_zero_33bits", x(9, r.get_bits(33)));
|
||||
} else
|
||||
v(indent, i, "sub_layer_reserved_zero_34bits", x(9, r.get_bits(34)));
|
||||
} else
|
||||
v(indent, i, "sub_layer_reserved_zero_43bits", x(11, r.get_bits(43)));
|
||||
|
||||
// flags 1, 2, 3, 4, 5, 9 == bits 30..26, 22
|
||||
// bits 30..26 == 0x7c
|
||||
// bit 22 == 0x40
|
||||
if ( ((sub_layer_profile_idc >= 1) && (sub_layer_profile_idc <= 5))
|
||||
|| (sub_layer_profile_idc == 9)
|
||||
|| (sub_layer_profile_compatibility_flag & 0x7c400000) != 0)
|
||||
v(indent, i, "sub_layer_inbld_flag", r.get_bits(1));
|
||||
else
|
||||
v(indent, i, "sub_layer_reserved_zero_bit", r.get_bits(1));
|
||||
}
|
||||
|
||||
if (sub_layer_level_present_flag[i])
|
||||
v(indent, i, "sub_layer_level_idc", r.get_bits(8));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
parse_scaling_list_data(std::size_t indent,
|
||||
bit_reader_c &r) {
|
||||
v(indent, "scaling list data");
|
||||
indent += 2;
|
||||
|
||||
for (auto size_id = 0u; size_id < 4u; size_id++) {
|
||||
for (auto matrix_id = 0u; matrix_id < 6u; matrix_id += (size_id == 3u) ? 3 : 1) {
|
||||
unsigned int scaling_list_pred_mode_flag;
|
||||
|
||||
v(indent, size_id, matrix_id, "scaling_list_pred_mode_flag", scaling_list_pred_mode_flag = r.get_bits(1));
|
||||
|
||||
if (!scaling_list_pred_mode_flag)
|
||||
v(indent, size_id, matrix_id, "scaling_list_pred_matrix_id_delta", r.get_unsigned_golomb());
|
||||
|
||||
else {
|
||||
if (size_id > 1)
|
||||
v(indent, size_id - 2, matrix_id, "scaling_list_dc_coef_minus8", r.get_signed_golomb());
|
||||
|
||||
auto coeff_num = std::min<unsigned int>(64u, (1 << (4 + (size_id << 1))));
|
||||
for (auto i = 0u; i < coeff_num; ++i)
|
||||
v(indent, size_id, matrix_id, i, "scaling_list_delta_coef", r.get_signed_golomb());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
parse_short_term_reference_picture_set(std::size_t indent,
|
||||
bit_reader_c &r,
|
||||
unsigned int pic_set_idx,
|
||||
unsigned int num_short_term_ref_pic_sets) {
|
||||
v(indent, (boost::format("short-term reference picture set %1%") % pic_set_idx).str());
|
||||
indent += 2;
|
||||
|
||||
mxerror("parse_short_term_reference_picture_set NOT IMPLEMENTED YET!\n");
|
||||
|
||||
unsigned int inter_ref_pic_set_prediction_flag = 0;
|
||||
|
||||
if (pic_set_idx != 0)
|
||||
v(indent, "inter_ref_pic_set_prediction_flag", inter_ref_pic_set_prediction_flag = r.get_bits(1));
|
||||
|
||||
if (inter_ref_pic_set_prediction_flag) {
|
||||
if (pic_set_idx == num_short_term_ref_pic_sets)
|
||||
v(indent, "delta_idx_minus1", r.get_unsigned_golomb());
|
||||
|
||||
v(indent, "delta_rps_sign", r.get_bits(1));
|
||||
v(indent, "abs_delta_rps_minus1", r.get_unsigned_golomb());
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
parse_hrd_parameters(std::size_t indent,
|
||||
bit_reader_c &r,
|
||||
bool stuff,
|
||||
unsigned int sps_max_sub_layers_minus1) {
|
||||
v(indent, "HRD parameters");
|
||||
indent += 2;
|
||||
|
||||
mxerror("parse_hrd_parameters NOT IMPLEMENTED YET!\n");
|
||||
}
|
||||
|
||||
static void
|
||||
parse_vui_parameters(std::size_t indent,
|
||||
bit_reader_c &r,
|
||||
unsigned int sps_max_sub_layers_minus1) {
|
||||
unsigned int aspect_ratio_info_present_flag, overscan_info_present_flag, video_signal_type_present_flag, chroma_loc_info_present_flag, vui_timing_info_present_flag, bitstream_restriction_flag;
|
||||
unsigned int default_display_window_flag{};
|
||||
|
||||
v(indent, "VUI parameters");
|
||||
indent += 2;
|
||||
|
||||
v(indent, "aspect_ratio_info_present_flag", aspect_ratio_info_present_flag = r.get_bits(1));
|
||||
|
||||
if (aspect_ratio_info_present_flag) {
|
||||
unsigned int aspect_ratio_idc;
|
||||
|
||||
v(indent, "aspect_ratio_idc", aspect_ratio_idc = r.get_bits(8));
|
||||
if (aspect_ratio_idc == HEVC_EXTENDED_SAR) {
|
||||
v(indent, "sar_width", r.get_bits(16));
|
||||
v(indent, "sar_height", r.get_bits(16));
|
||||
}
|
||||
}
|
||||
|
||||
v(indent, "overscan_info_present_flag", overscan_info_present_flag = r.get_bits(1));
|
||||
if (overscan_info_present_flag)
|
||||
v(indent, "overscan_appropriate_flag", r.get_bits(1));
|
||||
|
||||
v(indent, "video_signal_type_present_flag", video_signal_type_present_flag = r.get_bits(1));
|
||||
if (video_signal_type_present_flag) {
|
||||
unsigned int colour_description_present_flag;
|
||||
|
||||
v(indent, "video_format", r.get_bits(3));
|
||||
v(indent, "video_full_range_flag", r.get_bits(1));
|
||||
v(indent, "colour_description_present_flag", colour_description_present_flag = r.get_bits(1));
|
||||
|
||||
if (colour_description_present_flag) {
|
||||
v(indent, "colour_primaries", r.get_bits(8));
|
||||
v(indent, "transfer_characteristics", r.get_bits(8));
|
||||
v(indent, "matrix_coeffs", r.get_bits(8));
|
||||
}
|
||||
}
|
||||
|
||||
v(indent, "chroma_loc_info_present_flag", chroma_loc_info_present_flag = r.get_bits(1));
|
||||
if (chroma_loc_info_present_flag) {
|
||||
v(indent, "chroma_sample_loc_type_top_field", r.get_unsigned_golomb());
|
||||
v(indent, "chroma_sample_loc_type_bottom_field", r.get_unsigned_golomb());
|
||||
}
|
||||
|
||||
v(indent, "neutral_chroma_indication_flag", r.get_bits(1));
|
||||
v(indent, "field_seq_flag", r.get_bits(1));
|
||||
v(indent, "frame_field_info_present_flag", r.get_bits(1));
|
||||
|
||||
if ( (r.get_remaining_bits() >= 68)
|
||||
&& (r.peek_bits(21) == 0x100000))
|
||||
v(indent, "default_display_window_flag", std::string{"(invalid default display window)"});
|
||||
else
|
||||
v(indent, "default_display_window_flag", default_display_window_flag = r.get_bits(1));
|
||||
|
||||
if (default_display_window_flag) {
|
||||
v(indent, "def_disp_win_left_offset", r.get_unsigned_golomb());
|
||||
v(indent, "def_disp_win_right_offset", r.get_unsigned_golomb());
|
||||
v(indent, "def_disp_win_top_offset", r.get_unsigned_golomb());
|
||||
v(indent, "def_disp_win_bottom_offset", r.get_unsigned_golomb());
|
||||
}
|
||||
|
||||
v(indent, "vui_timing_info_present_flag", vui_timing_info_present_flag = r.get_bits(1));
|
||||
if (vui_timing_info_present_flag) {
|
||||
unsigned int vui_poc_proportional_to_timing_flag, vui_hrd_parameters_present_flag;
|
||||
|
||||
v(indent, "vui_num_units_in_tick", r.get_bits(32));
|
||||
v(indent, "vui_time_scale", r.get_bits(32));
|
||||
v(indent, "vui_poc_proportional_to_timing_flag", vui_poc_proportional_to_timing_flag = r.get_bits(1));
|
||||
|
||||
if (vui_poc_proportional_to_timing_flag)
|
||||
v(indent, "vui_num_ticks_poc_diff_one_minus1", r.get_unsigned_golomb());
|
||||
|
||||
v(indent, "vui_hrd_parameters_present_flag", vui_hrd_parameters_present_flag = r.get_bits(1));
|
||||
if (vui_hrd_parameters_present_flag)
|
||||
parse_hrd_parameters(indent, r, true, sps_max_sub_layers_minus1);
|
||||
}
|
||||
|
||||
v(indent, "bitstream_restriction_flag", bitstream_restriction_flag = r.get_bits(1));
|
||||
if (bitstream_restriction_flag) {
|
||||
v(indent, "tiles_fixed_structure_flag", r.get_bits(1));
|
||||
v(indent, "motion_vectors_over_pic_boundaries_flag", r.get_bits(1));
|
||||
v(indent, "restricted_ref_pic_lists_flag", r.get_bits(1));
|
||||
v(indent, "min_spatial_segmentation_idc", r.get_unsigned_golomb());
|
||||
v(indent, "max_bytes_per_pic_denom", r.get_unsigned_golomb());
|
||||
v(indent, "max_bits_per_min_cu_denom", r.get_unsigned_golomb());
|
||||
v(indent, "log2_max_mv_length_horizontal", r.get_unsigned_golomb());
|
||||
v(indent, "log2_max_mv_length_vertical", r.get_unsigned_golomb());
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
parse_sps_range_extension(std::size_t indent,
|
||||
bit_reader_c &) {
|
||||
v(indent, "range extension");
|
||||
indent += 2;
|
||||
|
||||
mxerror("parse_sps_range_extension NOT IMPLEMENTED YET!\n");
|
||||
}
|
||||
|
||||
static void
|
||||
parse_sps_multilayer_extension(std::size_t indent,
|
||||
bit_reader_c &) {
|
||||
v(indent, "multilayer extension");
|
||||
indent += 2;
|
||||
|
||||
mxerror("parse_sps_multilayer_extension NOT IMPLEMENTED YET!\n");
|
||||
}
|
||||
|
||||
static void
|
||||
parse_sps_3d_extension(std::size_t indent,
|
||||
bit_reader_c &) {
|
||||
v(indent, "3d extension");
|
||||
indent += 2;
|
||||
|
||||
mxerror("parse_sps_3d_extension NOT IMPLEMENTED YET!\n");
|
||||
}
|
||||
|
||||
static void
|
||||
parse_sps_scc_extension(std::size_t indent,
|
||||
bit_reader_c &) {
|
||||
v(indent, "scc extension");
|
||||
indent += 2;
|
||||
|
||||
mxerror("parse_sps_scc_extension NOT IMPLEMENTED YET!\n");
|
||||
}
|
||||
|
||||
static void
|
||||
parse_sps_extension_4bits(std::size_t indent,
|
||||
bit_reader_c &) {
|
||||
v(indent, "extension 4bits");
|
||||
indent += 2;
|
||||
|
||||
mxerror("parse_sps_extension_4bits NOT IMPLEMENTED YET!\n");
|
||||
}
|
||||
|
||||
static void
|
||||
parse_sps(memory_cptr const &data) {
|
||||
unsigned int sps_max_sub_layers_minus1, chroma_format_idc, conformance_window_flag, sps_sub_layer_ordering_info_present_flag, scaling_list_enabled_flag, pcm_enabled_flag, num_short_term_ref_pic_sets, long_term_ref_pics_present_flag;
|
||||
unsigned int vui_parameters_present_flag, sps_extension_present_flag, log2_max_pic_order_cnt_lsb_minus4;
|
||||
unsigned int sps_range_extension_flag{}, sps_multilayer_extension_flag{}, sps_3d_extension_flag{}, sps_scc_extension_flag{}, sps_extension_4bits{};
|
||||
|
||||
auto r = bit_reader_c{data->get_buffer(), data->get_size()};
|
||||
|
||||
v(4, "sequence parameter set");
|
||||
v(6, "forbidden_zero_bit", r.get_bits(1));
|
||||
v(6, "nal_unit_type", r.get_bits(6));
|
||||
v(6, "nuh_layer_id", r.get_bits(6));
|
||||
v(6, "nuh_temporal_id_plus1", r.get_bits(3));
|
||||
v(6, "sps_video_parameter_set_id", r.get_bits(4));
|
||||
v(6, "sps_max_sub_layers_minus1", sps_max_sub_layers_minus1 = r.get_bits(3));
|
||||
v(6, "sps_temporal_id_nesting_flag", r.get_bits(1));
|
||||
|
||||
parse_profile_tier_level(6, r, true, sps_max_sub_layers_minus1);
|
||||
|
||||
v(6, "sps_seq_parameter_set_id", r.get_unsigned_golomb());
|
||||
v(6, "chroma_format_idc", chroma_format_idc = r.get_unsigned_golomb());
|
||||
|
||||
if (chroma_format_idc == 3)
|
||||
v(6, "separate_colour_plane_flag", r.get_bits(1));
|
||||
|
||||
v(6, "pic_width_in_luma_samples", r.get_unsigned_golomb());
|
||||
v(6, "pic_height_in_luma_samples", r.get_unsigned_golomb());
|
||||
v(6, "conformance_window_flag", conformance_window_flag = r.get_bits(1));
|
||||
|
||||
if (conformance_window_flag) {
|
||||
v(6, "conf_win_left_offset", r.get_unsigned_golomb());
|
||||
v(6, "conf_win_right_offset", r.get_unsigned_golomb());
|
||||
v(6, "conf_win_top_offset", r.get_unsigned_golomb());
|
||||
v(6, "conf_win_bottom_offset", r.get_unsigned_golomb());
|
||||
}
|
||||
|
||||
v(6, "bit_depth_luma_minus8", r.get_unsigned_golomb());
|
||||
v(6, "bit_depth_chroma_minus8", r.get_unsigned_golomb());
|
||||
v(6, "log2_max_pic_order_cnt_lsb_minus4", log2_max_pic_order_cnt_lsb_minus4 = r.get_unsigned_golomb());
|
||||
v(6, "sps_sub_layer_ordering_info_present_flag", sps_sub_layer_ordering_info_present_flag = r.get_bits(1));
|
||||
|
||||
for (auto i = (sps_sub_layer_ordering_info_present_flag ? 0 : sps_max_sub_layers_minus1); i <= sps_max_sub_layers_minus1; ++i) {
|
||||
v(6, i, "sps_max_dec_pic_buffering_minus1", r.get_unsigned_golomb());
|
||||
v(6, i, "sps_max_num_reorder_pics", r.get_unsigned_golomb());
|
||||
v(6, i, "sps_max_latency_increase_plus1", r.get_unsigned_golomb());
|
||||
}
|
||||
|
||||
v(6, "log2_min_luma_coding_block_size_minus3", r.get_unsigned_golomb());
|
||||
v(6, "log2_diff_max_min_luma_coding_block_size", r.get_unsigned_golomb());
|
||||
v(6, "log2_min_luma_transform_block_size_minus2", r.get_unsigned_golomb());
|
||||
v(6, "log2_diff_max_min_luma_transform_block_size", r.get_unsigned_golomb());
|
||||
v(6, "max_transform_hierarchy_depth_inter", r.get_unsigned_golomb());
|
||||
v(6, "max_transform_hierarchy_depth_intra", r.get_unsigned_golomb());
|
||||
v(6, "scaling_list_enabled_flag", scaling_list_enabled_flag = r.get_bits(1));
|
||||
|
||||
if (scaling_list_enabled_flag) {
|
||||
unsigned int sps_scaling_list_data_present_flag;
|
||||
v(6, "sps_scaling_list_data_present_flag", sps_scaling_list_data_present_flag = r.get_bits(1));
|
||||
|
||||
if (sps_scaling_list_data_present_flag)
|
||||
parse_scaling_list_data(6, r);
|
||||
}
|
||||
|
||||
v(6, "amp_enabled_flag", r.get_bits(1));
|
||||
v(6, "sample_adaptive_offset_enabled_flag", r.get_bits(1));
|
||||
v(6, "pcm_enabled_flag", pcm_enabled_flag = r.get_bits(1));
|
||||
|
||||
if (pcm_enabled_flag) {
|
||||
v(6, "pcm_sample_bit_depth_luma_minus1", r.get_bits(4));
|
||||
v(6, "pcm_sample_bit_depth_chroma_minus1", r.get_bits(4));
|
||||
v(6, "log2_min_pcm_luma_coding_block_size_minus3", r.get_unsigned_golomb());
|
||||
v(6, "log2_diff_max_min_pcm_luma_coding_block_size", r.get_unsigned_golomb());
|
||||
v(6, "pcm_loop_filter_disabled_flag", r.get_bits(1));
|
||||
}
|
||||
|
||||
v(6, "num_short_term_ref_pic_sets", num_short_term_ref_pic_sets = r.get_unsigned_golomb());
|
||||
for (auto i = 0u; i < num_short_term_ref_pic_sets; ++i)
|
||||
parse_short_term_reference_picture_set(6, r, i, num_short_term_ref_pic_sets);
|
||||
|
||||
v(6, "long_term_ref_pics_present_flag", long_term_ref_pics_present_flag = r.get_bits(1));
|
||||
if (long_term_ref_pics_present_flag) {
|
||||
unsigned int num_long_term_ref_pics_sps;
|
||||
v(6, "num_long_term_ref_pics_sps", num_long_term_ref_pics_sps = r.get_unsigned_golomb());
|
||||
|
||||
for (auto i = 0u; i < num_long_term_ref_pics_sps; ++i) {
|
||||
v(6, i, "lt_ref_pic_poc_lsb_sps", r.get_bits(log2_max_pic_order_cnt_lsb_minus4 + 4));
|
||||
v(6, i, "used_by_curr_pic_lt_sps_flag", r.get_bits(1));
|
||||
}
|
||||
}
|
||||
|
||||
v(6, "sps_temporal_mvp_enabled_flag", r.get_bits(1));
|
||||
v(6, "strong_intra_smoothing_enabled_flag", r.get_bits(1));
|
||||
v(6, "vui_parameters_present_flag", vui_parameters_present_flag = r.get_bits(1));
|
||||
|
||||
if (vui_parameters_present_flag)
|
||||
parse_vui_parameters(6, r, sps_max_sub_layers_minus1);
|
||||
|
||||
v(6, "sps_extension_present_flag", sps_extension_present_flag = r.get_bits(1));
|
||||
if (sps_extension_present_flag) {
|
||||
v(6, "sps_range_extension_flag", sps_range_extension_flag = r.get_bits(1));
|
||||
v(6, "sps_multilayer_extension_flag", sps_multilayer_extension_flag = r.get_bits(1));
|
||||
v(6, "sps_3d_extension_flag", sps_3d_extension_flag = r.get_bits(1));
|
||||
v(6, "sps_scc_extension_flag", sps_scc_extension_flag = r.get_bits(1));
|
||||
v(6, "sps_extension_4bits", sps_extension_4bits = r.get_bits(4));
|
||||
}
|
||||
|
||||
if (sps_range_extension_flag)
|
||||
parse_sps_range_extension(6, r);
|
||||
if (sps_multilayer_extension_flag)
|
||||
parse_sps_multilayer_extension(6, r);
|
||||
if (sps_3d_extension_flag)
|
||||
parse_sps_3d_extension(6, r);
|
||||
if (sps_scc_extension_flag)
|
||||
parse_sps_scc_extension(6, r);
|
||||
if (sps_extension_4bits)
|
||||
parse_sps_extension_4bits(6, r);
|
||||
}
|
||||
|
||||
static void
|
||||
parse_hevcc(std::string const &file_name,
|
||||
uint64_t file_pos) {
|
||||
mm_file_io_c in{file_name};
|
||||
|
||||
in.setFilePointer(file_pos);
|
||||
auto data = in.read(23);
|
||||
auto r = bit_reader_c{data->get_buffer(), data->get_size()};
|
||||
unsigned int num_parameter_sets;
|
||||
|
||||
v(0, "configuration_version", r.get_bits(8));
|
||||
v(0, "general_profile_space", r.get_bits(2));
|
||||
v(0, "general_tier_flag", r.get_bits(1));
|
||||
v(0, "general_profile_idc", r.get_bits(5));
|
||||
v(0, "general_profile_compatibility_flag", x(8, r.get_bits(32)));
|
||||
v(0, "general_progressive_source_flag", r.get_bits(1));
|
||||
v(0, "general_interlace_source_flag", r.get_bits(1));
|
||||
v(0, "general_nonpacked_constraint_flag", r.get_bits(1));
|
||||
v(0, "general_frame_only_constraint_flag", r.get_bits(1));
|
||||
v(0, "reserved", x(11, r.get_bits(44)));
|
||||
v(0, "general_level_idc", r.get_bits(8));
|
||||
v(0, "reserved", r.get_bits(4));
|
||||
v(0, "min_spatial_segmentation_idc", r.get_bits(12));
|
||||
v(0, "reserved", r.get_bits(6));
|
||||
v(0, "parallelism_type", r.get_bits(2));
|
||||
v(0, "reserved", r.get_bits(6));
|
||||
v(0, "chroma_format_idc", r.get_bits(2));
|
||||
v(0, "reserved", r.get_bits(5));
|
||||
v(0, "bit_depth_luma_minus8", r.get_bits(3));
|
||||
v(0, "reserved", r.get_bits(5));
|
||||
v(0, "bit_depth_chroma_minus8", r.get_bits(3));
|
||||
v(0, "reserved", x(4, r.get_bits(16)));
|
||||
v(0, "reserved", r.get_bits(2));
|
||||
v(0, "max_sub_layers", r.get_bits(3));
|
||||
v(0, "temporal_id_nesting_flag", r.get_bits(1));
|
||||
v(0, "size_nalu_minus_one", r.get_bits(2));
|
||||
v(0, "num_parameter_sets", num_parameter_sets = r.get_bits(8));
|
||||
|
||||
for (auto parameter_set_idx = 0u; parameter_set_idx < num_parameter_sets; ++parameter_set_idx) {
|
||||
auto byte = in.read_uint8();
|
||||
auto type = byte & 0x3f;
|
||||
auto type_name = type == HEVC_NALU_TYPE_VIDEO_PARAM ? "video parameter set"
|
||||
: type == HEVC_NALU_TYPE_SEQ_PARAM ? "sequence parameter set"
|
||||
: type == HEVC_NALU_TYPE_PIC_PARAM ? "picture parameter set"
|
||||
: type == HEVC_NALU_TYPE_PREFIX_SEI ? "supplemental enhancement information"
|
||||
: "unknown";
|
||||
auto nal_unit_count = in.read_uint16_be();
|
||||
|
||||
v(0, (boost::format("parameter set %1%") % parameter_set_idx).str());
|
||||
v(2, "array_completeness", (byte & 0x80) >> 7);
|
||||
v(2, "reserved", (byte & 0x40) >> 6);
|
||||
v(2, "nal_unit_type", (boost::format("%1% (%2%)") % type % type_name).str());
|
||||
v(2, "nal_unit_count", nal_unit_count);
|
||||
|
||||
for (auto nal_unit_idx = 0u; nal_unit_idx < nal_unit_count; ++nal_unit_idx) {
|
||||
auto nal_unit_size = in.read_uint16_be();
|
||||
data = in.read(nal_unit_size);
|
||||
data = mtx::mpeg::nalu_to_rbsp(data);
|
||||
|
||||
v(2, (boost::format("NAL unit %1%") % nal_unit_idx).str());
|
||||
v(4, "nal_unit_size", (boost::format("%1% (RBSP size: %2%)") % nal_unit_size % data->get_size()).str());
|
||||
|
||||
if (type == HEVC_NALU_TYPE_SEQ_PARAM)
|
||||
parse_sps(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc,
|
||||
char **argv) {
|
||||
mtx_common_init("hevcc_dump", argv[0]);
|
||||
|
||||
auto args = command_line_utf8(argc, argv);
|
||||
while (handle_common_cli_args(args, "-r"))
|
||||
;
|
||||
|
||||
auto file_spec = parse_args(args);
|
||||
|
||||
try {
|
||||
parse_hevcc(file_spec.first, file_spec.second);
|
||||
} catch (mtx::mm_io::open_x &) {
|
||||
mxerror("File not found\n");
|
||||
}
|
||||
|
||||
mxexit();
|
||||
}
|
Loading…
Reference in New Issue
Block a user