-cut opption doesn't work in ZED SVOEditor.exe in some .svo files

I have a Python script that splits a “.svo2” file into 7 “.svo2” files.
I know the start and end timestamp for the split to seconds.
I run this command to split the “svo2” file:

"C:\Program Files (x86)\ZED SDK\tools\ZED SVOEditor.exe" -cut "path/to/input/svo_file.svo2" -start-timestamp 1722324826000000000 -end-timestamp 1722324856000000000 "path/to/input/svo_file.svo2"

Sometimes it works fine, but sometimes I get this error:

-cut option detected
Detected timestamp input instead of frame index. The frame 38400 will be used as start frame for cutting
Detected timestamp input instead of frame index. The frame 38401 will be used as end frame for cutting
*FAIL : Invalid parameters : In/out :  38400 38401

After checking the “.svo2” file, I didn’t find anything wrong. All these files are playable and not corrupted.
Output of ZED SVOEditor.exe -inf:

-inf option detected
SVO Infos : SVO v 2
Image Size : [ 1280  x  720 ]
Framerate :  60
Number of Frames :  38401
ZED Serial Number :  <Serial number>
Compression mode :  " H265 Lossy (GPU) compression"
Product : ZED2i
Sensors Fw version :  777
Camera Fw version :  1523

I also see that the timestamps of the “.svo2” files are correct. I checked in **ZED Explorer** and extracted timestamp of the first and the last timestamp of the “.svo2” file using the pyzed library in Python 3.9.13.
What I can do to avoid this error and how to do that?
I’m using ZED SDK 4.1.3

Another question. How I can get dropped frames number of ".svo2 file using Python?

Hi @VladEf,

Welcome to the Stereolabs forums! :wave:

It seems that ZED_SVO_Editor has found that the timestamps you’ve provided are not included in the SVO in question, that is why it only returns one frame.

Can you confirm that the given timestamps are included in the SVO? If so, would it be possible to send this SVO so we can take a look? You can send it privately at support@stereolabs.com

To get the number of dropped frames using the Python API, you can take the timestamps of 2 consecutive frames from the SVO, and determine if the second frame is late compared with the expected frame rate.

You can also use this method from the ZED SDK: Camera Class Reference | API Reference | Stereolabs

Hi,
I have this problem in 5 SVO files. I can’t make them available.
I saw in ZED explorer that the start and end timestamps provided for trimming are between the first and last timestamps of the frame in the SVO file.
I also extracted the first and last timestamps of the SVO file using pyzed in python and saw that the timestamps provided for trimming are in that range.
What do you need to check and how can I give you this information?
Maybe I can cut the video in some other way, like using python or providing a frame index for cutting?
If so, what is the best way to do it?

Hello @VladEf,

You can indeed use frame index for cutting SVO file. Please use -s for the start frame index and -e for the end frame. For example:
ZED_SVO_Editor -cut svo1.svo -s 100 -e 200 output.svo

This is indeed what do ZED_SVO_Editor internally. It find the frame index that is close to the provided timestamp and run the cut option on the found frame index. This function is available inside SDK. You could use getSVOPositionAtTimestamp method for this. However this is available only in C++.

If cutting by frame index does not work, we could investigate what’s wrong but we would need SVO files for this. If you want to share it privately no problem, we won’t share it to anybody else.

Regards,
Tanguy

Hello @TanguyHardelin
I managed to cut an SVO file using the first and last frame indexes. Thank you.
For some reason I need to run this command ZED_SVO_Editor -cut -s <start_frame_index - 1> -e <end_frame_index + 1> to cut SVO file so that the first and last timestamp will be the correct timestamp. Is this correct?
I have checked that the timestamp of the frame I received using my code is the correct timestamp I need.
This is the code that I use to find the frame index by timestamp:

import datetime
import pyzed.sl as sl
from typing import Optional, Tuple


def find_frame_index_for_timestamp(svo_file: str, target_timestamp: int) -> Optional[Tuple[int, int]]:
    # Initialize the ZED camera
    zed = sl.Camera()

    # Set the SVO file as input
    input_params = sl.InitParameters()
    input_params.set_from_svo_file(svo_file)
    input_params.coordinate_units = sl.UNIT.METER

    # Open the camera
    if zed.open(input_params) != sl.ERROR_CODE.SUCCESS:
        print("Error opening SVO file")
        return None

    runtime = sl.RuntimeParameters()

    try:
        # Get the total number of frames in the SVO file
        total_frames = zed.get_svo_number_of_frames()

        # Binary search for the target timestamp
        left, right = 0, total_frames - 1
        while left <= right:
            mid = (left + right) // 2

            # Seek to the middle frame
            zed.set_svo_position(mid)
            if zed.grab(runtime) != sl.ERROR_CODE.SUCCESS:
                print(f"Error grabbing frame at position {mid}")
                return None, None

            # Get the current frame's timestamp
            frame_timestamp = get_timestamp_nano(zed=zed, runtime=runtime, frame_index=mid)

            # Compare timestamps
            if frame_timestamp < target_timestamp:
                left = mid + 1
            elif frame_timestamp > target_timestamp:
                right = mid - 1
            else:
                # Exact match found
                return mid, frame_timestamp

        frame_timestamp = get_timestamp_nano(zed, runtime, left)
        # If an exact match is not found, return the closest frame
        return (left, frame_timestamp) if left < total_frames else (None, None)
    finally:
        zed.close()


