Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion base/cvd/cuttlefish/host/commands/assemble_cvd/flags.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1360,7 +1360,14 @@ Result<CuttlefishConfig> InitializeCuttlefishConfiguration(
CF_EXPECT_EQ(media_configs_bindings.size(), 1,
"Expected a single binding?");
auto media_configs = media_configs_bindings[0]->GetConfigs();
instance.set_media_configs(media_configs);
std::vector<CuttlefishConfig::MediaConfig> instance_media_configs;
for (const auto& config : media_configs) {
if (!config.instance_index.has_value() ||
config.instance_index.value() == instance_index) {
instance_media_configs.push_back(config);
}
}
instance.set_media_configs(instance_media_configs);

instance_index++;
} // end of num_instances loop
Expand Down
7 changes: 7 additions & 0 deletions base/cvd/cuttlefish/host/commands/assemble_cvd/media.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ class MediaConfigsFragmentImpl : public MediaConfigsFragment {
Json::Value json(Json::objectValue);
json[kType] = static_cast<int>(config.type);
json[kLensFacing] = config.lens_facing;
if (config.instance_index.has_value()) {
json[kInstanceIndex] = *config.instance_index;
}
configs_json.append(json);
}
return configs_json;
Expand All @@ -139,6 +142,9 @@ class MediaConfigsFragmentImpl : public MediaConfigsFragment {
if (json.isMember(kLensFacing)) {
config.lens_facing = json[kLensFacing].asString();
}
if (json.isMember(kInstanceIndex)) {
config.instance_index = json[kInstanceIndex].asInt();
}
configs.emplace_back(config);
}

Expand All @@ -150,6 +156,7 @@ class MediaConfigsFragmentImpl : public MediaConfigsFragment {
static constexpr char kMediaConfigs[] = "media_configs";
static constexpr char kType[] = "type";
static constexpr char kLensFacing[] = "lens_facing";
static constexpr char kInstanceIndex[] = "instance_index";
MediaConfigs& configs_;
};

Expand Down
154 changes: 154 additions & 0 deletions base/cvd/cuttlefish/host/commands/cvd/cli/parser/flags_parser_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,160 @@ TEST(FlagsParserTest, ParseMediaV4l2Proxy) {
<< "media flag is missing or wrongly formatted";
}

TEST(FlagsParserTest, ParseMediaV4l2StreamProxy) {
const char* test_string = R""""(
{
"instances" :
[
{
"media": {
"devices": [
{
"v4l2_stream_proxy": {
"input_path": "/tmp/v4l2_fifo",
"input_width": 320,
"input_height": 240,
"input_fps": "10"
},
"lens_facing": "BACK"
}
]
}
}
]
}
)"""";

Json::Value json_configs;
std::string json_text(test_string);
EXPECT_TRUE(ParseJsonString(json_text, json_configs))
<< "Invalid Json string";

auto serialized_data = LaunchCvdParserTester(json_configs);

ASSERT_THAT(serialized_data, IsOk());
EXPECT_TRUE(FindConfig(
*serialized_data,
"--media=v4l2_stream_proxy:input_path=/tmp/v4l2_fifo:input_width=320:input_height=240:input_fps=10:lens_facing=BACK"))
<< "media flag is missing or wrongly formatted";
}

TEST(FlagsParserTest, ParseMediaMultiInstanceSingleMedia) {
const char* test_string = R""""(
{
"instances" :
[
{},
{
"media": {
"devices": [
{
"v4l2_stream_proxy": {
"input_path": "/tmp/v4l2_fifo",
"input_width": 320,
"input_height": 240,
"input_fps": "10"
}
}
]
}
}
]
}
)"""";

Json::Value json_configs;
std::string json_text(test_string);
EXPECT_TRUE(ParseJsonString(json_text, json_configs))
<< "Invalid Json string";

auto serialized_data = LaunchCvdParserTester(json_configs);

ASSERT_THAT(serialized_data, IsOk());
EXPECT_TRUE(FindConfig(
*serialized_data,
"--media=v4l2_stream_proxy:input_path=/tmp/v4l2_fifo:input_width=320:input_height=240:input_fps=10:instance=1"))
<< "media flag is missing or wrongly formatted";
}

