Skip to content

Commit 602749f

Browse files
danielyan86129meta-codesync[bot]
authored andcommitted
Add DataLayout support for pyvrs VRSWriter (#356)
Summary: Pull Request resolved: #356 Pull Request resolved: #355 * **rename of zstd**: needed because OSS version only expose ZSTD_MEDIUM via pybind. internal version still works b.c. it exposes both ZSTD_MEDIUM and Zmedium. Differential Revision: D95732614
1 parent 2dcd1fd commit 602749f

7 files changed

Lines changed: 451 additions & 4 deletions

File tree

.github/workflows/deploy.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,14 @@ jobs:
5454
- name: Set up Python
5555
uses: actions/setup-python@v5
5656
with:
57-
python-version: '3.9'
57+
python-version: '3.11'
5858
- name: Upgrade pip
5959
run: |
6060
python3 -m pip install --upgrade pip
6161
6262
- name: Install cibuildwheel
6363
run: |
64-
python3 -m pip install cibuildwheel==2.17.0
64+
python3 -m pip install cibuildwheel==2.22.0
6565
6666
- name: Build wheels for CPython
6767
run: |

csrc/writer/VRSWriter.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include "StreamFactory.h"
4141

4242
// Open source DataLayout definitions
43+
#include "datalayouts/AriaGen2ImageDataLayout.h"
4344
#include "datalayouts/SampleDataLayout.h"
4445

4546
namespace py = pybind11;
@@ -74,6 +75,16 @@ void VRSWriter::init() {
7475
"sample_with_image", createSampleStreamWithImage);
7576
StreamFactory::getInstance().registerStreamCreationFunction(
7677
"sample_with_multiple_data_layout", createSampleStreamWithMultipleDataLayout);
78+
// Aria Gen2 camera streams with correct RecordableTypeId + H.265 content block
79+
StreamFactory::getInstance().registerFlavoredStreamCreationFunction(
80+
"aria_gen2_rgb_camera", [](const string& flavor) {
81+
return createAriaGen2ImageStream(
82+
flavor, RecordableTypeId::RgbCameraRecordableClass, "H.265");
83+
});
84+
StreamFactory::getInstance().registerFlavoredStreamCreationFunction(
85+
"aria_gen2_slam_camera", [](const string& flavor) {
86+
return createAriaGen2ImageStream(flavor, RecordableTypeId::SlamCameraData, "H.265");
87+
});
7788
/// Register open source stream writers (end)
7889

7990
#if IS_VRS_FB_INTERNAL()
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "AriaGen2ImageDataLayout.h"
18+
19+
#include <vrs/RecordFormat.h>
20+
21+
#include "../PyRecordable.h"
22+
23+
using namespace vrs;
24+
25+
namespace pyvrs {
26+
27+
std::unique_ptr<PyStream> createAriaGen2ImageStream(
28+
const std::string& flavor,
29+
RecordableTypeId typeId,
30+
const std::string& codec) {
31+
constexpr uint32_t kVersion = 2;
32+
33+
auto configurationRecordFormat = std::make_unique<PyRecordFormat>(
34+
Record::Type::CONFIGURATION,
35+
kVersion,
36+
std::make_unique<ImageSensorConfigurationLayout>(/*allocateVideoFields=*/true));
37+
38+
auto dataContentBlocks = codec == "H.265"
39+
? std::vector<ContentBlock>{ContentBlock("H.265", ImageContentBlockSpec::kQualityUndefined)}
40+
: std::vector<ContentBlock>{ContentBlock(ImageFormat::RAW)};
41+
42+
auto dataRecordFormat = std::make_unique<PyRecordFormat>(
43+
Record::Type::DATA,
44+
kVersion,
45+
std::make_unique<ImageDataLayout>(/*allocateVideoFields=*/true),
46+
dataContentBlocks);
47+
48+
return std::make_unique<PyStream>(
49+
typeId, flavor, std::move(configurationRecordFormat), std::move(dataRecordFormat));
50+
}
51+
52+
} // namespace pyvrs
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
// Aria Gen2 camera DataLayouts for OSS pyvrs writer.
18+
// Vendored from arvr/libraries/visiontypes/vrs/data_layouts/ImageDataLayout.h
19+
// with namespace changed from visiontypes::detail to pyvrs.
20+
21+
#pragma once
22+
23+
#include <cstdint>
24+
25+
#include <vrs/DataLayout.h>
26+
#include <vrs/DataLayoutConventions.h>
27+
#include <vrs/DataPieces.h>
28+
29+
namespace pyvrs {
30+
31+
using vrs::OptionalDataPieces;
32+
using vrs::datalayout_conventions::ImageSpecType;
33+
34+
// Additional fields to enable in ImageSensorConfigurationLayout when data was
35+
// encoded as video before recording.
36+
struct VideoConfigurationFields {
37+
vrs::DataPieceString videoCodecName{vrs::datalayout_conventions::kImageCodecName};
38+
};
39+
40+
struct ImageSensorConfigurationLayout : public vrs::AutoDataLayout {
41+
static constexpr uint32_t kVersion = 2;
42+
43+
explicit ImageSensorConfigurationLayout(bool allocateVideoFields = false)
44+
: videoConfigurationFields(allocateVideoFields) {}
45+
46+
vrs::DataPieceString deviceType{"device_type"};
47+
vrs::DataPieceString deviceVersion{"device_version"};
48+
vrs::DataPieceString deviceSerial{"device_serial"};
49+
50+
vrs::DataPieceValue<std::uint32_t> cameraId{"camera_id"};
51+
vrs::DataPieceValue<std::uint32_t> streamType{"stream_type"};
52+
vrs::DataPieceValue<std::uint32_t> streamIndex{"stream_index"};
53+
54+
vrs::DataPieceString sensorModel{"sensor_model"};
55+
vrs::DataPieceString sensorSerial{"sensor_serial"};
56+
57+
vrs::DataPieceValue<double> nominalRateHz{"nominal_rate"};
58+
59+
vrs::DataPieceValue<ImageSpecType> imageWidth{vrs::datalayout_conventions::kImageWidth};
60+
vrs::DataPieceValue<ImageSpecType> imageHeight{vrs::datalayout_conventions::kImageHeight};
61+
vrs::DataPieceValue<ImageSpecType> imageStride{vrs::datalayout_conventions::kImageStride};
62+
vrs::DataPieceValue<ImageSpecType> imageStride2{vrs::datalayout_conventions::kImageStride2};
63+
vrs::DataPieceValue<ImageSpecType> pixelFormat{vrs::datalayout_conventions::kImagePixelFormat};
64+
vrs::DataPieceValue<ImageSpecType> plane2OffsetRows{"image_plane_2_offset_rows"};
65+
vrs::DataPieceValue<ImageSpecType> plane3OffsetRows{"image_plane_3_offset_rows"};
66+
67+
vrs::DataPieceValue<std::uint32_t> imageOrientation{"image_orientation"};
68+
vrs::DataPieceValue<std::uint32_t> shutterDirection{"shutter_direction"};
69+
70+
vrs::DataPieceValue<double> exposureDurationMin{"exposure_duration.min"};
71+
vrs::DataPieceValue<double> exposureDurationMax{"exposure_duration.max"};
72+
73+
vrs::DataPieceValue<double> gainMin{"gain.min"};
74+
vrs::DataPieceValue<double> gainMax{"gain.max"};
75+
76+
vrs::DataPieceValue<double> gammaFactor{"gamma_factor"};
77+
78+
vrs::DataPieceString factoryCalibration{"factory_calibration"};
79+
vrs::DataPieceString onlineCalibration{"online_calibration"};
80+
81+
vrs::DataPieceString description{"description"};
82+
83+
vrs::DataPieceString cameraMuxModeName{"camera_mux_mode_name"};
84+
85+
const OptionalDataPieces<VideoConfigurationFields> videoConfigurationFields;
86+
87+
vrs::AutoDataLayoutEnd end;
88+
};
89+
90+
// Additional fields to enable in ImageDataLayout when data was encoded as video
91+
// before recording.
92+
struct VideoDataFields {
93+
vrs::DataPieceValue<double> keyFrameTimestamp{
94+
vrs::datalayout_conventions::kImageKeyFrameTimeStamp};
95+
vrs::DataPieceValue<ImageSpecType> keyFrameIndex{
96+
vrs::datalayout_conventions::kImageKeyFrameIndex};
97+
};
98+
99+
struct ImageDataLayout : public vrs::AutoDataLayout {
100+
static constexpr uint32_t kVersion = 2;
101+
102+
explicit ImageDataLayout(bool allocateVideoFields = false)
103+
: videoDataFields(allocateVideoFields) {}
104+
105+
vrs::DataPieceValue<std::uint64_t> groupId{"group_id"};
106+
vrs::DataPieceValue<std::uint64_t> groupMask{"group_mask"};
107+
vrs::DataPieceValue<std::uint64_t> streamIndexMask{"stream_index_mask"};
108+
vrs::DataPieceValue<std::uint64_t> frameNumber{"frame_number"};
109+
vrs::DataPieceValue<std::uint32_t> frameTag{"frame_tag"};
110+
vrs::DataPieceValue<double> exposureDuration{"exposure_duration_s"};
111+
vrs::DataPieceValue<double> gain{"gain"};
112+
vrs::DataPieceValue<double> readoutDurationSeconds{"readout_duration_s"};
113+
vrs::DataPieceValue<std::int64_t> captureTimestampNs{"capture_timestamp_ns"};
114+
vrs::DataPieceValue<std::int64_t> captureTimestampInProcessingClockDomainNs{
115+
"capture_timestamp_in_processing_clock_domain_ns"};
116+
vrs::DataPieceValue<std::int64_t> arrivalTimestampNs{"arrival_timestamp_ns"};
117+
vrs::DataPieceValue<std::int64_t> processingStartTimestampNs{"processing_start_timestamp_ns"};
118+
vrs::DataPieceValue<double> temperature{"temperature_deg_c"};
119+
vrs::DataPieceVector<uint8_t> imageMetadata{"image_metadata"};
120+
121+
const OptionalDataPieces<VideoDataFields> videoDataFields;
122+
123+
vrs::DataPieceValue<double> focusDistanceMm{"focus_distance_mm", -1.0};
124+
125+
vrs::AutoDataLayoutEnd end;
126+
};
127+
128+
class PyStream;
129+
130+
std::unique_ptr<PyStream> createAriaGen2ImageStream(
131+
const std::string& flavor,
132+
vrs::RecordableTypeId typeId,
133+
const std::string& codec = "H.265");
134+
135+
} // namespace pyvrs

pyvrs/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,15 @@
3535
recordable_type_id_name,
3636
RecordableId,
3737
RecordableTypeId,
38+
RecordFormat,
3839
records_checksum,
3940
RecordType,
41+
Stream,
4042
StreamNotFoundError,
4143
TimestampNotFoundError,
4244
verbatim_checksum,
4345
VRSRecord,
46+
Writer,
4447
)
4548

