diff --git a/includes/acl/compression/impl/compact.transform.h b/includes/acl/compression/impl/compact.transform.h index 5dadc355..18898702 100644 --- a/includes/acl/compression/impl/compact.transform.h +++ b/includes/acl/compression/impl/compact.transform.h @@ -29,7 +29,9 @@ #include "acl/core/track_formats.h" #include "acl/core/impl/compiler_utils.h" #include "acl/core/error.h" +#include "acl/core/scope_profiler.h" #include "acl/compression/impl/clip_context.h" +#include "acl/compression/impl/compression_stats.h" #include "acl/compression/impl/rigid_shell_utils.h" #include "acl/compression/transform_error_metrics.h" @@ -349,8 +351,20 @@ namespace acl // By default, constant sub-tracks will retain the first sample. // A constant sub-track is a default sub-track if its unique sample can be replaced by the default value // without exceeding our error threshold. - inline void compact_constant_streams(iallocator& allocator, clip_context& context, const clip_context& additive_base_clip_context, const track_array_qvvf& track_list, const compression_settings& settings) + inline void compact_constant_streams( + iallocator& allocator, + clip_context& context, + const clip_context& additive_base_clip_context, + const track_array_qvvf& track_list, + const compression_settings& settings, + compression_stats_t& compression_stats) { + (void)compression_stats; + +#if defined(ACL_USE_SJSON) + scope_profiler compact_constant_sub_tracks_time; +#endif + ACL_ASSERT(context.num_segments == 1, "context must contain a single segment!"); segment_context& segment = context.segments[0]; @@ -655,6 +669,10 @@ namespace acl } } #endif + +#if defined(ACL_USE_SJSON) + compression_stats.compact_constant_sub_tracks_elapsed_seconds = compact_constant_sub_tracks_time.get_elapsed_seconds(); +#endif } } diff --git a/includes/acl/compression/impl/compress.transform.impl.h b/includes/acl/compression/impl/compress.transform.impl.h index 54d62a9f..ea0a4c15 100644 --- a/includes/acl/compression/impl/compress.transform.impl.h +++ b/includes/acl/compression/impl/compress.transform.impl.h @@ -40,6 +40,7 @@ #include "acl/compression/output_stats.h" #include "acl/compression/track_array.h" #include "acl/compression/impl/clip_context.h" +#include "acl/compression/impl/compression_stats.h" #include "acl/compression/impl/track_stream.h" #include "acl/compression/impl/convert_rotation.transform.h" #include "acl/compression/impl/compact.transform.h" @@ -142,8 +143,12 @@ namespace acl if (result.any()) return result; + compression_stats_t compression_stats; + (void)compression_stats; + #if defined(ACL_USE_SJSON) scope_profiler compression_time; + scope_profiler initialization_time; #endif // Segmenting settings are an implementation detail @@ -223,40 +228,44 @@ namespace acl if (is_additive) additive_base_clip_context.clip_shell_metadata = clip_shell_metadata; +#if defined(ACL_USE_SJSON) + compression_stats.initialization_elapsed_seconds = initialization_time.get_elapsed_seconds(); +#endif + // Wrap instead of clamp if we loop - optimize_looping(lossy_clip_context, additive_base_clip_context, settings); + optimize_looping(lossy_clip_context, additive_base_clip_context, settings, compression_stats); // Convert our rotations if we need to - convert_rotation_streams(allocator, lossy_clip_context, settings.rotation_format); + convert_rotation_streams(allocator, lossy_clip_context, settings.rotation_format, compression_stats); // Extract our clip ranges now, we need it for compacting the constant streams - extract_clip_bone_ranges(allocator, lossy_clip_context); + extract_clip_bone_ranges(allocator, lossy_clip_context, compression_stats); // Compact and collapse the constant streams - compact_constant_streams(allocator, lossy_clip_context, additive_base_clip_context, track_list, settings); + compact_constant_streams(allocator, lossy_clip_context, additive_base_clip_context, track_list, settings, compression_stats); uint32_t clip_range_data_size = 0; if (range_reduction != range_reduction_flags8::none) { // Normalize our samples into the clip wide ranges per bone - normalize_clip_streams(lossy_clip_context, range_reduction); + normalize_clip_streams(lossy_clip_context, range_reduction, compression_stats); clip_range_data_size = get_clip_range_data_size(lossy_clip_context, range_reduction, settings.rotation_format); } - segment_streams(allocator, lossy_clip_context, segmenting_settings); + segment_streams(allocator, lossy_clip_context, segmenting_settings, compression_stats); // If we have a single segment, skip segment range reduction since it won't help if (range_reduction != range_reduction_flags8::none && lossy_clip_context.num_segments > 1) { // Extract and fixup our segment wide ranges per bone - extract_segment_bone_ranges(allocator, lossy_clip_context); + extract_segment_bone_ranges(allocator, lossy_clip_context, compression_stats); // Normalize our samples into the segment wide ranges per bone - normalize_segment_streams(lossy_clip_context, range_reduction); + normalize_segment_streams(lossy_clip_context, range_reduction, compression_stats); } // Find how many bits we need per sub-track and quantize everything - quantize_streams(allocator, lossy_clip_context, settings, raw_clip_context, additive_base_clip_context, out_stats); + quantize_streams(allocator, lossy_clip_context, settings, raw_clip_context, additive_base_clip_context, out_stats, compression_stats); uint32_t num_output_bones = 0; uint32_t* output_bone_mapping = create_output_track_mapping(allocator, track_list, num_output_bones); @@ -265,9 +274,12 @@ namespace acl calculate_animated_data_size(lossy_clip_context, output_bone_mapping, num_output_bones); // Remove whole keyframes as needed - strip_keyframes(lossy_clip_context, settings); + strip_keyframes(lossy_clip_context, settings, compression_stats); // Compression is done! Time to pack things. +#if defined(ACL_USE_SJSON) + scope_profiler output_packing_time; +#endif if (remove_contributing_error) settings.metadata.include_contributing_error = false; @@ -517,6 +529,10 @@ namespace acl buffer_header->size = buffer_size; buffer_header->hash = hash32(safe_ptr_cast(header), buffer_size - sizeof(raw_buffer_header)); // Hash everything but the raw buffer header +#if defined(ACL_USE_SJSON) + compression_stats.output_packing_elapsed_seconds = output_packing_time.get_elapsed_seconds(); +#endif + #if defined(ACL_HAS_ASSERT_CHECKS) { // Make sure we wrote the right amount of data @@ -575,10 +591,10 @@ namespace acl #endif #if defined(ACL_USE_SJSON) - compression_time.stop(); + compression_stats.total_elapsed_seconds = compression_time.stop().get_elapsed_seconds(); if (out_stats.logging != stat_logging::none) - write_stats(allocator, track_list, lossy_clip_context, *out_compressed_tracks, settings, segmenting_settings, range_reduction, raw_clip_context, additive_base_clip_context, compression_time, out_stats); + write_stats(allocator, track_list, lossy_clip_context, *out_compressed_tracks, settings, segmenting_settings, range_reduction, raw_clip_context, additive_base_clip_context, compression_stats, out_stats); #endif deallocate_type_array(allocator, output_bone_mapping, num_output_bones); diff --git a/includes/acl/compression/impl/compression_stats.h b/includes/acl/compression/impl/compression_stats.h new file mode 100644 index 00000000..b6a00c37 --- /dev/null +++ b/includes/acl/compression/impl/compression_stats.h @@ -0,0 +1,67 @@ +#pragma once + +//////////////////////////////////////////////////////////////////////////////// +// The MIT License (MIT) +// +// Copyright (c) 2024 Nicholas Frechette & Animation Compression Library contributors +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +//////////////////////////////////////////////////////////////////////////////// + +#include "acl/version.h" +#include "acl/core/impl/compiler_utils.h" + +#include + +ACL_IMPL_FILE_PRAGMA_PUSH + +namespace acl +{ + ACL_IMPL_VERSION_NAMESPACE_BEGIN + + namespace acl_impl + { + // Holds compression timing stats for diagnostics + struct compression_stats_t + { +#if defined(ACL_USE_SJSON) + // Total compression time + double total_elapsed_seconds = 0.0; + + // High level passes + double initialization_elapsed_seconds = 0.0; + double optimize_looping_elapsed_seconds = 0.0; + double convert_rotations_elapsed_seconds = 0.0; + double extract_clip_ranges_elapsed_seconds = 0.0; + double compact_constant_sub_tracks_elapsed_seconds = 0.0; + double normalize_clip_elapsed_seconds = 0.0; + double segmenting_elapsed_seconds = 0.0; + double extract_segment_ranges_elapsed_seconds = 0.0; + double normalize_segment_elapsed_seconds = 0.0; + double bit_rate_optimization_elapsed_seconds = 0.0; + double keyframe_stripping_elapsed_seconds = 0.0; + double output_packing_elapsed_seconds = 0.0; +#endif + }; + } + + ACL_IMPL_VERSION_NAMESPACE_END +} + +ACL_IMPL_FILE_PRAGMA_POP diff --git a/includes/acl/compression/impl/convert_rotation.transform.h b/includes/acl/compression/impl/convert_rotation.transform.h index 64a926b7..fd97d856 100644 --- a/includes/acl/compression/impl/convert_rotation.transform.h +++ b/includes/acl/compression/impl/convert_rotation.transform.h @@ -28,8 +28,10 @@ #include "acl/core/iallocator.h" #include "acl/core/impl/compiler_utils.h" #include "acl/core/error.h" +#include "acl/core/scope_profiler.h" #include "acl/core/track_formats.h" #include "acl/compression/impl/clip_context.h" +#include "acl/compression/impl/compression_stats.h" #include #include @@ -105,10 +107,24 @@ namespace acl } } - inline void convert_rotation_streams(iallocator& allocator, clip_context& context, rotation_format8 rotation_format) + inline void convert_rotation_streams( + iallocator& allocator, + clip_context& context, + rotation_format8 rotation_format, + compression_stats_t& compression_stats) { + (void)compression_stats; + +#if defined(ACL_USE_SJSON) + scope_profiler convert_rotations_time; +#endif + for (segment_context& segment : context.segment_iterator()) convert_rotation_streams(allocator, segment, rotation_format); + +#if defined(ACL_USE_SJSON) + compression_stats.convert_rotations_elapsed_seconds = convert_rotations_time.get_elapsed_seconds(); +#endif } } diff --git a/includes/acl/compression/impl/keyframe_stripping.h b/includes/acl/compression/impl/keyframe_stripping.h index 7c576b33..9e48d877 100644 --- a/includes/acl/compression/impl/keyframe_stripping.h +++ b/includes/acl/compression/impl/keyframe_stripping.h @@ -25,8 +25,10 @@ //////////////////////////////////////////////////////////////////////////////// #include "acl/version.h" +#include "acl/core/scope_profiler.h" #include "acl/core/impl/compiler_utils.h" #include "acl/compression/compression_settings.h" +#include "acl/compression/impl/compression_stats.h" #include @@ -38,11 +40,17 @@ namespace acl namespace acl_impl { - inline void strip_keyframes(clip_context& lossy_clip_context, const compression_settings& settings) + inline void strip_keyframes(clip_context& lossy_clip_context, const compression_settings& settings, compression_stats_t& compression_stats) { if (!settings.keyframe_stripping.is_enabled()) return; // We don't want to strip keyframes, nothing to do + (void)compression_stats; + +#if defined(ACL_USE_SJSON) + scope_profiler keyframe_stripping_time; +#endif + const bitset_description hard_keyframes_desc = bitset_description::make_from_num_bits<32>(); const uint32_t num_keyframes = lossy_clip_context.num_samples; @@ -130,6 +138,10 @@ namespace acl } lossy_clip_context.has_stripped_keyframes = num_keyframes_to_strip != 0; + +#if defined(ACL_USE_SJSON) + compression_stats.keyframe_stripping_elapsed_seconds = keyframe_stripping_time.get_elapsed_seconds(); +#endif } } diff --git a/includes/acl/compression/impl/normalize.transform.h b/includes/acl/compression/impl/normalize.transform.h index 4c503a5d..c256d365 100644 --- a/includes/acl/compression/impl/normalize.transform.h +++ b/includes/acl/compression/impl/normalize.transform.h @@ -29,10 +29,12 @@ #include "acl/core/impl/compiler_utils.h" #include "acl/core/error.h" #include "acl/core/enum_utils.h" +#include "acl/core/scope_profiler.h" #include "acl/core/track_formats.h" #include "acl/core/track_types.h" #include "acl/core/range_reduction_types.h" #include "acl/compression/impl/clip_context.h" +#include "acl/compression/impl/compression_stats.h" #include @@ -92,18 +94,34 @@ namespace acl } } - inline void extract_clip_bone_ranges(iallocator& allocator, clip_context& context) + inline void extract_clip_bone_ranges(iallocator& allocator, clip_context& context, compression_stats_t& compression_stats) { + (void)compression_stats; + +#if defined(ACL_USE_SJSON) + scope_profiler extract_clip_ranges_time; +#endif + context.ranges = allocate_type_array(allocator, context.num_bones); ACL_ASSERT(context.num_segments == 1, "context must contain a single segment!"); const segment_context& segment = context.segments[0]; acl_impl::extract_bone_ranges_impl(segment, context.ranges); + +#if defined(ACL_USE_SJSON) + compression_stats.extract_clip_ranges_elapsed_seconds = extract_clip_ranges_time.get_elapsed_seconds(); +#endif } - inline void extract_segment_bone_ranges(iallocator& allocator, clip_context& context) + inline void extract_segment_bone_ranges(iallocator& allocator, clip_context& context, compression_stats_t& compression_stats) { + (void)compression_stats; + +#if defined(ACL_USE_SJSON) + scope_profiler extract_segment_ranges_time; +#endif + const rtm::vector4f one = rtm::vector_set(1.0F); const rtm::vector4f zero = rtm::vector_zero(); const float max_range_value_flt = float((1 << k_segment_range_reduction_num_bits_per_component) - 1); @@ -173,6 +191,10 @@ namespace acl bone_range.scale = fixup_range(bone_range.scale); } } + +#if defined(ACL_USE_SJSON) + compression_stats.extract_segment_ranges_elapsed_seconds = extract_segment_ranges_time.get_elapsed_seconds(); +#endif } inline rtm::vector4f RTM_SIMD_CALL normalize_sample(rtm::vector4f_arg0 sample, const track_stream_range& range) @@ -321,8 +343,14 @@ namespace acl } } - inline void normalize_clip_streams(clip_context& context, range_reduction_flags8 range_reduction) + inline void normalize_clip_streams(clip_context& context, range_reduction_flags8 range_reduction, compression_stats_t& compression_stats) { + (void)compression_stats; + +#if defined(ACL_USE_SJSON) + scope_profiler normalize_clip_time; +#endif + ACL_ASSERT(context.num_segments == 1, "context must contain a single segment!"); segment_context& segment = context.segments[0]; @@ -345,10 +373,20 @@ namespace acl normalize_scale_streams(segment.bone_streams, context.ranges, segment.num_bones); context.are_scales_normalized = true; } + +#if defined(ACL_USE_SJSON) + compression_stats.normalize_clip_elapsed_seconds = normalize_clip_time.get_elapsed_seconds(); +#endif } - inline void normalize_segment_streams(clip_context& context, range_reduction_flags8 range_reduction) + inline void normalize_segment_streams(clip_context& context, range_reduction_flags8 range_reduction, compression_stats_t& compression_stats) { + (void)compression_stats; + +#if defined(ACL_USE_SJSON) + scope_profiler normalize_segments_time; +#endif + for (segment_context& segment : context.segment_iterator()) { if (are_any_enum_flags_set(range_reduction, range_reduction_flags8::rotations)) @@ -400,6 +438,10 @@ namespace acl segment.range_data_size = range_data_size; } + +#if defined(ACL_USE_SJSON) + compression_stats.normalize_segment_elapsed_seconds = normalize_segments_time.get_elapsed_seconds(); +#endif } } diff --git a/includes/acl/compression/impl/optimize_looping.transform.h b/includes/acl/compression/impl/optimize_looping.transform.h index 73b936c5..c47daceb 100644 --- a/includes/acl/compression/impl/optimize_looping.transform.h +++ b/includes/acl/compression/impl/optimize_looping.transform.h @@ -27,9 +27,11 @@ #include "acl/version.h" #include "acl/core/iallocator.h" #include "acl/core/error.h" +#include "acl/core/scope_profiler.h" #include "acl/core/impl/compiler_utils.h" #include "acl/compression/compression_settings.h" #include "acl/compression/impl/clip_context.h" +#include "acl/compression/impl/compression_stats.h" #include "acl/compression/impl/segment_context.h" #include "acl/compression/impl/transform_clip_adapters.h" @@ -173,7 +175,11 @@ namespace acl return is_wrapping; } - inline void optimize_looping(clip_context& context, const clip_context& additive_base_clip_context, const compression_settings& settings) + inline void optimize_looping( + clip_context& context, + const clip_context& additive_base_clip_context, + const compression_settings& settings, + compression_stats_t& compression_stats) { if (!settings.optimize_loops) return; // We don't want to optimize loops, nothing to do @@ -192,6 +198,12 @@ namespace acl if (context.num_bones == 0) return; // No data present + (void)compression_stats; + +#if defined(ACL_USE_SJSON) + scope_profiler optimize_loop_time; +#endif + segment_context& segment = context.segments[0]; ACL_ASSERT(segment.bone_streams->rotations.get_rotation_format() == rotation_format8::quatf_full, "Expected full precision"); @@ -224,6 +236,10 @@ namespace acl segment.bone_streams[transform_index].scales.strip_last_sample(); } } + +#if defined(ACL_USE_SJSON) + compression_stats.optimize_looping_elapsed_seconds = optimize_loop_time.get_elapsed_seconds(); +#endif } } diff --git a/includes/acl/compression/impl/quantize.transform.h b/includes/acl/compression/impl/quantize.transform.h index a7da5c66..e052fc42 100644 --- a/includes/acl/compression/impl/quantize.transform.h +++ b/includes/acl/compression/impl/quantize.transform.h @@ -28,6 +28,7 @@ #include "acl/core/iallocator.h" #include "acl/core/impl/compiler_utils.h" #include "acl/core/error.h" +#include "acl/core/scope_profiler.h" #include "acl/core/time_utils.h" #include "acl/core/track_formats.h" #include "acl/core/impl/variable_bit_rates.h" @@ -36,6 +37,7 @@ #include "acl/compression/impl/track_bit_rate_database.h" #include "acl/compression/impl/transform_bit_rate_permutations.h" #include "acl/compression/impl/clip_context.h" +#include "acl/compression/impl/compression_stats.h" #include "acl/compression/impl/sample_streams.h" #include "acl/compression/impl/normalize.transform.h" #include "acl/compression/impl/convert_rotation.transform.h" @@ -1850,13 +1852,25 @@ namespace acl deallocate_type_array(allocator, num_stripped_in_segment, num_segments); } - inline void quantize_streams(iallocator& allocator, clip_context& clip, const compression_settings& settings, const clip_context& raw_clip_context, const clip_context& additive_base_clip_context, const output_stats& out_stats) + inline void quantize_streams( + iallocator& allocator, + clip_context& clip, + const compression_settings& settings, + const clip_context& raw_clip_context, + const clip_context& additive_base_clip_context, + const output_stats& out_stats, + compression_stats_t& compression_stats) { (void)out_stats; + (void)compression_stats; if (clip.num_bones == 0 || clip.num_samples == 0) return; +#if defined(ACL_USE_SJSON) + scope_profiler bit_rate_optimization_time; +#endif + const bool is_rotation_variable = is_rotation_format_variable(settings.rotation_format); const bool is_translation_variable = is_vector_format_variable(settings.translation_format); const bool is_scale_variable = is_vector_format_variable(settings.scale_format); @@ -1910,6 +1924,10 @@ namespace acl if (settings.metadata.include_contributing_error) sort_contributing_error(allocator, clip); +#if defined(ACL_USE_SJSON) + compression_stats.bit_rate_optimization_elapsed_seconds = bit_rate_optimization_time.get_elapsed_seconds(); +#endif + #if defined(ACL_USE_SJSON) if (are_all_enum_flags_set(out_stats.logging, stat_logging::detailed)) { diff --git a/includes/acl/compression/impl/segment.transform.h b/includes/acl/compression/impl/segment.transform.h index cc8247a2..ddf40c72 100644 --- a/includes/acl/compression/impl/segment.transform.h +++ b/includes/acl/compression/impl/segment.transform.h @@ -28,8 +28,10 @@ #include "acl/core/iallocator.h" #include "acl/core/impl/compiler_utils.h" #include "acl/core/error.h" +#include "acl/core/scope_profiler.h" #include "acl/compression/compression_settings.h" #include "acl/compression/impl/clip_context.h" +#include "acl/compression/impl/compression_stats.h" #include @@ -125,7 +127,11 @@ namespace acl return num_samples_per_segment; } - inline void segment_streams(iallocator& allocator, clip_context& clip, const compression_segmenting_settings& settings) + inline void segment_streams( + iallocator& allocator, + clip_context& clip, + const compression_segmenting_settings& settings, + compression_stats_t& compression_stats) { ACL_ASSERT(clip.num_segments == 1, "clip_context must have a single segment."); ACL_ASSERT(settings.ideal_num_samples <= settings.max_num_samples, "Invalid num samples for segmenting settings. %u > %u", settings.ideal_num_samples, settings.max_num_samples); @@ -133,6 +139,12 @@ namespace acl if (clip.num_samples <= settings.max_num_samples) return; + (void)compression_stats; + +#if defined(ACL_USE_SJSON) + scope_profiler segmenting_time; +#endif + // We split our samples over multiple segments, but some might be empty at the end after re-balancing uint32_t num_estimated_segments = 0; uint32_t num_segments = 0; @@ -238,6 +250,10 @@ namespace acl deallocate_type_array(allocator, num_samples_per_segment, num_estimated_segments); destroy_segment_context(allocator, *clip_segment); deallocate_type_array(allocator, clip_segment, 1); + +#if defined(ACL_USE_SJSON) + compression_stats.segmenting_elapsed_seconds = segmenting_time.get_elapsed_seconds(); +#endif } } diff --git a/includes/acl/compression/impl/write_stats.h b/includes/acl/compression/impl/write_stats.h index 15d13483..daab4b97 100644 --- a/includes/acl/compression/impl/write_stats.h +++ b/includes/acl/compression/impl/write_stats.h @@ -34,6 +34,7 @@ #include "acl/compression/transform_error_metrics.h" #include "acl/compression/track_error.h" #include "acl/compression/impl/clip_context.h" +#include "acl/compression/impl/compression_stats.h" #include @@ -403,7 +404,8 @@ namespace acl inline void write_stats(iallocator& allocator, const track_array_qvvf& track_list, const clip_context& clip, const compressed_tracks& compressed_clip, const compression_settings& settings, const compression_segmenting_settings& segmenting_settings, range_reduction_flags8 range_reduction, const clip_context& raw_clip, - const clip_context& additive_base_clip_context, const scope_profiler& compression_time, + const clip_context& additive_base_clip_context, + const compression_stats_t& compression_stats, output_stats& stats) { ACL_ASSERT(stats.writer != nullptr, "Attempted to log stats without a writer"); @@ -455,7 +457,7 @@ namespace acl writer["raw_size"] = raw_size; writer["compressed_size"] = compressed_size; writer["compression_ratio"] = compression_ratio; - writer["compression_time"] = compression_time.get_elapsed_seconds(); + writer["compression_time"] = compression_stats.total_elapsed_seconds; writer["duration"] = compressed_clip.get_duration(); writer["num_samples"] = compressed_clip.get_num_samples_per_track(); writer["num_bones"] = compressed_clip.get_num_tracks(); @@ -608,6 +610,27 @@ namespace acl }); } }; + + if (are_any_enum_flags_set(stats.logging, stat_logging::detailed)) + { + writer["timings"] = [&](sjson::ObjectWriter& timings_writer) + { + timings_writer["total"] = compression_stats.total_elapsed_seconds; + + timings_writer["initialization"] = compression_stats.initialization_elapsed_seconds; + timings_writer["optimize_looping"] = compression_stats.optimize_looping_elapsed_seconds; + timings_writer["convert_rotations"] = compression_stats.convert_rotations_elapsed_seconds; + timings_writer["extract_clip_ranges"] = compression_stats.extract_clip_ranges_elapsed_seconds; + timings_writer["compact_constant_sub_tracks"] = compression_stats.compact_constant_sub_tracks_elapsed_seconds; + timings_writer["normalize_over_clip"] = compression_stats.normalize_clip_elapsed_seconds; + timings_writer["segmenting"] = compression_stats.segmenting_elapsed_seconds; + timings_writer["extract_segment_ranges"] = compression_stats.extract_segment_ranges_elapsed_seconds; + timings_writer["normalize_over_segments"] = compression_stats.normalize_segment_elapsed_seconds; + timings_writer["bit_rate_optimization"] = compression_stats.bit_rate_optimization_elapsed_seconds; + timings_writer["keyframe_stripping"] = compression_stats.keyframe_stripping_elapsed_seconds; + timings_writer["output_packing"] = compression_stats.output_packing_elapsed_seconds; + }; + } } }