TEST(FlagsParserTest, ParseMediaMultiInstanceFirstInstanceMedia) {
const char* test_string = R""""(
{
"instances" :
[
{
"media": {
"devices": [
{
"v4l2_stream_proxy": {
"input_path": "/tmp/v4l2_fifo",
"input_width": 320,
"input_height": 240,
"input_fps": "10"
}
}
]
}
},
{}
]
}
)"""";

Json::Value json_configs;
std::string json_text(test_string);
EXPECT_TRUE(ParseJsonString(json_text, json_configs))
<< "Invalid Json string";

auto serialized_data = LaunchCvdParserTester(json_configs);

ASSERT_THAT(serialized_data, IsOk());
EXPECT_TRUE(FindConfig(
*serialized_data,
"--media=v4l2_stream_proxy:input_path=/tmp/v4l2_fifo:input_width=320:input_height=240:input_fps=10:instance=0"))
<< "media flag is missing or wrongly formatted";
}

TEST(FlagsParserTest, ParseMediaMultiInstanceMultipleMediaFails) {
const char* test_string = R""""(
{
"instances" :
[
{
"media": {
"devices": [
{
"v4l2_stream_proxy": {
"input_path": "/tmp/v4l2_fifo_1"
}
}
]
}
},
{
"media": {
"devices": [
{
"v4l2_stream_proxy": {
"input_path": "/tmp/v4l2_fifo_2"
}
}
]
}
}
]
}
)"""";

Json::Value json_configs;
std::string json_text(test_string);
EXPECT_TRUE(ParseJsonString(json_text, json_configs))
<< "Invalid Json string";

auto serialized_data = LaunchCvdParserTester(json_configs);
EXPECT_FALSE(serialized_data.has_value());
}

