Playback ZedX SVO in ROS2 on X64

Hi,

I am running into an issue when trying to play an SVO in ROS2 on remote PC. The SVO plays back fine using ZED_Explorer, but when trying to open it using the ROS2 wrapper I get:

$ros2 launch zed_wrapper zed_camera.launch.py camera_model:=zedx svo_file:=~/workspace/projects/process_svo/data/svos/front_cam_0921.svo2
….
[component_container_isolated-2] [ERROR] [1754929016.869881133] [zed.zed_node]: Camera model ZED X is available only with NVIDIA Jetson devices.

I have not had this issue previously using ROS1(using remote streams from the Jetson). Is this a new issue in ROS2? Am I doing something wrong? Is there a work around? I tried setting a different camera model, which allows the node to open, but of course the output is trash at that point.

Thank you!

Benjamin

Hi @benijohn,

In the ZED ROS2 Wrapper, the launcher argument is svo_path and not svo_file, this is probably why you have this error.

@mattrouss This was indeed the issue. My mistake. However, I am now facing a different issue. The node launches and opens the svo, but immediately says:

[WARNING] END OF SVO FILE REACHED in sl::ERROR_CODE sl::camera::grab(sl::RuntimeParameters)

and while I see a lot of topics listed, none of them appear to be publishing anything. this is what I have done:

ros2 launch zed_wrapper zed_camera.launch.py camera_model:=zed2i svo_path:=~/workspace/projects/process_svo/data/svos/front_cam_0921.svo2 svo_loop:=true

and the config file:

 svo:
            use_svo_timestamps: true # Use the SVO timestamps to publish data. If false, data will be published at the system time.
            publish_svo_clock: true # [overwritten by launch file options] When use_svo_timestamps is true allows to publish the SVO clock to the `/clock` topic. This is useful for synchronous rosbag playback.
            svo_loop: true # Enable loop mode when using an SVO as input source. NOTE: ignored if SVO timestamping is used
            svo_realtime: true # if true the SVO will be played trying to respect the original framerate eventually skipping frames, otherwise every frame will be processed respecting the `pub_frame_rate` setting
            play_from_frame: 0 # Start playing the SVO from a specific frame
            replay_rate: 1.0 # Replay rate for the SVO when not used in realtime mode (between [0.10-5.0])

This svo does play in ZED_Explorer. The one parameter I am unsure about is play_from_frame: 0.

I have noticed that when creating multiple recordings from a camera, each SVO starts recording at the frame where the last left off, rather than starting at 0 for each new recording. I assume this is intended behavior as I don’t recall ever telling it to do this. But for this SVO, frame 0 doesn’t exist. Could this be causing issues? Is there a setting to automatically detect and find the actual first frame value? Or should that already be handled?

Thanks!

Benjamin

Hi @benijohn,

Could you share the SVO which has this issue? You can send it by email at support@stereolabs.com with a link to this topic.

This is not intended behavior. An SVO file will start to be recorded after a call from enableRecording() and performing grab() calls to the camera, and should be stopped by either disableRecording() or close(). When doing this, camera frames in an SVO are indexed starting from 0 at the beginning.

It would help to have a few SVO that show this behavior

Hi @benijohn,

Thank you for sending the SVOs, I was able to take a look and there indeed seems to be an issue with the recording of the second SVO.

To be sure to be able to reproduce this, could you send the resulting JSON from the ZED_Diagnostic tool, run on your recording system?

Also, can you reproduce this behavior in a C++ or Python script, without the ROS2 wrapper?

Hey I am attaching the diagnostic json, but it failed on camera. On the recording machine, the cameras are only available as remote streams. Is there a way to run the diagnostic using remote cameras?I did make a quick script combining the streaming receiver and svo recording examples. The problem doesn’t appear to be present when doing it this way. The script is here:

///////////////////////////////////////////////////////////////////////////

//

// Copyright (c) 2025, STEREOLABS.

//

// All rights reserved.

//

// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

// “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

//

///////////////////////////////////////////////////////////////////////////

/****************************************************************************************

** This sample shows how to record video in Stereolabs SVO format. **

** SVO video files can be played with the ZED API and used with its different modules **

*****************************************************************************************/

// ZED includes

#include <sl/Camera.hpp>

// Sample includes

#include “utils.hpp”

// Using namespace

using namespace sl;

using namespace std;

void print(string msg_prefix, ERROR_CODE err_code = ERROR_CODE::SUCCESS, string msg_suffix = “”);

void parseArgs(int argc, char **argv,sl::InitParameters& param);

