Project import generated by Copybara.

GitOrigin-RevId: 373e3ac1e5839befd95bf7d73ceff3c5f1171969
This commit is contained in:
MediaPipe Team
2021-10-06 14:27:49 -07:00
committed by jqtang
parent 137e1cc763
commit 33d683c671
153 changed files with 7871 additions and 1349 deletions
@@ -23,6 +23,7 @@
#if !MEDIAPIPE_DISABLE_GPU
#ifdef __APPLE__
#include "mediapipe/objc/CFHolder.h"
#include "mediapipe/objc/util.h"
#endif // __APPLE__
#endif // !MEDIAPIPE_DISABLE_GPU
+12
View File
@@ -89,6 +89,18 @@ cc_library(
],
)
cc_library(
name = "commandlineflags",
hdrs = [
"commandlineflags.h",
],
visibility = ["//visibility:public"],
deps = [
"//third_party:glog",
"@com_google_absl//absl/flags:flag",
],
)
cc_library(
name = "core_proto",
hdrs = [
@@ -0,0 +1,30 @@
// Copyright 2019 The MediaPipe Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef MEDIAPIPE_PORT_COMMANDLINEFLAGS_H_
#define MEDIAPIPE_PORT_COMMANDLINEFLAGS_H_
#include "gflags/gflags.h"
namespace absl {
template <typename T>
T GetFlag(const T& f) {
return f;
}
template <typename T, typename U>
void SetFlag(T* f, const U& u) {
*f = u;
}
} // namespace absl
#endif // MEDIAPIPE_PORT_COMMANDLINEFLAGS_H_
+4 -1
View File
@@ -202,6 +202,7 @@ cc_library(
"//mediapipe/framework:packet_type",
"//mediapipe/framework/port:advanced_proto",
"//mediapipe/framework/port:any_proto",
"//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings",
@@ -291,7 +292,9 @@ mediapipe_cc_test(
data = [":node_chain_subgraph.proto"],
requires_full_emulation = False,
deps = [
":options_field_util",
":options_registry",
":options_syntax_util",
":options_util",
"//mediapipe/calculators/core:flow_limiter_calculator",
"//mediapipe/calculators/core:flow_limiter_calculator_cc_proto",
@@ -305,8 +308,8 @@ mediapipe_cc_test(
"//mediapipe/framework/port:status",
"//mediapipe/framework/testdata:night_light_calculator_options_lib",
"//mediapipe/framework/tool:node_chain_subgraph_options_lib",
"//mediapipe/framework/tool:options_syntax_util",
"//mediapipe/util:header_util",
"@com_google_absl//absl/strings",
],
)
+298 -95
View File
@@ -8,11 +8,13 @@
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "mediapipe/framework/packet.h"
#include "mediapipe/framework/packet_type.h"
#include "mediapipe/framework/port/advanced_proto_inc.h"
#include "mediapipe/framework/port/any_proto.h"
#include "mediapipe/framework/port/canonical_errors.h"
#include "mediapipe/framework/port/ret_check.h"
#include "mediapipe/framework/port/status.h"
#include "mediapipe/framework/tool/name_util.h"
#include "mediapipe/framework/tool/proto_util_lite.h"
@@ -31,6 +33,9 @@ using ::mediapipe::proto_ns::io::StringOutputStream;
// Utility functions for OptionsFieldUtil.
namespace {
// The type name for the proto3 "Any" type.
constexpr absl::string_view kGoogleProtobufAny = "google.protobuf.Any";
// Converts a FieldDescriptor::Type to the corresponding FieldType.
FieldType AsFieldType(proto_ns::FieldDescriptorProto::Type type) {
return static_cast<FieldType>(type);
@@ -81,7 +86,7 @@ absl::Status WriteValue(const FieldData& value, FieldType field_type,
return absl::UnimplementedError(
absl::StrCat("Cannot write type: ", field_type));
}
return mediapipe::OkStatus();
return absl::OkStatus();
}
// Serializes a packet value.
@@ -167,6 +172,7 @@ absl::Status ReadValue(absl::string_view field_bytes, FieldType field_type,
// Deserializes a packet from a protobuf field.
absl::Status ReadField(absl::string_view bytes, const FieldDescriptor* field,
FieldData* result) {
RET_CHECK_NE(field, nullptr);
FieldType field_type = AsFieldType(field->type());
std::string message_type = (field_type == WireFormatLite::TYPE_MESSAGE)
? field->message_type()->full_name()
@@ -174,47 +180,137 @@ absl::Status ReadField(absl::string_view bytes, const FieldDescriptor* field,
return ReadValue(bytes, field_type, message_type, result);
}
// Converts a chain of fields and indexes into field-numbers and indexes.
ProtoUtilLite::ProtoPath AsProtoPath(const FieldPath& field_path) {
ProtoUtilLite::ProtoPath result;
for (auto field : field_path) {
result.push_back({field.first->number(), field.second});
// Reads all values from a repeated field.
absl::Status GetFieldValues(const FieldData& message_data,
const FieldDescriptor& field,
std::vector<FieldData>* result) {
const std::string& message_bytes = message_data.message_value().value();
FieldType field_type = AsFieldType(field.type());
ProtoUtilLite proto_util;
ProtoUtilLite::ProtoPath proto_path = {{field.number(), 0}};
int count;
MP_RETURN_IF_ERROR(
proto_util.GetFieldCount(message_bytes, proto_path, field_type, &count));
std::vector<std::string> field_values;
MP_RETURN_IF_ERROR(proto_util.GetFieldRange(message_bytes, proto_path, count,
field_type, &field_values));
for (int i = 0; i < count; ++i) {
FieldData r;
MP_RETURN_IF_ERROR(ReadField(field_values[i], &field, &r));
result->push_back(std::move(r));
}
return absl::OkStatus();
}
// Reads one value from a field.
absl::Status GetFieldValue(const FieldData& message_data,
const FieldPathEntry& entry, FieldData* result) {
RET_CHECK_NE(entry.field, nullptr);
const std::string& message_bytes = message_data.message_value().value();
FieldType field_type = AsFieldType(entry.field->type());
ProtoUtilLite proto_util;
ProtoUtilLite::ProtoPath proto_path = {{entry.field->number(), entry.index}};
std::vector<std::string> field_values;
MP_RETURN_IF_ERROR(proto_util.GetFieldRange(message_bytes, proto_path, 1,
field_type, &field_values));
MP_RETURN_IF_ERROR(ReadField(field_values[0], entry.field, result));
return absl::OkStatus();
}
// Writes one value to a field.
absl::Status SetFieldValue(const FieldPathEntry& entry, const FieldData& value,
FieldData* result) {
std::vector<FieldData> field_values;
ProtoUtilLite proto_util;
FieldType field_type = AsFieldType(entry.field->type());
ProtoUtilLite::ProtoPath proto_path = {{entry.field->number(), entry.index}};
std::string* message_bytes = result->mutable_message_value()->mutable_value();
int field_count;
MP_RETURN_IF_ERROR(proto_util.GetFieldCount(*message_bytes, proto_path,
field_type, &field_count));
if (entry.index > field_count) {
return absl::OutOfRangeError(
absl::StrCat("Option field index out of range: ", entry.index));
}
int replace_length = entry.index < field_count ? 1 : 0;
std::string field_value;
MP_RETURN_IF_ERROR(WriteField(value, entry.field, &field_value));
MP_RETURN_IF_ERROR(proto_util.ReplaceFieldRange(
message_bytes, proto_path, replace_length, field_type, {field_value}));
return absl::OkStatus();
}
// Returns true for a field of type "google.protobuf.Any".
bool IsProtobufAny(const FieldDescriptor* field) {
return AsFieldType(field->type()) == FieldType::TYPE_MESSAGE &&
field->message_type()->full_name() == kGoogleProtobufAny;
}
// Returns the message FieldData from a serialized protobuf.Any.
FieldData ParseProtobufAny(const FieldData& data) {
protobuf::Any any;
any.ParseFromString(data.message_value().value());
FieldData result;
result.mutable_message_value()->set_value(std::string(any.value()));
result.mutable_message_value()->set_type_url(any.type_url());
return result;
}
// Returns the options protobuf for a subgraph.
// TODO: Ensure that this works with multiple options protobufs.
absl::Status GetOptionsMessage(
const proto_ns::RepeatedPtrField<mediapipe::protobuf::Any>& options_any,
const proto_ns::MessageLite& options_ext, FieldData* result) {
// Read the "graph_options" or "node_options" field.
for (const auto& options : options_any) {
if (options.type_url().empty()) {
continue;
}
result->mutable_message_value()->set_type_url(options.type_url());
result->mutable_message_value()->set_value(std::string(options.value()));
return mediapipe::OkStatus();
}
// Returns the serialized protobuf.Any containing a message FieldData.
FieldData SerializeProtobufAny(const FieldData& data) {
protobuf::Any any;
any.set_value(data.message_value().value());
any.set_type_url(data.message_value().type_url());
FieldData result;
result.mutable_message_value()->set_value(any.SerializeAsString());
result.mutable_message_value()->set_type_url(TypeUrl(kGoogleProtobufAny));
return result;
}
// Read the "options" field.
FieldData message_data;
*message_data.mutable_message_value()->mutable_value() =
options_ext.SerializeAsString();
message_data.mutable_message_value()->set_type_url(options_ext.GetTypeName());
std::vector<const FieldDescriptor*> ext_fields;
OptionsRegistry::FindAllExtensions(options_ext.GetTypeName(), &ext_fields);
for (auto ext_field : ext_fields) {
absl::Status status = GetField({{ext_field, 0}}, message_data, result);
if (!status.ok()) {
return status;
}
if (result->has_message_value()) {
return status;
// Returns the field index of an extension type in a repeated field.
StatusOr<int> FindExtensionIndex(const FieldData& message_data,
FieldPathEntry* entry) {
if (entry->field == nullptr || !IsProtobufAny(entry->field)) {
return -1;
}
std::string& extension_type = entry->extension_type;
std::vector<FieldData> field_values;
RET_CHECK_NE(entry->field, nullptr);
MP_RETURN_IF_ERROR(
GetFieldValues(message_data, *entry->field, &field_values));
for (int i = 0; i < field_values.size(); ++i) {
FieldData extension = ParseProtobufAny(field_values[i]);
if (extension_type == "*" ||
ParseTypeUrl(extension.message_value().type_url()) == extension_type) {
return i;
}
}
return mediapipe::OkStatus();
return -1;
}
// Returns true if the value of a field is available.
bool HasField(const FieldPath& field_path, const FieldData& message_data) {
FieldData value;
return GetField(field_path, message_data, &value).ok() &&
value.value_case() != mediapipe::FieldData::VALUE_NOT_SET;
}
// Returns the extension field containing the specified extension-type.
const FieldDescriptor* FindExtensionField(const FieldData& message_data,
absl::string_view extension_type) {
std::string message_type =
ParseTypeUrl(message_data.message_value().type_url());
std::vector<const FieldDescriptor*> extensions;
OptionsRegistry::FindAllExtensions(message_type, &extensions);
for (const FieldDescriptor* extension : extensions) {
if (extension->message_type()->full_name() == extension_type) {
return extension;
}
if (extension_type == "*" && HasField({{extension, 0}}, message_data)) {
return extension;
}
}
return nullptr;
}
// Sets a protobuf in a repeated protobuf::Any field.
@@ -234,6 +330,20 @@ void SetOptionsMessage(
*options_any->mutable_value() = node_options.message_value().value();
}
// Returns the count of values in a repeated field.
int FieldCount(const FieldData& message_data, const FieldDescriptor* field) {
const std::string& message_bytes = message_data.message_value().value();
FieldType field_type = AsFieldType(field->type());
ProtoUtilLite proto_util;
ProtoUtilLite::ProtoPath proto_path = {{field->number(), 0}};
int count;
if (proto_util.GetFieldCount(message_bytes, proto_path, field_type, &count)
.ok()) {
return count;
}
return 0;
}
} // anonymous namespace
// Deserializes a packet containing a MessageLite value.
@@ -247,8 +357,8 @@ absl::Status ReadMessage(const std::string& value, const std::string& type_name,
}
// Merge two options FieldData values.
absl::Status MergeOptionsMessages(const FieldData& base, const FieldData& over,
FieldData* result) {
absl::Status MergeMessages(const FieldData& base, const FieldData& over,
FieldData* result) {
absl::Status status;
if (over.value_case() == FieldData::VALUE_NOT_SET) {
*result = base;
@@ -278,28 +388,148 @@ absl::Status MergeOptionsMessages(const FieldData& base, const FieldData& over,
return status;
}
// Returns either the extension field or the repeated protobuf.Any field index
// holding the specified extension-type.
absl::Status FindExtension(const FieldData& message_data,
FieldPathEntry* entry) {
if (entry->extension_type.empty()) {
return absl::OkStatus();
}
// For repeated protobuf::Any, find the index for the extension_type.
ASSIGN_OR_RETURN(int index, FindExtensionIndex(message_data, entry));
if (index != -1) {
entry->index = index;
return absl::OkStatus();
}
// Returns the extension field containing the specified extension-type.
std::string& extension_type = entry->extension_type;
const FieldDescriptor* field =
FindExtensionField(message_data, extension_type);
if (field != nullptr) {
entry->field = field;
entry->index = 0;
return absl::OkStatus();
}
return absl::NotFoundError(
absl::StrCat("Option extension not found: ", extension_type));
}
// Return the FieldPath referencing an extension message.
FieldPath GetExtensionPath(const std::string& parent_type,
const std::string& extension_type,
const std::string& field_name,
bool is_protobuf_any) {
FieldPath result;
const tool::Descriptor* parent_descriptor =
tool::OptionsRegistry::GetProtobufDescriptor(parent_type);
FieldPathEntry field_entry;
field_entry.field = parent_descriptor->FindFieldByName(field_name);
if (is_protobuf_any) {
field_entry.extension_type = extension_type;
result = {std::move(field_entry)};
} else {
field_entry.index = 0;
FieldPathEntry extension_entry;
extension_entry.extension_type = extension_type;
result = {std::move(field_entry), std::move(extension_entry)};
}
return result;
}
// Returns the requested options protobuf for a graph node.
absl::Status GetNodeOptions(const FieldData& message_data,
const std::string& extension_type,
FieldData* result) {
constexpr char kOptionsName[] = "options";
constexpr char kNodeOptionsName[] = "node_options";
std::string parent_type = options_field_util::ParseTypeUrl(
std::string(message_data.message_value().type_url()));
FieldPath path;
Status status;
path = GetExtensionPath(parent_type, extension_type, kOptionsName, false);
status = GetField(path, message_data, result);
if (status.ok()) {
return status;
}
path = GetExtensionPath(parent_type, extension_type, kNodeOptionsName, true);
status = GetField(path, message_data, result);
return status;
}
// Returns the requested options protobuf for a graph.
absl::Status GetGraphOptions(const FieldData& message_data,
const std::string& extension_type,
FieldData* result) {
constexpr char kOptionsName[] = "options";
constexpr char kGraphOptionsName[] = "graph_options";
std::string parent_type = options_field_util::ParseTypeUrl(
std::string(message_data.message_value().type_url()));
FieldPath path;
Status status;
path = GetExtensionPath(parent_type, extension_type, kOptionsName, false);
status = GetField(path, message_data, result);
if (status.ok()) {
return status;
}
path = GetExtensionPath(parent_type, extension_type, kGraphOptionsName, true);
status = GetField(path, message_data, result);
return status;
}
// Reads a FieldData value from a protobuf field.
absl::Status GetField(const FieldPath& field_path,
const FieldData& message_data, FieldData* result) {
if (field_path.empty()) {
*result->mutable_message_value() = message_data.message_value();
return absl::OkStatus();
}
FieldPathEntry head = field_path.front();
FieldPath tail = field_path;
tail.erase(tail.begin());
if (!head.extension_type.empty()) {
MP_RETURN_IF_ERROR(FindExtension(message_data, &head));
}
if (tail.empty() && FieldCount(message_data, head.field) == 0) {
return absl::OkStatus();
}
MP_RETURN_IF_ERROR(GetFieldValue(message_data, head, result));
if (IsProtobufAny(head.field)) {
*result = ParseProtobufAny(*result);
}
if (!tail.empty()) {
FieldData child = *result;
MP_RETURN_IF_ERROR(GetField(tail, child, result));
}
return absl::OkStatus();
}
// Writes a FieldData value into protobuf field.
absl::Status SetField(const FieldPath& field_path, const FieldData& value,
FieldData* message_data) {
if (field_path.empty()) {
*message_data->mutable_message_value() = value.message_value();
return mediapipe::OkStatus();
return absl::OkStatus();
}
ProtoUtilLite proto_util;
const FieldDescriptor* field = field_path.back().first;
FieldType field_type = AsFieldType(field->type());
std::string field_value;
MP_RETURN_IF_ERROR(WriteField(value, field, &field_value));
ProtoUtilLite::ProtoPath proto_path = AsProtoPath(field_path);
std::string* message_bytes =
message_data->mutable_message_value()->mutable_value();
int field_count;
MP_RETURN_IF_ERROR(proto_util.GetFieldCount(*message_bytes, proto_path,
field_type, &field_count));
MP_RETURN_IF_ERROR(
proto_util.ReplaceFieldRange(message_bytes, AsProtoPath(field_path),
field_count, field_type, {field_value}));
return mediapipe::OkStatus();
FieldPathEntry head = field_path.front();
FieldPath tail = field_path;
tail.erase(tail.begin());
if (!head.extension_type.empty()) {
MP_RETURN_IF_ERROR(FindExtension(*message_data, &head));
}
if (tail.empty()) {
MP_RETURN_IF_ERROR(SetFieldValue(head, value, message_data));
} else {
FieldData child;
MP_RETURN_IF_ERROR(GetFieldValue(*message_data, head, &child));
MP_RETURN_IF_ERROR(SetField(tail, value, &child));
if (IsProtobufAny(head.field)) {
child = SerializeProtobufAny(child);
}
MP_RETURN_IF_ERROR(SetFieldValue(head, child, message_data));
}
return absl::OkStatus();
}
// Merges a packet value into nested protobuf Message.
@@ -308,7 +538,7 @@ absl::Status MergeField(const FieldPath& field_path, const FieldData& value,
absl::Status status;
FieldType field_type = field_path.empty()
? FieldType::TYPE_MESSAGE
: AsFieldType(field_path.back().first->type());
: AsFieldType(field_path.back().field->type());
std::string message_type =
(value.has_message_value())
? ParseTypeUrl(std::string(value.message_value().type_url()))
@@ -317,49 +547,12 @@ absl::Status MergeField(const FieldPath& field_path, const FieldData& value,
if (field_type == FieldType::TYPE_MESSAGE) {
FieldData b;
status.Update(GetField(field_path, *message_data, &b));
status.Update(MergeOptionsMessages(b, v, &v));
status.Update(MergeMessages(b, v, &v));
}
status.Update(SetField(field_path, v, message_data));
return status;
}
// Reads a packet value from a protobuf field.
absl::Status GetField(const FieldPath& field_path,
const FieldData& message_data, FieldData* result) {
if (field_path.empty()) {
*result->mutable_message_value() = message_data.message_value();
return mediapipe::OkStatus();
}
ProtoUtilLite proto_util;
const FieldDescriptor* field = field_path.back().first;
FieldType field_type = AsFieldType(field->type());
std::vector<std::string> field_values;
ProtoUtilLite::ProtoPath proto_path = AsProtoPath(field_path);
const std::string& message_bytes = message_data.message_value().value();
int field_count;
MP_RETURN_IF_ERROR(proto_util.GetFieldCount(message_bytes, proto_path,
field_type, &field_count));
if (field_count == 0) {
return mediapipe::OkStatus();
}
MP_RETURN_IF_ERROR(proto_util.GetFieldRange(message_bytes, proto_path, 1,
field_type, &field_values));
MP_RETURN_IF_ERROR(ReadField(field_values.front(), field, result));
return mediapipe::OkStatus();
}
// Returns the options protobuf for a graph.
absl::Status GetOptionsMessage(const CalculatorGraphConfig& config,
FieldData* result) {
return GetOptionsMessage(config.graph_options(), config.options(), result);
}
// Returns the options protobuf for a node.
absl::Status GetOptionsMessage(const CalculatorGraphConfig::Node& node,
FieldData* result) {
return GetOptionsMessage(node.node_options(), node.options(), result);
}
// Sets the node_options field in a Node, and clears the options field.
void SetOptionsMessage(const FieldData& node_options,
CalculatorGraphConfig::Node* node) {
@@ -367,6 +560,16 @@ void SetOptionsMessage(const FieldData& node_options,
node->clear_options();
}
// Serialize a MessageLite to a FieldData.
FieldData AsFieldData(const proto_ns::MessageLite& message) {
FieldData result;
*result.mutable_message_value()->mutable_value() =
message.SerializePartialAsString();
*result.mutable_message_value()->mutable_type_url() =
TypeUrl(message.GetTypeName());
return result;
}
// Represents a protobuf enum value stored in a Packet.
struct ProtoEnum {
ProtoEnum(int32 v) : value(v) {}
@@ -415,7 +618,7 @@ absl::Status AsPacket(const FieldData& data, Packet* result) {
case FieldData::VALUE_NOT_SET:
*result = Packet();
}
return mediapipe::OkStatus();
return absl::OkStatus();
}
absl::Status AsFieldData(Packet packet, FieldData* result) {
@@ -436,7 +639,7 @@ absl::Status AsFieldData(Packet packet, FieldData* result) {
packet.GetProtoMessageLite().SerializeAsString());
result->mutable_message_value()->set_type_url(
TypeUrl(packet.GetProtoMessageLite().GetTypeName()));
return mediapipe::OkStatus();
return absl::OkStatus();
}
if (kTypeIds->count(packet.GetTypeId()) == 0) {
@@ -473,7 +676,7 @@ absl::Status AsFieldData(Packet packet, FieldData* result) {
result->set_string_value(packet.Get<std::string>());
break;
}
return mediapipe::OkStatus();
return absl::OkStatus();
}
std::string TypeUrl(absl::string_view type_name) {
+22 -10
View File
@@ -19,8 +19,15 @@ namespace tool {
// Utility to read and write Packet data from protobuf fields.
namespace options_field_util {
// A chain of nested fields and indexes.
using FieldPath = std::vector<std::pair<const FieldDescriptor*, int>>;
// A protobuf field and index description.
struct FieldPathEntry {
const FieldDescriptor* field = nullptr;
int index = -1;
std::string extension_type;
};
// A chain of nested protobuf fields and indexes.
using FieldPath = std::vector<FieldPathEntry>;
// Writes a field value into protobuf field.
absl::Status SetField(const FieldPath& field_path, const FieldData& value,
@@ -39,21 +46,26 @@ absl::Status ReadMessage(const std::string& value, const std::string& type_name,
Packet* result);
// Merge two options protobuf field values.
absl::Status MergeOptionsMessages(const FieldData& base, const FieldData& over,
FieldData* result);
absl::Status MergeMessages(const FieldData& base, const FieldData& over,
FieldData* result);
// Returns the options protobuf for a graph.
absl::Status GetOptionsMessage(const CalculatorGraphConfig& config,
FieldData* result);
// Returns the requested options protobuf for a graph.
absl::Status GetNodeOptions(const FieldData& message_data,
const std::string& extension_type,
FieldData* result);
// Returns the options protobuf for a node.
absl::Status GetOptionsMessage(const CalculatorGraphConfig::Node& node,
FieldData* result);
// Returns the requested options protobuf for a graph node.
absl::Status GetGraphOptions(const FieldData& message_data,
const std::string& extension_type,
FieldData* result);
// Sets the node_options field in a Node, and clears the options field.
void SetOptionsMessage(const FieldData& node_options,
CalculatorGraphConfig::Node* node);
// Serialize a MessageLite to a FieldData.
FieldData AsFieldData(const proto_ns::MessageLite& message);
// Constructs a Packet for a FieldData proto.
absl::Status AsPacket(const FieldData& data, Packet* result);
+65 -10
View File
@@ -5,17 +5,42 @@
#include <tuple>
#include <vector>
#include "absl/strings/match.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "mediapipe/framework/packet.h"
#include "mediapipe/framework/packet_type.h"
#include "mediapipe/framework/port/advanced_proto_inc.h"
#include "mediapipe/framework/port/any_proto.h"
#include "mediapipe/framework/port/status.h"
#include "mediapipe/framework/tool/name_util.h"
#include "mediapipe/framework/tool/options_registry.h"
namespace mediapipe {
namespace tool {
namespace {
// StrSplit Delimiter to split strings at single colon tokens, ignoring
// double-colon tokens.
class SingleColonDelimiter {
public:
SingleColonDelimiter() {}
absl::string_view Find(absl::string_view text, size_t pos) const {
while (pos < text.length()) {
size_t p = text.find(':', pos);
p = (p == absl::string_view::npos) ? text.length() : p;
if (p >= text.length() - 1 || text[p + 1] != ':') {
return text.substr(p, 1);
}
pos = p + 2;
}
return text.substr(text.length(), 0);
}
};
} // namespace
// Helper functions for parsing the graph options syntax.
class OptionsSyntaxUtil::OptionsSyntaxHelper {
public:
@@ -31,13 +56,32 @@ class OptionsSyntaxUtil::OptionsSyntaxHelper {
// Returns the option protobuf field name for a tag or packet name.
absl::string_view OptionFieldName(absl::string_view name) { return name; }
// Return the extension-type specified for an option field.
absl::string_view ExtensionType(absl::string_view option_name) {
constexpr absl::string_view kExt = "Ext::";
if (absl::StartsWithIgnoreCase(option_name, kExt)) {
return option_name.substr(kExt.size());
}
return "";
}
// Returns the field names encoded in an options tag.
std::vector<absl::string_view> OptionTagNames(absl::string_view tag) {
if (absl::StartsWith(tag, syntax_.tag_name)) {
tag = tag.substr(syntax_.tag_name.length());
} else if (absl::StartsWith(tag, syntax_.packet_name)) {
tag = tag.substr(syntax_.packet_name.length());
}
if (absl::StartsWith(tag, syntax_.separator)) {
tag = tag.substr(syntax_.separator.length());
}
return absl::StrSplit(tag, syntax_.separator);
}
// Returns the field-path for an option stream-tag.
FieldPath OptionFieldPath(const std::string& tag,
FieldPath OptionFieldPath(absl::string_view tag,
const Descriptor* descriptor) {
int prefix = syntax_.tag_name.length() + syntax_.separator.length();
std::string suffix = tag.substr(prefix);
std::vector<absl::string_view> name_tags =
absl::StrSplit(suffix, syntax_.separator);
std::vector<absl::string_view> name_tags = OptionTagNames(tag);
FieldPath result;
for (absl::string_view name_tag : name_tags) {
if (name_tag.empty()) {
@@ -46,8 +90,16 @@ class OptionsSyntaxUtil::OptionsSyntaxHelper {
absl::string_view option_name = OptionFieldName(name_tag);
int index;
if (absl::SimpleAtoi(option_name, &index)) {
result.back().second = index;
result.back().index = index;
}
if (!ExtensionType(option_name).empty()) {
std::string extension_type = std::string(ExtensionType(option_name));
result.push_back({nullptr, 0, extension_type});
descriptor = OptionsRegistry::GetProtobufDescriptor(extension_type);
} else {
if (descriptor == nullptr) {
break;
}
auto field = descriptor->FindFieldByName(std::string(option_name));
descriptor = field ? field->message_type() : nullptr;
result.push_back({std::move(field), 0});
@@ -78,7 +130,7 @@ class OptionsSyntaxUtil::OptionsSyntaxHelper {
}
// Converts slash-separated field names into a tag name.
std::string OptionFieldsTag(const std::string& option_names) {
std::string OptionFieldsTag(absl::string_view option_names) {
std::string tag_prefix = syntax_.tag_name + syntax_.separator;
std::vector<absl::string_view> names = absl::StrSplit(option_names, '/');
if (!names.empty() && names[0] == syntax_.tag_name) {
@@ -129,15 +181,18 @@ OptionsSyntaxUtil::OptionsSyntaxUtil(const std::string& tag_name,
OptionsSyntaxUtil::~OptionsSyntaxUtil() {}
std::string OptionsSyntaxUtil::OptionFieldsTag(
const std::string& option_names) {
std::string OptionsSyntaxUtil::OptionFieldsTag(absl::string_view option_names) {
return syntax_helper_->OptionFieldsTag(option_names);
}
OptionsSyntaxUtil::FieldPath OptionsSyntaxUtil::OptionFieldPath(
const std::string& tag, const Descriptor* descriptor) {
absl::string_view tag, const Descriptor* descriptor) {
return syntax_helper_->OptionFieldPath(tag, descriptor);
}
std::vector<absl::string_view> OptionsSyntaxUtil::StrSplitTags(
absl::string_view tag_and_name) {
return absl::StrSplit(tag_and_name, SingleColonDelimiter());
}
} // namespace tool
} // namespace mediapipe
@@ -28,12 +28,15 @@ class OptionsSyntaxUtil {
~OptionsSyntaxUtil();
// Converts slash-separated field names into a tag name.
std::string OptionFieldsTag(const std::string& option_names);
std::string OptionFieldsTag(absl::string_view option_names);
// Returns the field-path for an option stream-tag.
FieldPath OptionFieldPath(const std::string& tag,
FieldPath OptionFieldPath(absl::string_view tag,
const Descriptor* descriptor);
// Splits a std::string into "tag" and "name" delimited by a single colon.
std::vector<absl::string_view> StrSplitTags(absl::string_view tag_and_name);
private:
class OptionsSyntaxHelper;
std::unique_ptr<OptionsSyntaxHelper> syntax_helper_;
+60 -32
View File
@@ -7,6 +7,7 @@
#include "absl/strings/ascii.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "mediapipe/framework/calculator_context.h"
#include "mediapipe/framework/input_stream_shard.h"
#include "mediapipe/framework/output_side_packet.h"
@@ -24,50 +25,77 @@
namespace mediapipe {
namespace tool {
using options_field_util::FieldPath;
using options_field_util::GetField;
using options_field_util::GetGraphOptions;
using options_field_util::GetNodeOptions;
using options_field_util::MergeField;
using options_field_util::MergeMessages;
// Returns the type for the root options message if specified.
std::string ExtensionType(const std::string& option_fields_tag) {
OptionsSyntaxUtil syntax_util;
options_field_util::FieldPath field_path =
syntax_util.OptionFieldPath(option_fields_tag, nullptr);
std::string result = !field_path.empty() ? field_path[0].extension_type : "";
return !result.empty() ? result : "*";
}
// Constructs a FieldPath for field names starting at a message type.
FieldPath GetPath(const std::string& path_tag,
const std::string& message_type) {
OptionsSyntaxUtil syntax_util;
const Descriptor* descriptor =
OptionsRegistry::GetProtobufDescriptor(message_type);
return syntax_util.OptionFieldPath(path_tag, descriptor);
}
// Returns the message type for a FieldData.
std::string MessageType(FieldData message) {
return options_field_util::ParseTypeUrl(
std::string(message.message_value().type_url()));
}
// Copy literal options from graph_options to node_options.
absl::Status CopyLiteralOptions(CalculatorGraphConfig::Node parent_node,
CalculatorGraphConfig* config) {
Status status;
FieldData config_options, parent_node_options, graph_options;
status.Update(
options_field_util::GetOptionsMessage(*config, &config_options));
status.Update(
options_field_util::GetOptionsMessage(parent_node, &parent_node_options));
status.Update(options_field_util::MergeOptionsMessages(
config_options, parent_node_options, &graph_options));
const Descriptor* options_descriptor =
OptionsRegistry::GetProtobufDescriptor(options_field_util::ParseTypeUrl(
std::string(graph_options.message_value().type_url())));
if (!options_descriptor) {
return status;
}
FieldData graph_data = options_field_util::AsFieldData(*config);
FieldData parent_data = options_field_util::AsFieldData(parent_node);
OptionsSyntaxUtil syntax_util;
for (auto& node : *config->mutable_node()) {
FieldData node_data;
status.Update(options_field_util::GetOptionsMessage(node, &node_data));
if (!node_data.has_message_value() || node.option_value_size() == 0) {
continue;
}
const Descriptor* node_options_descriptor =
OptionsRegistry::GetProtobufDescriptor(options_field_util::ParseTypeUrl(
std::string(node_data.message_value().type_url())));
if (!node_options_descriptor) {
continue;
}
FieldData node_data = options_field_util::AsFieldData(node);
for (const std::string& option_def : node.option_value()) {
std::vector<std::string> tag_and_name = absl::StrSplit(option_def, ':');
std::vector<absl::string_view> tag_and_name =
syntax_util.StrSplitTags(option_def);
std::string graph_tag = syntax_util.OptionFieldsTag(tag_and_name[1]);
std::string graph_extension_type = ExtensionType(graph_tag);
std::string node_tag = syntax_util.OptionFieldsTag(tag_and_name[0]);
std::string node_extension_type = ExtensionType(node_tag);
FieldData graph_options;
GetGraphOptions(graph_data, graph_extension_type, &graph_options)
.IgnoreError();
FieldData parent_options;
GetNodeOptions(parent_data, graph_extension_type, &parent_options)
.IgnoreError();
status.Update(
MergeMessages(graph_options, parent_options, &graph_options));
FieldData node_options;
status.Update(
GetNodeOptions(node_data, node_extension_type, &node_options));
if (!node_options.has_message_value() ||
!graph_options.has_message_value()) {
continue;
}
FieldPath graph_path = GetPath(graph_tag, MessageType(graph_options));
FieldPath node_path = GetPath(node_tag, MessageType(node_options));
FieldData packet_data;
status.Update(options_field_util::GetField(
syntax_util.OptionFieldPath(graph_tag, options_descriptor),
graph_options, &packet_data));
status.Update(options_field_util::MergeField(
syntax_util.OptionFieldPath(node_tag, node_options_descriptor),
packet_data, &node_data));
status.Update(GetField(graph_path, graph_options, &packet_data));
status.Update(MergeField(node_path, packet_data, &node_options));
options_field_util::SetOptionsMessage(node_options, &node);
}
options_field_util::SetOptionsMessage(node_data, &node);
}
return status;
}
+125 -4
View File
@@ -15,6 +15,7 @@
#include <memory>
#include <vector>
#include "absl/strings/string_view.h"
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/deps/message_matchers.h"
#include "mediapipe/framework/port/gtest.h"
@@ -22,6 +23,7 @@
#include "mediapipe/framework/port/status_matchers.h"
#include "mediapipe/framework/testdata/night_light_calculator.pb.h"
#include "mediapipe/framework/tool/node_chain_subgraph.pb.h"
#include "mediapipe/framework/tool/options_field_util.h"
#include "mediapipe/framework/tool/options_registry.h"
#include "mediapipe/framework/tool/options_syntax_util.h"
@@ -51,6 +53,35 @@ class NightLightCalculator : public CalculatorBase {
};
REGISTER_CALCULATOR(NightLightCalculator);
using tool::options_field_util::FieldPath;
// Validates FieldPathEntry contents.
bool Equals(const tool::options_field_util::FieldPathEntry& entry,
const std::string& field_name, int index,
const std::string& extension_type) {
const std::string& name = entry.field ? entry.field->name() : "";
return name == field_name && entry.index == index &&
entry.extension_type == extension_type;
}
// Serializes a MessageLite into FieldData.message_value.
FieldData AsFieldData(const proto_ns::MessageLite& message) {
FieldData result;
*result.mutable_message_value()->mutable_value() =
message.SerializeAsString();
result.mutable_message_value()->set_type_url(message.GetTypeName());
return result;
}
// Returns the type for the root options message if specified.
std::string ExtensionType(const std::string& option_fields_tag) {
tool::OptionsSyntaxUtil syntax_util;
tool::options_field_util::FieldPath field_path =
syntax_util.OptionFieldPath(option_fields_tag, nullptr);
std::string result = !field_path.empty() ? field_path[0].extension_type : "";
return !result.empty() ? result : "*";
}
// Tests for calculator and graph options.
//
class OptionsUtilTest : public ::testing::Test {
@@ -150,8 +181,8 @@ TEST_F(OptionsUtilTest, OptionsSyntaxUtil) {
EXPECT_EQ(tag, "OPTIONS/sub_options/num_lights");
field_path = syntax_util.OptionFieldPath(tag, descriptor);
EXPECT_EQ(field_path.size(), 2);
EXPECT_EQ(field_path[0].first->name(), "sub_options");
EXPECT_EQ(field_path[1].first->name(), "num_lights");
EXPECT_EQ(field_path[0].field->name(), "sub_options");
EXPECT_EQ(field_path[1].field->name(), "num_lights");
}
{
// A tag syntax with a text-coded separator.
@@ -160,10 +191,100 @@ TEST_F(OptionsUtilTest, OptionsSyntaxUtil) {
EXPECT_EQ(tag, "OPTIONS_Z0Z_sub_options_Z0Z_num_lights");
field_path = syntax_util.OptionFieldPath(tag, descriptor);
EXPECT_EQ(field_path.size(), 2);
EXPECT_EQ(field_path[0].first->name(), "sub_options");
EXPECT_EQ(field_path[1].first->name(), "num_lights");
EXPECT_EQ(field_path[0].field->name(), "sub_options");
EXPECT_EQ(field_path[1].field->name(), "num_lights");
}
}
TEST_F(OptionsUtilTest, OptionFieldPath) {
tool::OptionsSyntaxUtil syntax_util;
std::vector<absl::string_view> split;
split = syntax_util.StrSplitTags("a/graph/option:a/node/option");
EXPECT_EQ(2, split.size());
EXPECT_EQ(split[0], "a/graph/option");
EXPECT_EQ(split[1], "a/node/option");
split = syntax_util.StrSplitTags("Ext::a/graph/option:Ext::a/node/option");
EXPECT_EQ(2, split.size());
EXPECT_EQ(split[0], "Ext::a/graph/option");
EXPECT_EQ(split[1], "Ext::a/node/option");
split =
syntax_util.StrSplitTags("chain_length:options/sub_options/num_lights");
EXPECT_EQ(2, split.size());
EXPECT_EQ(split[0], "chain_length");
EXPECT_EQ(split[1], "options/sub_options/num_lights");
const tool::Descriptor* descriptor =
tool::OptionsRegistry::GetProtobufDescriptor(
"mediapipe.NightLightCalculatorOptions");
tool::options_field_util::FieldPath field_path =
syntax_util.OptionFieldPath(split[1], descriptor);
EXPECT_EQ(field_path.size(), 2);
EXPECT_EQ(field_path[0].field->name(), "sub_options");
EXPECT_EQ(field_path[1].field->name(), "num_lights");
}
TEST_F(OptionsUtilTest, FindOptionsMessage) {
tool::OptionsSyntaxUtil syntax_util;
std::vector<absl::string_view> split;
split =
syntax_util.StrSplitTags("chain_length:options/sub_options/num_lights");
EXPECT_EQ(2, split.size());
EXPECT_EQ(split[0], "chain_length");
EXPECT_EQ(split[1], "options/sub_options/num_lights");
const tool::Descriptor* descriptor =
tool::OptionsRegistry::GetProtobufDescriptor(
"mediapipe.NightLightCalculatorOptions");
tool::options_field_util::FieldPath field_path =
syntax_util.OptionFieldPath(split[1], descriptor);
EXPECT_EQ(field_path.size(), 2);
EXPECT_TRUE(Equals(field_path[0], "sub_options", 0, ""));
EXPECT_TRUE(Equals(field_path[1], "num_lights", 0, ""));
{
// NightLightCalculatorOptions in Node.options.
CalculatorGraphConfig::Node node;
NightLightCalculatorOptions* options =
node.mutable_options()->MutableExtension(
NightLightCalculatorOptions::ext);
options->mutable_sub_options()->add_num_lights(33);
// Retrieve the specified option.
FieldData node_data = AsFieldData(node);
auto path = field_path;
std::string node_extension_type = ExtensionType(std::string(split[1]));
FieldData node_options;
MP_EXPECT_OK(tool::options_field_util::GetNodeOptions(
node_data, node_extension_type, &node_options));
FieldData packet_data;
MP_EXPECT_OK(tool::options_field_util::GetField(field_path, node_options,
&packet_data));
EXPECT_EQ(packet_data.value_case(), FieldData::kInt32Value);
EXPECT_EQ(packet_data.int32_value(), 33);
}
{
// NightLightCalculatorOptions in Node.node_options.
CalculatorGraphConfig::Node node;
NightLightCalculatorOptions options;
options.mutable_sub_options()->add_num_lights(33);
node.add_node_options()->PackFrom(options);
// Retrieve the specified option.
FieldData node_data = AsFieldData(node);
auto path = field_path;
std::string node_extension_type = ExtensionType(std::string(split[1]));
FieldData node_options;
MP_EXPECT_OK(tool::options_field_util::GetNodeOptions(
node_data, node_extension_type, &node_options));
FieldData packet_data;
MP_EXPECT_OK(tool::options_field_util::GetField(field_path, node_options,
&packet_data));
EXPECT_EQ(packet_data.value_case(), FieldData::kInt32Value);
EXPECT_EQ(packet_data.int32_value(), 33);
}
// TODO: Test with specified extension_type.
}
} // namespace
} // namespace mediapipe