TEST(ConnectivityFlagsParserTest, ParseModemSimulatorSimTypeValidInt) {
const char* test_string = R""""(
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,11 @@ Result<std::vector<std::string>> GenerateMediaFlags(
int has_media_count =
std::count_if(cfg.instances().rbegin(), cfg.instances().rend(),
[](const auto& v) { return v.has_media(); });
CF_EXPECT(has_media_count == 0 || cfg.instances().size() == 1,
CF_EXPECT(has_media_count <= 1,
"TODO(b/520098369): support media devices for multiple instances");
std::vector<std::string> flags;
for (const auto& instance : cfg.instances()) {
for (size_t i = 0; i < cfg.instances().size(); ++i) {
const auto& instance = cfg.instances(i);
if (instance.has_media()) {
for (const auto& device : instance.media().devices()) {
std::string flag = "--media=";
Expand All @@ -63,6 +64,9 @@ Result<std::vector<std::string>> GenerateMediaFlags(
if (device.has_lens_facing()) {
flag += ":lens_facing=" + device.lens_facing();
}
if (cfg.instances().size() > 1) {
flag += ":instance=" + std::to_string(i);
}
flags.push_back(flag);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ class VhostUserMediaDevices : public CommandSource {
CF_EXPECT(config.v4l2_stream_proxy.has_value(),
"Missing v4l2_stream_proxy config");
binary_path = VhostUserMediaV4l2StreamProxyBinary();
cmd.emplace(
NewCommand(binary_path, instance_.media_socket_path(index), ""));
cmd.emplace(NewCommand(binary_path, instance_.media_socket_path(index),
config.lens_facing));
cmd->AddParameter("--input_path=",
config.v4l2_stream_proxy->input_path);
cmd->AddParameter(
Expand Down
1 change: 1 addition & 0 deletions base/cvd/cuttlefish/host/libs/config/cuttlefish_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ class CuttlefishConfig {
struct MediaConfig {
MediaType type;
std::string lens_facing;
std::optional<int> instance_index;

struct V4l2StreamProxyConfig {
std::string input_path;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2001,6 +2001,7 @@ static constexpr char kMediaInputPath[] = "input_path";
static constexpr char kMediaInputWidth[] = "input_width";
static constexpr char kMediaInputHeight[] = "input_height";
static constexpr char kMediaInputFps[] = "input_fps";
static constexpr char kMediaInstanceIndex[] = "instance_index";

std::vector<CuttlefishConfig::MediaConfig>
CuttlefishConfig::InstanceSpecific::media_configs() const {
Expand All @@ -2012,6 +2013,9 @@ CuttlefishConfig::InstanceSpecific::media_configs() const {
if (json.isMember(kMediaLensFacing)) {
config.lens_facing = json[kMediaLensFacing].asString();
}
if (json.isMember(kMediaInstanceIndex)) {
config.instance_index = json[kMediaInstanceIndex].asInt();
}
if (config.type == CuttlefishConfig::MediaType::kV4l2StreamProxy) {
CuttlefishConfig::MediaConfig::V4l2StreamProxyConfig stream_config = {};
if (json.isMember(kMediaInputPath)) {
Expand Down Expand Up @@ -2041,6 +2045,9 @@ void CuttlefishConfig::MutableInstanceSpecific::set_media_configs(
Json::Value json(Json::objectValue);
json[kMediaType] = static_cast<int>(config.type);
json[kMediaLensFacing] = config.lens_facing;
if (config.instance_index.has_value()) {
json[kMediaInstanceIndex] = *config.instance_index;
}
if (config.type == CuttlefishConfig::MediaType::kV4l2StreamProxy &&
config.v4l2_stream_proxy.has_value()) {
json[kMediaInputPath] = config.v4l2_stream_proxy->input_path;
Expand Down
15 changes: 15 additions & 0 deletions base/cvd/cuttlefish/host/libs/config/media.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,16 @@ Result<std::optional<CuttlefishConfig::MediaConfig>> ParseMediaConfig(
"Invalid lens_facing value: " << lens_facing);
}

std::optional<int> instance_index;
auto instance_it = props.find("instance");
if (instance_it != props.end()) {
int idx = 0;
CF_EXPECT(android::base::ParseInt(instance_it->second, &idx),
"Failed to parse instance index: " << instance_it->second);
CF_EXPECT(idx >= 0, "instance index must be non-negative: " << idx);
instance_index = idx;
}

std::optional<CuttlefishConfig::MediaConfig::V4l2StreamProxyConfig>
v4l2_stream_proxy;
if (type == CuttlefishConfig::MediaType::kV4l2StreamProxy) {
Expand All @@ -87,6 +97,8 @@ Result<std::optional<CuttlefishConfig::MediaConfig>> ParseMediaConfig(
auto source_it = props.find("input_path");
CF_EXPECT(source_it != props.end(),
"Missing 'input_path' for v4l2_stream_proxy");
CF_EXPECT(!source_it->second.empty(),
"'input_path' must not be empty for v4l2_stream_proxy");
stream_config.input_path = source_it->second;

auto width_it = props.find("input_width");
Expand All @@ -110,6 +122,8 @@ Result<std::optional<CuttlefishConfig::MediaConfig>> ParseMediaConfig(
auto fps_it = props.find("input_fps");
CF_EXPECT(fps_it != props.end(),
"Missing 'input_fps' for v4l2_stream_proxy");
CF_EXPECT(!fps_it->second.empty(),
"'input_fps' must not be empty for v4l2_stream_proxy");
stream_config.input_fps = fps_it->second;

v4l2_stream_proxy = stream_config;
Expand All @@ -118,6 +132,7 @@ Result<std::optional<CuttlefishConfig::MediaConfig>> ParseMediaConfig(
return CuttlefishConfig::MediaConfig{
.type = type,
.lens_facing = lens_facing,
.instance_index = instance_index,
.v4l2_stream_proxy = v4l2_stream_proxy,
};
}
Expand Down
3 changes: 2 additions & 1 deletion base/cvd/cuttlefish/host/libs/config/media.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ constexpr const char kMediaHelp[] =
" 'input_fps': frames per second (e.g., 30 or 30000/1001)\n\n"
"Supported keys:\n"
" 'lens_facing': optional, supported values: 'FRONT', 'BACK', "
"'EXTERNAL'\n\n"
"'EXTERNAL'\n"
" 'instance': optional, zero-based instance index to attach device to\n\n"
"Example usage:\n"
" --media=v4l2_emulated_camera_mplane:lens_facing=BACK\n"
" --media=v4l2_stream_proxy:input_path=/tmp/fifo:"
Expand Down