int main(int argc, char **argv) {

if (argc < 2) {

cout << “Usage : Only the path of the output SVO file should be passed as argument.\n”;

return EXIT_FAILURE;

}

// Create a ZED camera

Camera zed;

// Set configuration parameters for the ZED

InitParameters init_parameters;

String ip = "192.168.16.175";

unsigned short port = 40000;

init_parameters.input.setFromStream(ip, port);

init_parameters.depth_mode = DEPTH_MODE::NONE;

init_parameters.async_image_retrieval = false; //This parameter can be used to record SVO in camera FPS even if the grab loop is running at a lower FPS (due to compute for ex.)

parseArgs(argc,argv,init_parameters);

// Open the camera

auto returned_state = zed.open(init_parameters);

if (returned_state != ERROR_CODE::SUCCESS) {

print(“Camera Open”, returned_state, “Exit program.”);

return EXIT_FAILURE;

}



// Enable recording with the filename specified in argument

RecordingParameters recording_parameters;

recording_parameters.video_filename.set(argv[1]);

recording_parameters.compression_mode = SVO_COMPRESSION_MODE::H265;

returned_state = zed.enableRecording(recording_parameters);

if (returned_state != ERROR_CODE::SUCCESS) {

print("Recording ZED : ", returned_state);

zed.close();

return EXIT_FAILURE;

}



// Start recording SVO, stop with Ctrl-C command

print(“SVO is Recording, use Ctrl-C to stop.” );

SetCtrlHandler();

sl::RecordingStatus rec_status;

while (!exit_app) {

if (zed.grab() <= ERROR_CODE::SUCCESS) {

        // Each new frame is added to the SVO file

        rec_status = zed.getRecordingStatus();

printf(" NFrames SVO: %d / %d\n",rec_status.number_frames_ingested,rec_status.number_frames_encoded);

    }

else

break;

}



// Stop recording

zed.disableRecording();

zed.close();

return EXIT_SUCCESS;

}

void print(string msg_prefix, ERROR_CODE err_code, string msg_suffix) {

cout <<“[Sample]”;

if (err_code != ERROR_CODE::SUCCESS)

cout << "[Error] ";

else

cout<<" ";

cout << msg_prefix << " ";

if (err_code != ERROR_CODE::SUCCESS) {

cout << " | " << toString(err_code) << " : ";

cout << toVerbose(err_code);

}

if (!msg_suffix.empty())

cout << " " << msg_suffix;

cout << endl;

}

void parseArgs(int argc, char **argv,sl::InitParameters& param)

{

if (argc > 2 && string(argv[2]).find(“.svo”)!=string::npos) {

    // SVO input mode

param.input.setFromSVOFile(argv[2]);

cout << "[Sample] Using SVO File input: " << argv[2] << endl;

} else if (argc > 2 && string(argv\[2\]).find(".svo")==string::npos) {

string arg = string(argv[2]);

unsigned int a,b,c,d,port;

if (sscanf(arg.c_str(),“%u.%u.%u.%u:%d”, &a, &b, &c, &d,&port) == 5) {

        // Stream input mode - IP + port

string ip_adress = to_string(a)+“.”+to_string(b)+“.”+to_string(c)+“.”+to_string(d);

param.input.setFromStream(sl::String(ip_adress.c_str()),port);

cout<<"[Sample] Using Stream input, IP : “<<ip_adress<<”, port : "<<port<<endl;

    }

else if (sscanf(arg.c_str(),“%u.%u.%u.%u”, &a, &b, &c, &d) == 4) {

        // Stream input mode - IP only

param.input.setFromStream(sl::String(argv[2]));

cout<<"[Sample] Using Stream input, IP : "<<argv[2]<<endl;

    }

else if (arg.find(“HD2K”) != string::npos) {

param.camera_resolution = RESOLUTION::HD2K;

cout << “[Sample] Using Camera in resolution HD2K” << endl;

    }else if (arg.find("HD1200") != string::npos) {

param.camera_resolution = RESOLUTION::HD1200;

cout << “[Sample] Using Camera in resolution HD1200” << endl;

    } else if (arg.find("HD1080") != string::npos) {

param.camera_resolution = RESOLUTION::HD1080;

cout << “[Sample] Using Camera in resolution HD1080” << endl;

    } else if (arg.find("HD720") != string::npos) {

param.camera_resolution = RESOLUTION::HD720;

cout << “[Sample] Using Camera in resolution HD720” << endl;

    }else if (arg.find("SVGA") != string::npos) {

param.camera_resolution = RESOLUTION::SVGA;

cout << “[Sample] Using Camera in resolution SVGA” << endl;

    }else if (arg.find("VGA") != string::npos) {

param.camera_resolution = RESOLUTION::VGA;

cout << “[Sample] Using Camera in resolution VGA” << endl;

    }

} else {

    // Default

}

}

I will also send the SVOs recorded using this approach.

Thanks!

Benjamin

Attached are the SVOs recorded using regular c++ script.


Hi @benijohn,

ZED_Diagnostic needs to run on the physical device on which the cameras are connected. It would be great if you can get these diagnostics as well.