4649
from .reader import AsyncVRSReader, SyncVRSReader
@@ -69,10 +72,13 @@
6972
"recordable_type_id_name",
7073
"RecordableId",
7174
"RecordableTypeId",
75+
"RecordFormat",
7276
"records_checksum",
7377
"RecordType",
78+
"Stream",
7479
"StreamNotFoundError",
7580
"TimestampNotFoundError",
7681
"verbatim_checksum",
7782
"VRSRecord",
83+
"Writer",
7884
]

pyvrs/writer.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def create_stream(
5757
self,
5858
name: str,
5959
flavor: str = "",
60-
compression: CompressionPreset = CompressionPreset.Zmedium,
60+
compression: CompressionPreset = CompressionPreset.ZSTD_MEDIUM,
6161
) -> "VRSStream":
6262
if len(flavor) > 0:
6363
return VRSStream(
@@ -121,7 +121,7 @@ def __init__(
121121
self,
122122
stream: Stream,
123123
writer: VRSWriter,
124-
compression: CompressionPreset = CompressionPreset.Zmedium,
124+
compression: CompressionPreset = CompressionPreset.ZSTD_MEDIUM,
125125
) -> None:
126126
self.stream = stream
127127
self.stream.setCompression(compression)

0 commit comments

Comments
 (0)