Skip to content

Commit 70c6f49

Browse files
committed
Add y16 10bit data handling to DDS streams
1 parent 7d1fb18 commit 70c6f49

10 files changed

+99
-27
lines changed

src/dds/rs-dds-sensor-proxy.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <src/context.h>
2525

2626
#include <src/proc/color-formats-converter.h>
27+
#include <src/proc/y16_10msb-to-y16.h>
2728

2829
#include <rsutils/string/nocase.h>
2930
#include <rsutils/json.h>
@@ -171,11 +172,22 @@ void dds_sensor_proxy::register_basic_converters()
171172
{ RS2_FORMAT_Y8, RS2_STREAM_INFRARED, 1 },
172173
{ RS2_FORMAT_Y8, RS2_STREAM_INFRARED, 2 } },
173174
[]() { return std::make_shared< identity_processing_block >(); } } );
175+
std::string product_line = get_device().get_info( RS2_CAMERA_INFO_PRODUCT_LINE );
176+
bool d400 = product_line.find("D400") != std::string::npos;
174177
_formats_converter.register_converter(
175178
{ { { RS2_FORMAT_Y16, RS2_STREAM_INFRARED } },
176179
{ { RS2_FORMAT_Y16, RS2_STREAM_INFRARED, 1 },
177180
{ RS2_FORMAT_Y16, RS2_STREAM_INFRARED, 2 } },
178-
[]() { return std::make_shared< identity_processing_block >(); } } );
181+
[d400]() -> std::shared_ptr< stream_filter_processing_block >
182+
{
183+
// Y16 is calibration format, sent with 10bit data that needs conversion to 16bit.
184+
// D400 products don't have DDS so we use rs-dds-adapter that already converts.
185+
// Calibration with other products that use rs-dds-adapter is currently not supported.
186+
if( d400 )
187+
return std::make_shared< identity_processing_block >();
188+
189+
return std::make_shared< y16_10msb_to_y16 >();
190+
} } );
179191

180192
// Motion
181193
_formats_converter.register_converter( processing_block_factory::create_id_pbf( RS2_FORMAT_COMBINED_MOTION, RS2_STREAM_MOTION ) );

src/ds/d500/d500-device.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
#include "proc/depth-formats-converter.h"
2424
#include "proc/y8i-to-y8y8.h"
25-
#include "proc/y16i-to-y10msby10msb.h"
25+
#include "proc/y16i-10msb-to-y16y16.h"
2626

2727
#include <rsutils/type/fourcc.h>
2828
using rs_fourcc = rsutils::type::fourcc;
@@ -516,7 +516,7 @@ namespace librealsense
516516
depth_sensor.register_processing_block(
517517
{ RS2_FORMAT_Y16I },
518518
{ {RS2_FORMAT_Y16, RS2_STREAM_INFRARED, 1}, {RS2_FORMAT_Y16, RS2_STREAM_INFRARED, 2} },
519-
[]() {return std::make_shared<y16i_to_y10msby10msb>(); }
519+
[]() {return std::make_shared<y16i_10msb_to_y16y16>(); }
520520
);
521521

522522
pid_hex_str = rsutils::string::from() << std::uppercase << rsutils::string::hexdump( _pid );

