diff --git a/src/core/stream-profile.h b/src/core/stream-profile.h index d256a0a5fe..10072bb3fb 100644 --- a/src/core/stream-profile.h +++ b/src/core/stream-profile.h @@ -1,12 +1,12 @@ // License: Apache 2.0. See LICENSE file in root directory. -// Copyright(c) 2023 Intel Corporation. All Rights Reserved. - +// Copyright(c) 2023-4 Intel Corporation. All Rights Reserved. #pragma once #include #include // std::hash #include // std::swap #include +#include namespace librealsense { @@ -72,6 +72,9 @@ inline bool operator<( const stream_profile & lhs, const stream_profile & rhs ) } +std::ostream & operator<<( std::ostream &, stream_profile const & ); + + } // namespace librealsense diff --git a/src/dds/rs-dds-sensor-proxy.cpp b/src/dds/rs-dds-sensor-proxy.cpp index 8a782168a3..1d2cc689f1 100644 --- a/src/dds/rs-dds-sensor-proxy.cpp +++ b/src/dds/rs-dds-sensor-proxy.cpp @@ -25,6 +25,7 @@ #include #include +#include #include using rsutils::json; @@ -180,6 +181,11 @@ void dds_sensor_proxy::register_basic_converters() { RS2_FORMAT_Y12I }, { { RS2_FORMAT_Y16, RS2_STREAM_INFRARED, 1 }, { RS2_FORMAT_Y16, RS2_STREAM_INFRARED, 2 } }, []() { return std::make_shared< y12i_to_y16y16 >(); } ); + _formats_converter.register_converter( + { RS2_FORMAT_Y8I }, + { { RS2_FORMAT_Y8, RS2_STREAM_INFRARED, 1 }, { RS2_FORMAT_Y8, RS2_STREAM_INFRARED, 2 } }, + []() { return std::make_shared< y8i_to_y8y8 >(); } + ); // L+R // Motion _formats_converter.register_converter( processing_block_factory::create_id_pbf( RS2_FORMAT_COMBINED_MOTION, RS2_STREAM_MOTION ) ); diff --git a/src/proc/formats-converter.cpp b/src/proc/formats-converter.cpp index d411cea1c7..c3181883d6 100644 --- a/src/proc/formats-converter.cpp +++ b/src/proc/formats-converter.cpp @@ -7,8 +7,11 @@ #include #include +#include #include +using rsutils::ios::field; + namespace librealsense { @@ -37,6 +40,9 @@ void formats_converter::clear_registered_converters() void formats_converter::drop_non_basic_formats() { + // Drop every format that's not identity, with the following exceptions: + // - Colored IR is dropped, even though it is identity + for( size_t i = 0; i < _pb_factories.size(); ++i ) { const auto & source = _pb_factories[i]->get_source_info(); @@ -63,6 +69,7 @@ void formats_converter::drop_non_basic_formats() continue; // Convert interleaved formats. // Remove unwanted converters. Move to last element in vector and pop it out. + LOG_DEBUG( "stripping processing block: " << *_pb_factories[i] ); if( i != ( _pb_factories.size() -1 ) ) std::swap( _pb_factories[i], _pb_factories.back() ); _pb_factories.pop_back(); @@ -91,7 +98,25 @@ std::ostream & operator<<( std::ostream & os, const std::shared_ptr< stream_prof return os; } -stream_profiles formats_converter::get_all_possible_profiles( const stream_profiles & raw_profiles ) +std::ostream & operator<<( std::ostream & os, stream_profile const & profile ) +{ + os << field::group::start; + if( profile.stream != RS2_STREAM_ANY ) + os << field::separator << rs2_stream_to_string( profile.stream ); + if( profile.index ) + os << field::separator << profile.index; + if( profile.width + profile.height ) + os << field::separator << profile.width << "x" << profile.height; + if( profile.format != RS2_FORMAT_ANY ) + os << field::separator << rs2_format_to_string( profile.format ); + if( profile.fps ) + os << field::separator << "@ " << profile.fps << " Hz"; + os << field::group::end; + return os; +} + +stream_profiles formats_converter::get_all_possible_profiles( const stream_profiles & raw_profiles, + bool add_missing_identities ) { // For each profile that can be used as input check all registered factories if they can create // a converter from the profile format (source). If so, create appropriate profiles for all possible target formats @@ -102,6 +127,8 @@ stream_profiles formats_converter::get_all_possible_profiles( const stream_profi for( auto & raw_profile : raw_profiles ) { //LOG_DEBUG( "Raw profile: " << raw_profile ); + bool found_factory = false; + bool found_identity = false; for( auto & pbf : _pb_factories ) { const auto & sources = pbf->get_source_info(); @@ -110,6 +137,8 @@ stream_profiles formats_converter::get_all_possible_profiles( const stream_profi if( source.format == raw_profile->get_format() && ( source.stream == raw_profile->get_stream_type() || source.stream == RS2_STREAM_ANY ) ) { + found_factory = true; + // targets are saved with format, type and sometimes index. Updating fps and resolution before using as key for( const auto & target : pbf->get_target_info() ) { @@ -119,6 +148,9 @@ stream_profiles formats_converter::get_all_possible_profiles( const stream_profi if( source.stream == RS2_STREAM_INFRARED && raw_profile->get_stream_index() != target.index ) continue; + if( source.format == target.format ) + found_identity = true; + auto cloned_profile = clone_profile( raw_profile ); cloned_profile->set_format( target.format ); cloned_profile->set_stream_index( target.index ); @@ -161,6 +193,35 @@ stream_profiles formats_converter::get_all_possible_profiles( const stream_profi } } } + + if( add_missing_identities && ! found_identity ) + { + auto cloned_profile = clone_profile( raw_profile ); + cloned_profile->set_format( raw_profile->get_format() ); + cloned_profile->set_stream_index( raw_profile->get_stream_index() ); + cloned_profile->set_stream_type( raw_profile->get_stream_type() ); + + auto pbf = std::make_shared< processing_block_factory >( + processing_block_factory::create_id_pbf( raw_profile->get_format(), raw_profile->get_stream_type() ) ); + LOG_DEBUG( "adding identity processing block: " << *pbf ); + _pb_factories.push_back( pbf ); + + // Cache pbf supported profiles for efficiency in find_pbf_matching_most_profiles + _pbf_supported_profiles[pbf.get()].push_back( cloned_profile ); + + // Cache mapping of each target profile to profiles it is converting from. + // Using map key type stream_profile and calling to_profile because stream_profile_interface is + // abstract, can't use as key. shared_ptr< stream_profile_interface > saves pointer as key which + // will result in bugs when mapping multiple raw profiles to the same converted profile. + _target_profiles_to_raw_profiles[to_profile( cloned_profile.get() )].push_back( raw_profile ); + + if( ! is_profile_in_list( cloned_profile, to_profiles ) ) + to_profiles.push_back( cloned_profile ); + } + else if( ! found_factory ) + { + LOG_WARNING( "no factory found for raw profile: " << raw_profile ); + } } return to_profiles; diff --git a/src/proc/formats-converter.h b/src/proc/formats-converter.h index ef5b73cd0b..0a167ab25b 100644 --- a/src/proc/formats-converter.h +++ b/src/proc/formats-converter.h @@ -1,6 +1,5 @@ // License: Apache 2.0. See LICENSE file in root directory. -// Copyright(c) 2023 Intel Corporation. All Rights Reserved. - +// Copyright(c) 2023-4 Intel Corporation. All Rights Reserved. #pragma once #include "processing-blocks-factory.h" @@ -29,11 +28,10 @@ namespace librealsense void register_converters( const std::vector< processing_block_factory > & pbfs ); void clear_registered_converters(); - // Don't convert to types other then the raw camera formats (use only identity formats) - // Convert only interleaved formats (Y8I, Y12I), no colored infrared. + // Drop every format that's not identity, with some exceptions void drop_non_basic_formats(); - stream_profiles get_all_possible_profiles( const stream_profiles & raw_profiles ); + stream_profiles get_all_possible_profiles( const stream_profiles & raw_profiles, bool add_missing_identities = false ); void prepare_to_convert( stream_profiles to_profiles ); stream_profiles get_active_source_profiles() const; diff --git a/src/proc/processing-blocks-factory.cpp b/src/proc/processing-blocks-factory.cpp index 98cfbc1287..e642d71e02 100644 --- a/src/proc/processing-blocks-factory.cpp +++ b/src/proc/processing-blocks-factory.cpp @@ -1,12 +1,25 @@ // License: Apache 2.0. See LICENSE file in root directory. -// Copyright(c) 2017 Intel Corporation. All Rights Reserved. +// Copyright(c) 2017-24 Intel Corporation. All Rights Reserved. #include "processing-blocks-factory.h" - #include "stream.h" +#include + + namespace librealsense { + std::ostream & operator<<( std::ostream & os, processing_block_factory const & pbf ) + { + for( auto & source : pbf.get_source_info() ) + os << source; + os << " -> "; + for( auto & target : pbf.get_target_info() ) + os << target; + return os; + } + + processing_block_factory::processing_block_factory(const std::vector& from, const std::vector& to, std::function(void)> generate_func) : _source_info(from), _target_info(to), generate_processing_block(generate_func) {} diff --git a/src/proc/processing-blocks-factory.h b/src/proc/processing-blocks-factory.h index e2aea219d4..c9c221880c 100644 --- a/src/proc/processing-blocks-factory.h +++ b/src/proc/processing-blocks-factory.h @@ -1,16 +1,15 @@ // License: Apache 2.0. See LICENSE file in root directory. -// Copyright(c) 2017 Intel Corporation. All Rights Reserved. - +// Copyright(c) 2017-24 Intel Corporation. All Rights Reserved. #pragma once #include #include +#include "identity-processing-block.h" + #include +#include -#include "../types.h" - -#include "identity-processing-block.h" namespace librealsense { @@ -67,4 +66,7 @@ namespace librealsense std::vector _target_info; std::function(void)> generate_processing_block; }; + + + std::ostream & operator<<( std::ostream &, processing_block_factory const & ); } diff --git a/src/sensor.cpp b/src/sensor.cpp index f051cb2af4..94c13d8395 100644 --- a/src/sensor.cpp +++ b/src/sensor.cpp @@ -567,6 +567,10 @@ void log_callback_end( uint32_t fps, { case format_conversion::basic: _formats_converter.drop_non_basic_formats(); + result_profiles = _formats_converter.get_all_possible_profiles( get_raw_stream_profiles(), + true /*add_missing_identities*/ ); + break; + // fall-thru case format_conversion::full: result_profiles = _formats_converter.get_all_possible_profiles( get_raw_stream_profiles() ); diff --git a/third-party/rsutils/include/rsutils/ios/field.h b/third-party/rsutils/include/rsutils/ios/field.h index fee0b3d31e..d3c662cc69 100644 --- a/third-party/rsutils/include/rsutils/ios/field.h +++ b/third-party/rsutils/include/rsutils/ios/field.h @@ -38,6 +38,14 @@ struct field // os << field::separator << "key" << field::value << value; static std::ostream & value( std::ostream & ); + // Mark the next field as the first + // os << field::first; + // if( ... ) + // os << field::separator << "a"; + // if( ... ) + // os << field::separator << "b"; + static std::ostream & first( std::ostream & ); + // Start a "group" of fields that are indented, e.g.: // os << "quality-of-service" << field::group() << _qos; // Which will output: @@ -53,6 +61,9 @@ struct field { mutable std::ostream * pos = nullptr; ~group(); // needed to unindent/close the group + + static std::ostream & start( std::ostream & ); + static std::ostream & end( std::ostream & ); }; }; diff --git a/third-party/rsutils/src/ios.cpp b/third-party/rsutils/src/ios.cpp index 3b105f88ac..0d348e2f9e 100644 --- a/third-party/rsutils/src/ios.cpp +++ b/third-party/rsutils/src/ios.cpp @@ -17,6 +17,22 @@ long & indent_flag( std::ios_base & s ) } +static long & first_flag( std::ios_base & s ) +{ + static int const index = std::ios_base::xalloc(); + return s.iword( index ); +} + + +inline bool is_first( std::ios_base & s ) { return first_flag( s ) > 0; } +inline bool set_first( std::ios_base & s, bool f = true ) +{ + bool was_first = is_first( s ); + first_flag( s ) = (long)f; + return was_first; +} + + std::ostream & operator<<( std::ostream & os, indent const & indent ) { add_indent( os, indent.d ); @@ -26,7 +42,9 @@ std::ostream & operator<<( std::ostream & os, indent const & indent ) /*static*/ std::ostream & field::sameline( std::ostream & os ) { - return os << ' '; + if( ! set_first( os, false ) ) + os << ' '; + return os; } @@ -37,6 +55,7 @@ std::ostream & operator<<( std::ostream & os, indent const & indent ) os << '\n'; while( i-- ) os << ' '; + set_first( os, true ); } else { @@ -48,7 +67,31 @@ std::ostream & operator<<( std::ostream & os, indent const & indent ) /*static*/ std::ostream & field::value( std::ostream & os ) { - os << ' '; + if( ! set_first( os, false ) ) + os << ' '; + return os; +} + + +/*static*/ std::ostream & field::first( std::ostream & os ) +{ + set_first( os, true ); + return os; +} + + +/*static*/ std::ostream & field::group::start( std::ostream & os ) +{ + os << '['; + set_first( os, true ); + return os; +} + + +/*static*/ std::ostream & field::group::end( std::ostream & os ) +{ + os << ']'; + set_first( os, false ); return os; } @@ -58,7 +101,7 @@ std::ostream & operator<<( std::ostream & os, field::group const & group ) if( has_indent( os ) ) os << indent(); else - os << "["; + os << field::group::start; group.pos = &os; return os; } @@ -71,7 +114,7 @@ field::group::~group() if( has_indent( *pos ) ) *pos << unindent(); else - *pos << " ]"; + *pos << field::group::end; } }