Add args field to mjResource for decoder and encoder arguments.
Add an optional `const char* args` field to `mjResource` to allow passing resource arguments/hints (such as requested channel count or encoding options) to resource decoders and encoders. PiperOrigin-RevId: 959774058 Change-Id: Icc41a2bb3895fef24f98c5fa9a77cdad092a6bc7
This commit is contained in:
committed by
Copybara-Service
parent
83e621d771
commit
596b6f433d
@@ -30,6 +30,8 @@ Actuation
|
||||
|
||||
- :ref:`mjsActuator` gained ``velrange`` and ``ffrange`` fields, changing its size and layout. The :ref:`mjtGain`
|
||||
and :ref:`mjtDyn` enums gained ``pid`` members, shifting the values of ``mjGAIN_USER`` and ``mjDYN_USER``.
|
||||
- :ref:`mjResource` gained an ``args`` field (changing its size and layout), used to hold optional extra encoding and
|
||||
decoding arguments formatted as URI query parameters (separated by ``&``).
|
||||
|
||||
Engine
|
||||
^^^^^^
|
||||
|
||||
@@ -1252,6 +1252,8 @@ typedef struct mjResource_ {
|
||||
mjVFS* vfs; // pointer to the VFS
|
||||
char timestamp[512]; // timestamp of the resource
|
||||
const struct mjpResourceProvider* provider; // pointer to the provider
|
||||
const char* args; // resource arguments/hints, URI query format key=val&...
|
||||
// (optional)
|
||||
} mjResource;
|
||||
typedef struct mjpResourceProvider {
|
||||
const char* prefix; // prefix for match against a resource name
|
||||
|
||||
@@ -30,6 +30,8 @@ typedef struct mjResource_ {
|
||||
mjVFS* vfs; // pointer to the VFS
|
||||
char timestamp[512]; // timestamp of the resource
|
||||
const struct mjpResourceProvider* provider; // pointer to the provider
|
||||
const char* args; // resource arguments/hints, URI query format key=val&...
|
||||
// (optional)
|
||||
} mjResource;
|
||||
|
||||
// callback for opening a resource, returns zero on failure.
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string_view>
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <mujoco/mjmodel.h>
|
||||
@@ -118,5 +122,45 @@ TEST_F(DecoderPluginTest, CanDecode) {
|
||||
mj_deleteSpec(spec);
|
||||
}
|
||||
|
||||
TEST_F(DecoderPluginTest, DecodeWithResourceArgs) {
|
||||
static auto decode_args_fn =
|
||||
+[](mjResource* resource, const mjVFS* vfs) -> mjSpec* {
|
||||
mjSpec* s = MakeSimpleSpec();
|
||||
if (resource && resource->args) {
|
||||
std::string_view args_view(resource->args);
|
||||
size_t pos = args_view.find("size=");
|
||||
if (pos != std::string_view::npos) {
|
||||
mjsElement* elem = mjs_firstElement(s, mjOBJ_GEOM);
|
||||
mjsGeom* geom = mjs_asGeom(elem);
|
||||
if (geom) {
|
||||
geom->size[0] = std::atof(args_view.data() + pos + 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
return s;
|
||||
};
|
||||
|
||||
mjpDecoder decoder;
|
||||
mjp_defaultDecoder(&decoder);
|
||||
decoder.content_type = "model/argsformat";
|
||||
decoder.extension = ".argsformat";
|
||||
decoder.can_decode = +[](const mjResource* r) -> int { return 1; };
|
||||
decoder.decode = decode_args_fn;
|
||||
mjp_registerDecoder(&decoder);
|
||||
|
||||
mjResource resource;
|
||||
std::memset(&resource, 0, sizeof(resource));
|
||||
resource.name = const_cast<char*>("test.argsformat");
|
||||
resource.args = "size=42.0&foo=bar";
|
||||
|
||||
mjSpec* spec = mju_decodeResource(&resource, "model/argsformat", nullptr);
|
||||
ASSERT_THAT(spec, testing::NotNull());
|
||||
mjsElement* elem = mjs_firstElement(spec, mjOBJ_GEOM);
|
||||
mjsGeom* geom = mjs_asGeom(elem);
|
||||
ASSERT_THAT(geom, testing::NotNull());
|
||||
EXPECT_DOUBLE_EQ(geom->size[0], 42.0);
|
||||
mj_deleteSpec(spec);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace mujoco
|
||||
|
||||
@@ -130,5 +130,29 @@ TEST_F(EncoderPluginTest, EncodeModel) {
|
||||
mj_deleteSpec(spec);
|
||||
}
|
||||
|
||||
TEST_F(EncoderPluginTest, EncodeWithResourceArgs) {
|
||||
mjSpec* spec = mj_makeSpec();
|
||||
mjModel* model = mj_compile(spec, nullptr);
|
||||
ASSERT_THAT(model, testing::NotNull());
|
||||
|
||||
const mjpEncoder* found = mjp_findEncoder("output.fakeformat", nullptr);
|
||||
ASSERT_THAT(found, testing::NotNull());
|
||||
|
||||
mjResource resource = {};
|
||||
resource.name = const_cast<char*>("output.fakeformat");
|
||||
resource.args = "format=binary&compression=9";
|
||||
|
||||
int result = found->encode(spec, model, nullptr, &resource);
|
||||
EXPECT_GT(result, 0);
|
||||
|
||||
auto* output = static_cast<FakeEncoderOutput*>(resource.data);
|
||||
ASSERT_THAT(output, testing::NotNull());
|
||||
EXPECT_STREQ(resource.args, "format=binary&compression=9");
|
||||
|
||||
found->close_resource(&resource);
|
||||
mj_deleteModel(model);
|
||||
mj_deleteSpec(spec);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace mujoco
|
||||
|
||||
Reference in New Issue
Block a user