src/proc/CMakeLists.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ target_sources(${LRS_TARGET}
3030
"${CMAKE_CURRENT_LIST_DIR}/y8i-to-y8y8.cpp"
3131
"${CMAKE_CURRENT_LIST_DIR}/y12i-to-y16y16.cpp"
3232
"${CMAKE_CURRENT_LIST_DIR}/y12i-to-y16y16-mipi.cpp"
33-
"${CMAKE_CURRENT_LIST_DIR}/y16i-to-y10msby10msb.cpp"
33+
"${CMAKE_CURRENT_LIST_DIR}/y16i-10msb-to-y16y16.cpp"
34+
"${CMAKE_CURRENT_LIST_DIR}/y16_10msb-to-y16.cpp"
3435
"${CMAKE_CURRENT_LIST_DIR}/identity-processing-block.cpp"
3536
"${CMAKE_CURRENT_LIST_DIR}/threshold.cpp"
3637
"${CMAKE_CURRENT_LIST_DIR}/rates-printer.cpp"
@@ -61,7 +62,8 @@ target_sources(${LRS_TARGET}
6162
"${CMAKE_CURRENT_LIST_DIR}/y8i-to-y8y8.h"
6263
"${CMAKE_CURRENT_LIST_DIR}/y12i-to-y16y16.h"
6364
"${CMAKE_CURRENT_LIST_DIR}/y12i-to-y16y16-mipi.h"
64-
"${CMAKE_CURRENT_LIST_DIR}/y16i-to-y10msby10msb.h"
65+
"${CMAKE_CURRENT_LIST_DIR}/y16i-10msb-to-y16y16.h"
66+
"${CMAKE_CURRENT_LIST_DIR}/y16_10msb-to-y16.h"
6567
"${CMAKE_CURRENT_LIST_DIR}/identity-processing-block.h"
6668
"${CMAKE_CURRENT_LIST_DIR}/threshold.h"
6769
"${CMAKE_CURRENT_LIST_DIR}/rates-printer.h"

src/proc/y16_10msb-to-y16.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// License: Apache 2.0. See LICENSE file in root directory.
2+
// Copyright(c) 2022 Intel Corporation. All Rights Reserved.
3+
4+
#include "y16_10msb-to-y16.h"
5+
#include "stream.h"
6+
// TODO - CUDA
7+
//#ifdef RS2_USE_CUDA
8+
//#include "cuda/cuda-conversion.cuh"
9+
//#endif
10+
11+
namespace librealsense
12+
{
13+
y16_10msb_to_y16::y16_10msb_to_y16() : functional_processing_block( "Y16 10msb to Y16 Transform", RS2_FORMAT_Y16, RS2_STREAM_INFRARED )
14+
{
15+
}
16+
17+
void y16_10msb_to_y16::process_function( uint8_t * const dest[], const uint8_t * source, int width, int height, int actual_size, int input_size)
18+
{
19+
// TODO - CUDA
20+
// #ifdef RS2_USE_CUDA
21+
// rscuda::y16_from_y16_10msb_cuda( dest, count, reinterpret_cast< const uint16_t * >( source ) );
22+
// #else
23+
uint16_t * dest_16_bit = reinterpret_cast< uint16_t * >( dest[0] );
24+
const uint16_t * source_16_bit = reinterpret_cast< const uint16_t * >( source );
25+
for( size_t i = 0; i < width * height; ++i )
26+
{
27+
// Since the data is received only in 10 bits, and the conversion is to 16 bits,
28+
// the range moves from [0 : 2^10-1] to [0 : 2^16-1], so the values should be converted accordingly:
29+
// x in range [0 : 2^10-1] is converted to y = x * (2^16-1)/(2^10-1) approx = x * (64 + 1/16)
30+
// And x * (64 + 1/16) = x * 64 + x * 1/16 = x << 6 | x >> 4
31+
// This operation is done using shiftings to make it more efficient, and with a non-significant accuracy loss.
32+
dest_16_bit[i] = source_16_bit[i] << 6 | source_16_bit[i] >> 4;
33+
}
34+
// #endif
35+
}
36+
}

src/proc/y16_10msb-to-y16.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// License: Apache 2.0. See LICENSE file in root directory.
2+
// Copyright(c) 2025 Intel Corporation. All Rights Reserved.
3+
4+
#pragma once
5+
6+
#include "synthetic-stream.h"
7+
8+
namespace librealsense
9+
{
10+
class y16_10msb_to_y16 : public functional_processing_block
11+
{
12+
public:
13+
y16_10msb_to_y16();
14+
15+
protected:
16+
void process_function( uint8_t * const dest[], const uint8_t * source, int width, int height, int actual_size, int input_size ) override;
17+
};
18+
}
19+
Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// License: Apache 2.0. See LICENSE file in root directory.
22
// Copyright(c) 2022 Intel Corporation. All Rights Reserved.
33

4-
#include "y16i-to-y10msby10msb.h"
4+
#include "y16i-10msb-to-y16y16.h"
55
#include "stream.h"
66
// CUDA TODO
77
//#ifdef RS2_USE_CUDA
@@ -11,38 +11,38 @@
1111
namespace librealsense
1212
{
1313
struct y16i_pixel { uint16_t left : 16, right : 16;
14-
// explanation of "return x << 6 | x >> 4" :
14+
// Explanation of "return x << 6 | x >> 4" :
1515
// Since the data is received only in 10 bits, and the conversion is to 16 bits,
1616
// the range moves from [0 : 2^10-1] to [0 : 2^16-1], so the values should be converted accordingly:
17-
// x is range [0 : 2^10-1] is converted to y = x * (2^16-1)/(2^10-1) approx= x * (64 + 1/16)
17+
// x in range [0 : 2^10-1] is converted to y = x * (2^16-1)/(2^10-1) approx = x * (64 + 1/16)
1818
// And x * (64 + 1/16) = x * 64 + x * 1/16 = x << 6 | x >> 4
1919
// This operation is done using shiftings to make it more efficient, and with a non-significant accuracy loss.
2020
uint16_t l() const { return left << 6 | left >> 4; }
2121
uint16_t r() const { return right << 6 | right >> 4; }
2222
};
23-
void unpack_y10msb_y10msb_from_y16i( uint8_t * const dest[], const uint8_t * source, int width, int height, int actual_size)
23+
void unpack_y16_y16_from_y16i_10msb( uint8_t * const dest[], const uint8_t * source, int width, int height, int actual_size)
2424
{
2525
auto count = width * height;
2626
// CUDA TODO
2727
//#ifdef RS2_USE_CUDA
28-
// rscuda::split_frame_y10msb_y10msb_from_y16i_cuda(dest, count, reinterpret_cast<const y12i_pixel*>(source));
28+
// rscuda::split_frame_y16_16_from_y16i_10msb_cuda(dest, count, reinterpret_cast<const y16i_pixel*>(source));
2929
//#else
3030
split_frame(dest, count, reinterpret_cast<const y16i_pixel*>(source),
3131
[](const y16i_pixel& p) -> uint16_t { return (p.l()); },
3232
[](const y16i_pixel& p) -> uint16_t { return (p.r()); });
3333
//#endif
3434
}
3535

36-
y16i_to_y10msby10msb::y16i_to_y10msby10msb(int left_idx, int right_idx)
37-
: y16i_to_y10msby10msb("Y16I to Y10msbL Y10msbR Transform", left_idx, right_idx) {}
36+
y16i_10msb_to_y16y16::y16i_10msb_to_y16y16(int left_idx, int right_idx)
37+
: y16i_10msb_to_y16y16("Y16I 10msb to Y16L Y16R Transform", left_idx, right_idx) {}
3838

39-
y16i_to_y10msby10msb::y16i_to_y10msby10msb(const char* name, int left_idx, int right_idx)
39+
y16i_10msb_to_y16y16::y16i_10msb_to_y16y16(const char* name, int left_idx, int right_idx)
4040
: interleaved_functional_processing_block(name, RS2_FORMAT_Y16I, RS2_FORMAT_Y16, RS2_STREAM_INFRARED, RS2_EXTENSION_VIDEO_FRAME, 1,
4141
RS2_FORMAT_Y16, RS2_STREAM_INFRARED, RS2_EXTENSION_VIDEO_FRAME, 2)
4242
{}
4343

44-
void y16i_to_y10msby10msb::process_function( uint8_t * const dest[], const uint8_t * source, int width, int height, int actual_size, int input_size)
44+
void y16i_10msb_to_y16y16::process_function( uint8_t * const dest[], const uint8_t * source, int width, int height, int actual_size, int input_size)
4545
{
46-
unpack_y10msb_y10msb_from_y16i(dest, source, width, height, actual_size);
46+
unpack_y16_y16_from_y16i_10msb(dest, source, width, height, actual_size);
4747
}
4848
}

src/proc/y16i-to-y10msby10msb.h renamed to src/proc/y16i-10msb-to-y16y16.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@
99

1010
namespace librealsense
1111
{
12-
class y16i_to_y10msby10msb : public interleaved_functional_processing_block
12+
class y16i_10msb_to_y16y16 : public interleaved_functional_processing_block
1313
{
1414
public:
15-
y16i_to_y10msby10msb(int left_idx = 1, int right_idx = 2);
15+
y16i_10msb_to_y16y16(int left_idx = 1, int right_idx = 2);
1616

1717
protected:
18-
y16i_to_y10msby10msb(const char* name, int left_idx, int right_idx);
18+
y16i_10msb_to_y16y16(const char* name, int left_idx, int right_idx);
1919
void process_function( uint8_t * const dest[], const uint8_t * source, int width, int height, int actual_size, int input_size) override;
2020
};
2121
}

unit-tests/dds/formats-conversion-server.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313

1414
device_info = dds.message.device_info.from_json({
1515
"name": "formats-conversion-device",
16-
"topic-root": "root_123"
16+
"topic-root": "root_123",
17+
"product-line": "D400"
1718
})
1819

1920
# Used to created a device_server per test case, but it currently creates problems when creating a second device while

unit-tests/dds/test-librs-options.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@
1515
participant.init( 123, 'server' )
1616

1717
with test.closure( 'Create the server' ):
18-
device_info = dds.message.device_info()
19-
device_info.name = 'Options device'
20-
device_info.topic_root = 'librs-options/device'
18+
device_info = dds.message.device_info.from_json({
19+
"name": "Options device",
20+
"topic-root": "librs-options/device",
21+
"product-line": "D400"
22+
})
2123
s1p1 = dds.video_stream_profile( 9, dds.video_encoding.rgb, 10, 10 )
2224
s1profiles = [s1p1]
2325
s1 = dds.color_stream_server( 's1', 'sensor' )

unit-tests/dds/test-stream-sensor-bridge.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ def find_active_profile( stream_name ):
126126
raise KeyError( f"can't find '{sensor_name}' profile for stream '{stream_name}'" )
127127

128128
def find_server_profile( stream_name, profile_string ):
129-
by_string = f"<'{stream_name}' {profile_string}>"
129+
by_string = f"<'{stream_name}' {profile_string}>"
130130
for profile in servers[stream_name].profiles():
131131
if profile.to_string() == by_string:
132132
return profile
@@ -331,12 +331,12 @@ def find_server_profile( stream_name, profile_string ):
331331
bridge.open( find_server_profile( 'Infrared_1', '1280x800 mono8 @ 30 Hz' ))
332332
bridge.close( servers['Infrared_1'] )
333333
bridge.close( servers['Infrared_1'] )
334-
bridge.open( find_server_profile( 'Infrared_1', '1280x800 Y16 @ 25 Hz' ))
334+
bridge.open( find_server_profile( 'Infrared_1', '1280x800 mono16 @ 25 Hz' ))
335335
bridge.reset()
336-
bridge.open( find_server_profile( 'Infrared_1', '1280x800 Y16 @ 15 Hz' ))
336+
bridge.open( find_server_profile( 'Infrared_1', '1280x800 mono16 @ 15 Hz' ))
337337
test.check_throws( lambda:
338-
bridge.open( find_server_profile( 'Infrared_1', '1280x800 Y16 @ 25 Hz' )),
339-
RuntimeError, "profile <'Infrared_1' 1280x800 Y16 @ 25 Hz> is incompatible with already-open <'Infrared_1' 1280x800 Y16 @ 15 Hz>" )
338+
bridge.open( find_server_profile( 'Infrared_1', '1280x800 mono16 @ 25 Hz' )),
339+
RuntimeError, "profile <'Infrared_1' 1280x800 mono16 @ 25 Hz> is incompatible with already-open <'Infrared_1' 1280x800 mono16 @ 15 Hz>" )
340340
reset()
341341
#
342342
#############################################################################################

0 commit comments

Comments
 (0)