def get_timestamp_nano(zed: sl.Camera, runtime: sl.RuntimeParameters, frame_index: int) -> Optional[int]:
    # Seek to the frame by frame_index
    zed.set_svo_position(frame_index)
    if zed.grab(runtime) != sl.ERROR_CODE.SUCCESS:
        print(f"Error grabbing frame at position {frame_index}")
        return None

    # Get the current frame's timestamp
    frame_timestamp = zed.get_timestamp(sl.TIME_REFERENCE.IMAGE).get_nanoseconds()
    return frame_timestamp


svo_file = "path/to/svo/file.svo2"
timestamp_1 = 1722324826000000000
index_1, epoch_1 = find_frame_index_for_timestamp(svo_file, timestamp_1)
print(f"Frame index for start timestamp {timestamp_1} - {datetime.datetime.fromtimestamp(timestamp_1 / 1000 ** 3)}: {index_1} - {epoch_1} - {datetime.datetime.fromtimestamp(epoch_1 / 1000 ** 3)}")

Hello @VladEf,

Indeed the cut option cut a SVO file from the first frame to the last frame excluded. Sorry for the confusion. If you want to cut with the last frame included your command is correct :slight_smile:

Regards,
tanguy

Same problem with the first frame.
When I cut an SVO file using this command ZED_SVO_Editor -cut -s <start_frame_index> -e <end_frame_index + 1> the timestamp of the first frame in the cut SVO file doesn’t match the timestamp I got in start_frame_index in the original SVO file.
Maybe I am making a mistake?

Hello again @VladEf

The first frame of the trimmed SVO file should correspond to the start_frame_index . I have tested your script, and it functions correctly on desktop platforms. However, there may be issues when using a Jetson platform. Specifically, there was a known issue with the set_svo_position method on Jetson devices, which has now been resolved and will be included in the upcoming release. In the interim, a workaround for Jetson users is to retrieve the current position using get_svo_position instead of relying on the set_svo_position method.

Are you using jetson platform for cutting the SVO2 file ? If you are working on a desktop, I may require additional information to assist you, particularly details regarding the SVO2 file, start and end timestamps.

Regards,
Tanguy

Hello @TanguyHardelin
Thank you for your reply.
I’m working on a desktop. Windows 11
You need start and end timestamps of the original SVO2 file or the cut file.
When I use this command ZED_SVO_Editor -cut -s <start_frame_index-1> -e <end_frame_index+1>, the start and end timestamps will be the same as the start_frame_index and end_frame_index timestamps in the original SVO2 file.

I may have identified the issue. Are you referring to the precise timestamp from the SVO2 data or a closely approximate fixed timestamp that aligns with the SVO2 frames?

In my test, I extracted the timestamp from the SVO2 using the following code (apologies for it being in C++, but the same can be achieved in Python):

// ZED include
#include <sl/Camera.hpp>

// Using namespace
using namespace sl;
using namespace std;

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

    // Create ZED objects
    Camera zed;
    InitParameters init_parameters;
    init_parameters.input.setFromSVOFile(argv[1]);
    init_parameters.depth_mode = sl::DEPTH_MODE::NONE;
    init_parameters.sdk_verbose = 1;

    // Open the camera
    auto returned_state = zed.open(init_parameters);
    if (returned_state != ERROR_CODE::SUCCESS)
    {
        std::cerr << "Cannot open camera" << std::endl;
        return EXIT_FAILURE;
    }

    sl::Mat svo_image;
    while (1)
    {
        returned_state = zed.grab();
        if (returned_state == ERROR_CODE::SUCCESS)
        {
            // Get the side by side image
            zed.retrieveImage(svo_image, VIEW::SIDE_BY_SIDE);
            int svo_position = zed.getSVOPosition();
            std::cout << "SVO position: " << svo_position << " timestamp " << svo_image.timestamp.getNanoseconds() << std::endl;
        }
        else
            break;
    }
    zed.close();
    return EXIT_SUCCESS;
}

If the timestamp stored in timestamp_1 precisely matches a timestamp in the SVO2 data, the correct frame is returned. Otherwise, it returns the corresponding frame index + 1. This is likely why you need to initiate the cut with a starting frame equal to <start_frame_index-1>.

Regards,
Tanguy