hevcc_dump: new tool for dumping a HEVCC from the middle of a file (incomplete)

This commit is contained in:
Moritz Bunkus 2017-03-19 18:44:00 +01:00
parent 97b304708c
commit f12df7396f
3 changed files with 693 additions and 1 deletions

1
.gitignore vendored
View File

@ -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

View File

@ -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
View 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();
}