Project import generated by Copybara.
GitOrigin-RevId: 27c70b5fe62ab71189d358ca122ee4b19c817a8f
This commit is contained in:
@@ -222,10 +222,10 @@ cc_library(
|
||||
"//mediapipe/framework:mediapipe_options_cc_proto",
|
||||
"//mediapipe/framework:packet_generator_cc_proto",
|
||||
"//mediapipe/framework:status_handler_cc_proto",
|
||||
"//mediapipe/framework:stream_handler_cc_proto",
|
||||
"//mediapipe/framework/port:any_proto",
|
||||
"//mediapipe/framework/port:status",
|
||||
"//mediapipe/framework/tool:options_map",
|
||||
"//mediapipe/framework/tool:packet_generator_wrapper_calculator_cc_proto",
|
||||
"//mediapipe/framework/tool:tag_map",
|
||||
"@com_google_absl//absl/memory",
|
||||
],
|
||||
@@ -299,7 +299,6 @@ cc_library(
|
||||
":graph_service",
|
||||
":graph_service_manager",
|
||||
":input_stream_manager",
|
||||
":input_stream_shard",
|
||||
":output_side_packet_impl",
|
||||
":output_stream",
|
||||
":output_stream_manager",
|
||||
@@ -317,8 +316,6 @@ cc_library(
|
||||
":timestamp",
|
||||
":validated_graph_config",
|
||||
"//mediapipe/framework:calculator_cc_proto",
|
||||
"//mediapipe/framework:calculator_profile_cc_proto",
|
||||
"//mediapipe/framework:packet_factory_cc_proto",
|
||||
"//mediapipe/framework:packet_generator_cc_proto",
|
||||
"//mediapipe/framework:status_handler_cc_proto",
|
||||
"//mediapipe/framework:thread_pool_executor_cc_proto",
|
||||
@@ -327,6 +324,7 @@ cc_library(
|
||||
"@com_google_absl//absl/container:flat_hash_map",
|
||||
"@com_google_absl//absl/container:flat_hash_set",
|
||||
"@com_google_absl//absl/memory",
|
||||
"@com_google_absl//absl/status",
|
||||
"@com_google_absl//absl/strings",
|
||||
"@com_google_absl//absl/strings:str_format",
|
||||
"@com_google_absl//absl/synchronization",
|
||||
@@ -336,8 +334,8 @@ cc_library(
|
||||
"//mediapipe/framework/port:ret_check",
|
||||
"//mediapipe/framework/port:source_location",
|
||||
"//mediapipe/framework/port:status",
|
||||
"//mediapipe/framework/profiler:graph_profiler",
|
||||
"//mediapipe/framework/tool:fill_packet_set",
|
||||
"//mediapipe/framework/tool:packet_generator_wrapper_calculator",
|
||||
"//mediapipe/framework/tool:status_util",
|
||||
"//mediapipe/framework/tool:tag_map",
|
||||
"//mediapipe/framework/tool:validate",
|
||||
@@ -345,10 +343,7 @@ cc_library(
|
||||
"//mediapipe/gpu:graph_support",
|
||||
"//mediapipe/util:cpu_util",
|
||||
] + select({
|
||||
"//conditions:default": [
|
||||
"//mediapipe/gpu:gpu_shared_data_internal",
|
||||
"//mediapipe/gpu:gpu_service",
|
||||
],
|
||||
"//conditions:default": ["//mediapipe/gpu:gpu_shared_data_internal"],
|
||||
"//mediapipe/gpu:disable_gpu": [],
|
||||
}),
|
||||
)
|
||||
@@ -389,13 +384,11 @@ cc_library(
|
||||
":input_side_packet_handler",
|
||||
":input_stream_handler",
|
||||
":input_stream_manager",
|
||||
":input_stream_shard",
|
||||
":legacy_calculator_support",
|
||||
":mediapipe_profiling",
|
||||
":output_side_packet_impl",
|
||||
":output_stream_handler",
|
||||
":output_stream_manager",
|
||||
":output_stream_shard",
|
||||
":packet",
|
||||
":packet_set",
|
||||
":packet_type",
|
||||
@@ -404,14 +397,12 @@ cc_library(
|
||||
":validated_graph_config",
|
||||
"//mediapipe/framework:calculator_cc_proto",
|
||||
"//mediapipe/framework:stream_handler_cc_proto",
|
||||
"//mediapipe/framework/deps:registration",
|
||||
"//mediapipe/framework/port:core_proto",
|
||||
"//mediapipe/framework/port:integral_types",
|
||||
"//mediapipe/framework/port:logging",
|
||||
"//mediapipe/framework/port:ret_check",
|
||||
"//mediapipe/framework/port:source_location",
|
||||
"//mediapipe/framework/port:status",
|
||||
"//mediapipe/framework/profiler:graph_profiler",
|
||||
"//mediapipe/framework/stream_handler:default_input_stream_handler",
|
||||
"//mediapipe/framework/stream_handler:in_order_output_stream_handler",
|
||||
"//mediapipe/framework/tool:name_util",
|
||||
@@ -421,6 +412,7 @@ cc_library(
|
||||
"//mediapipe/gpu:graph_support",
|
||||
"@com_google_absl//absl/base:core_headers",
|
||||
"@com_google_absl//absl/memory",
|
||||
"@com_google_absl//absl/status",
|
||||
"@com_google_absl//absl/strings",
|
||||
"@com_google_absl//absl/synchronization",
|
||||
],
|
||||
@@ -1588,6 +1580,7 @@ cc_test(
|
||||
":packet",
|
||||
":packet_test_cc_proto",
|
||||
":type_map",
|
||||
"//mediapipe/framework/deps:message_matchers",
|
||||
"//mediapipe/framework/port:core_proto",
|
||||
"//mediapipe/framework/port:gtest_main",
|
||||
"@com_google_absl//absl/strings",
|
||||
|
||||
@@ -212,6 +212,9 @@ message ProfilerConfig {
|
||||
// False specifies an event for each calculator invocation.
|
||||
// True specifies a separate event for each start and finish time.
|
||||
bool trace_log_instant_events = 17;
|
||||
|
||||
// Limits calculator-profile histograms to a subset of calculators.
|
||||
string calculator_filter = 18;
|
||||
}
|
||||
|
||||
// Describes the topology and function of a MediaPipe Graph. The graph of
|
||||
|
||||
@@ -14,16 +14,40 @@
|
||||
|
||||
#include "mediapipe/framework/calculator_contract.h"
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/memory/memory.h"
|
||||
#include "mediapipe/framework/port/status.h"
|
||||
#include "mediapipe/framework/port/status_builder.h"
|
||||
#include "mediapipe/framework/port/status_macros.h"
|
||||
#include "mediapipe/framework/tool/packet_generator_wrapper_calculator.pb.h"
|
||||
#include "mediapipe/framework/tool/tag_map.h"
|
||||
|
||||
namespace mediapipe {
|
||||
|
||||
namespace {
|
||||
|
||||
CalculatorGraphConfig::Node MakePacketGeneratorWrapperConfig(
|
||||
const PacketGeneratorConfig& node, const std::string& package) {
|
||||
CalculatorGraphConfig::Node wrapper_node;
|
||||
wrapper_node.set_calculator("PacketGeneratorWrapperCalculator");
|
||||
*wrapper_node.mutable_input_side_packet() = node.input_side_packet();
|
||||
*wrapper_node.mutable_output_side_packet() = node.output_side_packet();
|
||||
|
||||
auto* wrapper_options = wrapper_node.mutable_options()->MutableExtension(
|
||||
mediapipe::PacketGeneratorWrapperCalculatorOptions::ext);
|
||||
wrapper_options->set_packet_generator(node.packet_generator());
|
||||
wrapper_options->set_package(package);
|
||||
if (node.has_options()) {
|
||||
*wrapper_options->mutable_options() = node.options();
|
||||
}
|
||||
return wrapper_node;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
absl::Status CalculatorContract::Initialize(
|
||||
const CalculatorGraphConfig::Node& node) {
|
||||
std::vector<absl::Status> statuses;
|
||||
@@ -74,7 +98,8 @@ absl::Status CalculatorContract::Initialize(
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status CalculatorContract::Initialize(const PacketGeneratorConfig& node) {
|
||||
absl::Status CalculatorContract::Initialize(const PacketGeneratorConfig& node,
|
||||
const std::string& package) {
|
||||
std::vector<absl::Status> statuses;
|
||||
|
||||
auto input_side_packet_statusor =
|
||||
@@ -101,6 +126,11 @@ absl::Status CalculatorContract::Initialize(const PacketGeneratorConfig& node) {
|
||||
return std::move(builder);
|
||||
}
|
||||
|
||||
wrapper_config_ = std::make_unique<CalculatorGraphConfig::Node>(
|
||||
MakePacketGeneratorWrapperConfig(node, package));
|
||||
options_.Initialize(*wrapper_config_);
|
||||
inputs_ = absl::make_unique<PacketTypeSet>(0);
|
||||
outputs_ = absl::make_unique<PacketTypeSet>(0);
|
||||
input_side_packets_ = absl::make_unique<PacketTypeSet>(
|
||||
std::move(input_side_packet_statusor).value());
|
||||
output_side_packets_ = absl::make_unique<PacketTypeSet>(
|
||||
|
||||
@@ -48,7 +48,8 @@ namespace mediapipe {
|
||||
class CalculatorContract {
|
||||
public:
|
||||
absl::Status Initialize(const CalculatorGraphConfig::Node& node);
|
||||
absl::Status Initialize(const PacketGeneratorConfig& node);
|
||||
absl::Status Initialize(const PacketGeneratorConfig& node,
|
||||
const std::string& package);
|
||||
absl::Status Initialize(const StatusHandlerConfig& node);
|
||||
void SetNodeName(const std::string& node_name) { node_name_ = node_name; }
|
||||
|
||||
@@ -163,7 +164,14 @@ class CalculatorContract {
|
||||
template <class T>
|
||||
void GetNodeOptions(T* result) const;
|
||||
|
||||
// When creating a contract for a PacketGenerator, we define a configuration
|
||||
// for a wrapper calculator, for use by CalculatorNode.
|
||||
const CalculatorGraphConfig::Node& GetWrapperConfig() const {
|
||||
return *wrapper_config_;
|
||||
}
|
||||
|
||||
const CalculatorGraphConfig::Node* node_config_ = nullptr;
|
||||
std::unique_ptr<CalculatorGraphConfig::Node> wrapper_config_;
|
||||
tool::OptionsMap options_;
|
||||
std::unique_ptr<PacketTypeSet> inputs_;
|
||||
std::unique_ptr<PacketTypeSet> outputs_;
|
||||
@@ -175,6 +183,8 @@ class CalculatorContract {
|
||||
std::map<std::string, GraphServiceRequest> service_requests_;
|
||||
bool process_timestamps_ = false;
|
||||
TimestampDiff timestamp_offset_ = TimestampDiff::Unset();
|
||||
|
||||
friend class CalculatorNode;
|
||||
};
|
||||
|
||||
} // namespace mediapipe
|
||||
|
||||
@@ -80,7 +80,7 @@ TEST(CalculatorContractTest, PacketGenerator) {
|
||||
output_side_packet: "content_fingerprint"
|
||||
)pb");
|
||||
CalculatorContract contract;
|
||||
MP_EXPECT_OK(contract.Initialize(node));
|
||||
MP_EXPECT_OK(contract.Initialize(node, ""));
|
||||
EXPECT_EQ(contract.InputSidePackets().NumEntries(), 1);
|
||||
EXPECT_EQ(contract.OutputSidePackets().NumEntries(), 4);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "absl/container/fixed_array.h"
|
||||
#include "absl/container/flat_hash_set.h"
|
||||
#include "absl/memory/memory.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "absl/strings/str_join.h"
|
||||
@@ -84,9 +85,9 @@ void CalculatorGraph::ScheduleAllOpenableNodes() {
|
||||
// node->ReadyForOpen() only before any node or graph input stream has
|
||||
// propagated header packets or generated output side packets, either of
|
||||
// which may cause a downstream node to be scheduled for OpenNode().
|
||||
for (CalculatorNode& node : *nodes_) {
|
||||
if (node.ReadyForOpen()) {
|
||||
scheduler_.ScheduleNodeForOpen(&node);
|
||||
for (auto& node : nodes_) {
|
||||
if (node->ReadyForOpen()) {
|
||||
scheduler_.ScheduleNodeForOpen(node.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -234,15 +235,15 @@ absl::Status CalculatorGraph::InitializeCalculatorNodes() {
|
||||
std::vector<absl::Status> errors;
|
||||
|
||||
// Create and initialize all the nodes in the graph.
|
||||
nodes_ = absl::make_unique<absl::FixedArray<CalculatorNode>>(
|
||||
validated_graph_->CalculatorInfos().size());
|
||||
for (int node_id = 0; node_id < validated_graph_->CalculatorInfos().size();
|
||||
++node_id) {
|
||||
// buffer_size_hint will be positive if one was specified in
|
||||
// the graph proto.
|
||||
int buffer_size_hint = 0;
|
||||
const absl::Status result = (*nodes_)[node_id].Initialize(
|
||||
validated_graph_.get(), node_id, input_stream_managers_.get(),
|
||||
NodeTypeInfo::NodeRef node_ref(NodeTypeInfo::NodeType::CALCULATOR, node_id);
|
||||
nodes_.push_back(absl::make_unique<CalculatorNode>());
|
||||
const absl::Status result = nodes_.back()->Initialize(
|
||||
validated_graph_.get(), node_ref, input_stream_managers_.get(),
|
||||
output_stream_managers_.get(), output_side_packets_.get(),
|
||||
&buffer_size_hint, profiler_);
|
||||
if (buffer_size_hint > 0) {
|
||||
@@ -263,6 +264,38 @@ absl::Status CalculatorGraph::InitializeCalculatorNodes() {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status CalculatorGraph::InitializePacketGeneratorNodes(
|
||||
const std::vector<int>& non_scheduled_generators) {
|
||||
// Do not add wrapper nodes again if we are running the graph multiple times.
|
||||
if (packet_generator_nodes_added_) return absl::OkStatus();
|
||||
|
||||
packet_generator_nodes_added_ = true;
|
||||
// Use a local variable to avoid needing to lock errors_.
|
||||
std::vector<absl::Status> errors;
|
||||
|
||||
for (int index : non_scheduled_generators) {
|
||||
// This is never used by the packet generator wrapper.
|
||||
int buffer_size_hint = 0;
|
||||
NodeTypeInfo::NodeRef node_ref(NodeTypeInfo::NodeType::PACKET_GENERATOR,
|
||||
index);
|
||||
nodes_.push_back(absl::make_unique<CalculatorNode>());
|
||||
const absl::Status result = nodes_.back()->Initialize(
|
||||
validated_graph_.get(), node_ref, input_stream_managers_.get(),
|
||||
output_stream_managers_.get(), output_side_packets_.get(),
|
||||
&buffer_size_hint, profiler_);
|
||||
if (!result.ok()) {
|
||||
// Collect as many errors as we can before failing.
|
||||
errors.push_back(result);
|
||||
}
|
||||
}
|
||||
if (!errors.empty()) {
|
||||
return tool::CombinedStatus(
|
||||
"CalculatorGraph::InitializePacketGeneratorNodes failed: ", errors);
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status CalculatorGraph::InitializeProfiler() {
|
||||
profiler_->Initialize(*validated_graph_);
|
||||
return absl::OkStatus();
|
||||
@@ -528,8 +561,8 @@ absl::StatusOr<std::map<std::string, Packet>> CalculatorGraph::PrepareGpu(
|
||||
std::map<std::string, Packet> additional_side_packets;
|
||||
bool update_sp = false;
|
||||
bool uses_gpu = false;
|
||||
for (const auto& node : *nodes_) {
|
||||
if (node.UsesGpu()) {
|
||||
for (const auto& node : nodes_) {
|
||||
if (node->UsesGpu()) {
|
||||
uses_gpu = true;
|
||||
break;
|
||||
}
|
||||
@@ -571,9 +604,9 @@ absl::StatusOr<std::map<std::string, Packet>> CalculatorGraph::PrepareGpu(
|
||||
}
|
||||
|
||||
// Set up executors.
|
||||
for (auto& node : *nodes_) {
|
||||
if (node.UsesGpu()) {
|
||||
MP_RETURN_IF_ERROR(gpu_resources->PrepareGpuNode(&node));
|
||||
for (auto& node : nodes_) {
|
||||
if (node->UsesGpu()) {
|
||||
MP_RETURN_IF_ERROR(gpu_resources->PrepareGpuNode(node.get()));
|
||||
}
|
||||
}
|
||||
for (const auto& name_executor : gpu_resources->GetGpuExecutors()) {
|
||||
@@ -616,8 +649,10 @@ absl::Status CalculatorGraph::PrepareForRun(
|
||||
}
|
||||
|
||||
current_run_side_packets_.clear();
|
||||
std::vector<int> non_scheduled_generators;
|
||||
absl::Status generator_status = packet_generator_graph_.RunGraphSetup(
|
||||
*input_side_packets, ¤t_run_side_packets_);
|
||||
*input_side_packets, ¤t_run_side_packets_,
|
||||
&non_scheduled_generators);
|
||||
|
||||
CallStatusHandlers(GraphRunState::PRE_RUN, generator_status);
|
||||
|
||||
@@ -650,6 +685,8 @@ absl::Status CalculatorGraph::PrepareForRun(
|
||||
}
|
||||
scheduler_.Reset();
|
||||
|
||||
MP_RETURN_IF_ERROR(InitializePacketGeneratorNodes(non_scheduled_generators));
|
||||
|
||||
{
|
||||
absl::MutexLock lock(&full_input_streams_mutex_);
|
||||
// Initialize a count per source node to store the number of input streams
|
||||
@@ -671,22 +708,22 @@ absl::Status CalculatorGraph::PrepareForRun(
|
||||
output_side_packets_[index].PrepareForRun(
|
||||
std::bind(&CalculatorGraph::RecordError, this, std::placeholders::_1));
|
||||
}
|
||||
for (CalculatorNode& node : *nodes_) {
|
||||
for (auto& node : nodes_) {
|
||||
InputStreamManager::QueueSizeCallback queue_size_callback =
|
||||
std::bind(&CalculatorGraph::UpdateThrottledNodes, this,
|
||||
std::placeholders::_1, std::placeholders::_2);
|
||||
node.SetQueueSizeCallbacks(queue_size_callback, queue_size_callback);
|
||||
scheduler_.AssignNodeToSchedulerQueue(&node);
|
||||
node->SetQueueSizeCallbacks(queue_size_callback, queue_size_callback);
|
||||
scheduler_.AssignNodeToSchedulerQueue(node.get());
|
||||
// TODO: update calculator node to use GraphServiceManager
|
||||
// instead of service packets?
|
||||
const absl::Status result = node.PrepareForRun(
|
||||
const absl::Status result = node->PrepareForRun(
|
||||
current_run_side_packets_, service_manager_.ServicePackets(),
|
||||
std::bind(&internal::Scheduler::ScheduleNodeForOpen, &scheduler_,
|
||||
&node),
|
||||
node.get()),
|
||||
std::bind(&internal::Scheduler::AddNodeToSourcesQueue, &scheduler_,
|
||||
&node),
|
||||
node.get()),
|
||||
std::bind(&internal::Scheduler::ScheduleNodeIfNotThrottled, &scheduler_,
|
||||
&node, std::placeholders::_1),
|
||||
node.get(), std::placeholders::_1),
|
||||
std::bind(&CalculatorGraph::RecordError, this, std::placeholders::_1),
|
||||
counter_factory_.get());
|
||||
if (!result.ok()) {
|
||||
@@ -714,8 +751,8 @@ absl::Status CalculatorGraph::PrepareForRun(
|
||||
|
||||
// Ensure that the latest value of max queue size is passed to all input
|
||||
// streams.
|
||||
for (auto& node : *nodes_) {
|
||||
node.SetMaxInputStreamQueueSize(max_queue_size_);
|
||||
for (auto& node : nodes_) {
|
||||
node->SetMaxInputStreamQueueSize(max_queue_size_);
|
||||
}
|
||||
|
||||
// Allow graph input streams to override the global max queue size.
|
||||
@@ -729,9 +766,9 @@ absl::Status CalculatorGraph::PrepareForRun(
|
||||
(*stream)->SetMaxQueueSize(name_max.second);
|
||||
}
|
||||
|
||||
for (CalculatorNode& node : *nodes_) {
|
||||
if (node.IsSource()) {
|
||||
scheduler_.AddUnopenedSourceNode(&node);
|
||||
for (auto& node : nodes_) {
|
||||
if (node->IsSource()) {
|
||||
scheduler_.AddUnopenedSourceNode(node.get());
|
||||
has_sources_ = true;
|
||||
}
|
||||
}
|
||||
@@ -1077,7 +1114,7 @@ void CalculatorGraph::UpdateThrottledNodes(InputStreamManager* stream,
|
||||
}
|
||||
} else {
|
||||
if (!is_throttled) {
|
||||
CalculatorNode& node = (*nodes_)[node_id];
|
||||
CalculatorNode& node = *nodes_[node_id];
|
||||
// Add this node to the scheduler queue if possible.
|
||||
if (node.Active() && !node.Closed()) {
|
||||
nodes_to_schedule.emplace_back(&node);
|
||||
@@ -1244,8 +1281,8 @@ void CalculatorGraph::CleanupAfterRun(absl::Status* status) {
|
||||
MEDIAPIPE_CHECK_OK(*status);
|
||||
}
|
||||
|
||||
for (CalculatorNode& node : *nodes_) {
|
||||
node.CleanupAfterRun(*status);
|
||||
for (auto& node : nodes_) {
|
||||
node->CleanupAfterRun(*status);
|
||||
}
|
||||
|
||||
for (auto& graph_output_stream : graph_output_streams_) {
|
||||
|
||||
@@ -486,6 +486,8 @@ class CalculatorGraph {
|
||||
absl::Status InitializeStreams();
|
||||
absl::Status InitializeProfiler();
|
||||
absl::Status InitializeCalculatorNodes();
|
||||
absl::Status InitializePacketGeneratorNodes(
|
||||
const std::vector<int>& non_scheduled_generators);
|
||||
|
||||
// Iterates through all nodes and schedules any that can be opened.
|
||||
void ScheduleAllOpenableNodes();
|
||||
@@ -556,7 +558,8 @@ class CalculatorGraph {
|
||||
std::unique_ptr<InputStreamManager[]> input_stream_managers_;
|
||||
std::unique_ptr<OutputStreamManager[]> output_stream_managers_;
|
||||
std::unique_ptr<OutputSidePacketImpl[]> output_side_packets_;
|
||||
std::unique_ptr<absl::FixedArray<CalculatorNode>> nodes_;
|
||||
std::vector<std::unique_ptr<CalculatorNode>> nodes_;
|
||||
bool packet_generator_nodes_added_ = false;
|
||||
|
||||
// The graph output streams.
|
||||
std::vector<std::shared_ptr<internal::GraphOutputStream>>
|
||||
|
||||
@@ -52,6 +52,25 @@ class OutputSidePacketInProcessCalculator : public CalculatorBase {
|
||||
};
|
||||
REGISTER_CALCULATOR(OutputSidePacketInProcessCalculator);
|
||||
|
||||
// Takes an input side packet and passes it as an output side packet.
|
||||
class OutputSidePacketInOpenCalculator : public CalculatorBase {
|
||||
public:
|
||||
static absl::Status GetContract(CalculatorContract* cc) {
|
||||
cc->InputSidePackets().Index(0).SetAny();
|
||||
cc->OutputSidePackets().Index(0).SetSameAs(
|
||||
&cc->InputSidePackets().Index(0));
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status Open(CalculatorContext* cc) final {
|
||||
cc->OutputSidePackets().Index(0).Set(cc->InputSidePackets().Index(0));
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status Process(CalculatorContext* cc) final { return absl::OkStatus(); }
|
||||
};
|
||||
REGISTER_CALCULATOR(OutputSidePacketInOpenCalculator);
|
||||
|
||||
// Takes an input stream packet and counts the number of the packets it
|
||||
// receives. Outputs the total number of packets as a side packet in Close.
|
||||
class CountAndOutputSummarySidePacketInCloseCalculator : public CalculatorBase {
|
||||
@@ -802,5 +821,80 @@ TEST(CalculatorGraph, OutputSidePacketCached) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CalculatorGraph, GeneratorAfterCalculatorOpen) {
|
||||
CalculatorGraph graph;
|
||||
CalculatorGraphConfig config =
|
||||
mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"pb(
|
||||
input_side_packet: "offset"
|
||||
node {
|
||||
calculator: "OutputSidePacketInOpenCalculator"
|
||||
input_side_packet: "offset"
|
||||
output_side_packet: "offset1"
|
||||
}
|
||||
packet_generator {
|
||||
packet_generator: 'PassThroughGenerator'
|
||||
input_side_packet: 'offset1'
|
||||
output_side_packet: 'offset_out'
|
||||
}
|
||||
node {
|
||||
calculator: "SidePacketToStreamPacketCalculator"
|
||||
input_side_packet: "offset_out"
|
||||
output_stream: "output"
|
||||
}
|
||||
)pb");
|
||||
MP_ASSERT_OK(graph.Initialize(config));
|
||||
std::vector<Packet> output_packets;
|
||||
MP_ASSERT_OK(graph.ObserveOutputStream(
|
||||
"output", [&output_packets](const Packet& packet) {
|
||||
output_packets.push_back(packet);
|
||||
return absl::OkStatus();
|
||||
}));
|
||||
MP_ASSERT_OK(graph.StartRun({{"offset", MakePacket<TimestampDiff>(100)}}));
|
||||
MP_ASSERT_OK(graph.WaitUntilDone());
|
||||
ASSERT_EQ(1, output_packets.size());
|
||||
EXPECT_EQ(100, output_packets[0].Get<TimestampDiff>().Value());
|
||||
}
|
||||
|
||||
TEST(CalculatorGraph, GeneratorAfterCalculatorProcess) {
|
||||
CalculatorGraph graph;
|
||||
CalculatorGraphConfig config =
|
||||
mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"pb(
|
||||
input_stream: "offset"
|
||||
node {
|
||||
calculator: "OutputSidePacketInProcessCalculator"
|
||||
input_stream: "offset"
|
||||
output_side_packet: "offset"
|
||||
}
|
||||
packet_generator {
|
||||
packet_generator: 'PassThroughGenerator'
|
||||
input_side_packet: 'offset'
|
||||
output_side_packet: 'offset_out'
|
||||
}
|
||||
node {
|
||||
calculator: "SidePacketToStreamPacketCalculator"
|
||||
input_side_packet: "offset_out"
|
||||
output_stream: "output"
|
||||
}
|
||||
)pb");
|
||||
MP_ASSERT_OK(graph.Initialize(config));
|
||||
std::vector<Packet> output_packets;
|
||||
MP_ASSERT_OK(graph.ObserveOutputStream(
|
||||
"output", [&output_packets](const Packet& packet) {
|
||||
output_packets.push_back(packet);
|
||||
return absl::OkStatus();
|
||||
}));
|
||||
// Run twice to verify that we don't duplicate wrapper nodes.
|
||||
for (int run = 0; run < 2; ++run) {
|
||||
output_packets.clear();
|
||||
MP_ASSERT_OK(graph.StartRun({}));
|
||||
MP_ASSERT_OK(graph.AddPacketToInputStream(
|
||||
"offset", MakePacket<TimestampDiff>(100).At(Timestamp(0))));
|
||||
MP_ASSERT_OK(graph.CloseInputStream("offset"));
|
||||
MP_ASSERT_OK(graph.WaitUntilDone());
|
||||
ASSERT_EQ(1, output_packets.size());
|
||||
EXPECT_EQ(100, output_packets[0].Get<TimestampDiff>().Value());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace mediapipe
|
||||
|
||||
@@ -1133,24 +1133,6 @@ class CheckInputTimestamp2SinkCalculator : public CalculatorBase {
|
||||
};
|
||||
REGISTER_CALCULATOR(CheckInputTimestamp2SinkCalculator);
|
||||
|
||||
// Takes an input stream packet and passes it (with timestamp removed) as an
|
||||
// output side packet.
|
||||
class OutputSidePacketInProcessCalculator : public CalculatorBase {
|
||||
public:
|
||||
static absl::Status GetContract(CalculatorContract* cc) {
|
||||
cc->Inputs().Index(0).SetAny();
|
||||
cc->OutputSidePackets().Index(0).SetSameAs(&cc->Inputs().Index(0));
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status Process(CalculatorContext* cc) final {
|
||||
cc->OutputSidePackets().Index(0).Set(
|
||||
cc->Inputs().Index(0).Value().At(Timestamp::Unset()));
|
||||
return absl::OkStatus();
|
||||
}
|
||||
};
|
||||
REGISTER_CALCULATOR(OutputSidePacketInProcessCalculator);
|
||||
|
||||
// A calculator checks if either of two input streams contains a packet and
|
||||
// sends the packet to the single output stream with the same timestamp.
|
||||
class SimpleMuxCalculator : public CalculatorBase {
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <utility>
|
||||
|
||||
#include "absl/memory/memory.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/str_join.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
@@ -119,79 +120,92 @@ Timestamp CalculatorNode::SourceProcessOrder(
|
||||
}
|
||||
|
||||
absl::Status CalculatorNode::Initialize(
|
||||
const ValidatedGraphConfig* validated_graph, int node_id,
|
||||
const ValidatedGraphConfig* validated_graph, NodeTypeInfo::NodeRef node_ref,
|
||||
InputStreamManager* input_stream_managers,
|
||||
OutputStreamManager* output_stream_managers,
|
||||
OutputSidePacketImpl* output_side_packets, int* buffer_size_hint,
|
||||
std::shared_ptr<ProfilingContext> profiling_context) {
|
||||
RET_CHECK(buffer_size_hint) << "buffer_size_hint is NULL";
|
||||
node_id_ = node_id;
|
||||
validated_graph_ = validated_graph;
|
||||
profiling_context_ = profiling_context;
|
||||
|
||||
const CalculatorGraphConfig::Node& node_config =
|
||||
validated_graph_->Config().node(node_id_);
|
||||
name_ = tool::CanonicalNodeName(validated_graph_->Config(), node_id_);
|
||||
|
||||
max_in_flight_ = node_config.max_in_flight();
|
||||
max_in_flight_ = max_in_flight_ ? max_in_flight_ : 1;
|
||||
if (!node_config.executor().empty()) {
|
||||
executor_ = node_config.executor();
|
||||
const CalculatorGraphConfig::Node* node_config;
|
||||
if (node_ref.type == NodeTypeInfo::NodeType::CALCULATOR) {
|
||||
node_config = &validated_graph_->Config().node(node_ref.index);
|
||||
name_ = tool::CanonicalNodeName(validated_graph_->Config(), node_ref.index);
|
||||
node_type_info_ = &validated_graph_->CalculatorInfos()[node_ref.index];
|
||||
} else if (node_ref.type == NodeTypeInfo::NodeType::PACKET_GENERATOR) {
|
||||
const PacketGeneratorConfig& pg_config =
|
||||
validated_graph_->Config().packet_generator(node_ref.index);
|
||||
name_ = absl::StrCat("__pg_", node_ref.index, "_",
|
||||
pg_config.packet_generator());
|
||||
node_type_info_ = &validated_graph_->GeneratorInfos()[node_ref.index];
|
||||
node_config = &node_type_info_->Contract().GetWrapperConfig();
|
||||
} else {
|
||||
return absl::InvalidArgumentError(
|
||||
"node_ref is not a calculator or packet generator");
|
||||
}
|
||||
source_layer_ = node_config.source_layer();
|
||||
|
||||
const NodeTypeInfo& node_type_info =
|
||||
validated_graph_->CalculatorInfos()[node_id_];
|
||||
const CalculatorContract& contract = node_type_info.Contract();
|
||||
max_in_flight_ = node_config->max_in_flight();
|
||||
max_in_flight_ = max_in_flight_ ? max_in_flight_ : 1;
|
||||
if (!node_config->executor().empty()) {
|
||||
executor_ = node_config->executor();
|
||||
}
|
||||
source_layer_ = node_config->source_layer();
|
||||
|
||||
const CalculatorContract& contract = node_type_info_->Contract();
|
||||
|
||||
uses_gpu_ =
|
||||
node_type_info.InputSidePacketTypes().HasTag(kGpuSharedTagName) ||
|
||||
ContainsKey(node_type_info.Contract().ServiceRequests(), kGpuService.key);
|
||||
node_type_info_->InputSidePacketTypes().HasTag(kGpuSharedTagName) ||
|
||||
ContainsKey(node_type_info_->Contract().ServiceRequests(),
|
||||
kGpuService.key);
|
||||
|
||||
// TODO Propagate types between calculators when SetAny is used.
|
||||
|
||||
MP_RETURN_IF_ERROR(InitializeOutputSidePackets(
|
||||
node_type_info.OutputSidePacketTypes(), output_side_packets));
|
||||
node_type_info_->OutputSidePacketTypes(), output_side_packets));
|
||||
|
||||
MP_RETURN_IF_ERROR(InitializeInputSidePackets(output_side_packets));
|
||||
|
||||
MP_RETURN_IF_ERROR(InitializeOutputStreamHandler(
|
||||
node_config.output_stream_handler(), node_type_info.OutputStreamTypes()));
|
||||
MP_RETURN_IF_ERROR(
|
||||
InitializeOutputStreamHandler(node_config->output_stream_handler(),
|
||||
node_type_info_->OutputStreamTypes()));
|
||||
MP_RETURN_IF_ERROR(InitializeOutputStreams(output_stream_managers));
|
||||
|
||||
calculator_state_ = absl::make_unique<CalculatorState>(
|
||||
name_, node_id_, node_config.calculator(), node_config,
|
||||
name_, node_ref.index, node_config->calculator(), *node_config,
|
||||
profiling_context_);
|
||||
|
||||
// Inform the scheduler that this node has buffering behavior and that the
|
||||
// maximum input queue size should be adjusted accordingly.
|
||||
*buffer_size_hint = node_config.buffer_size_hint();
|
||||
*buffer_size_hint = node_config->buffer_size_hint();
|
||||
|
||||
calculator_context_manager_.Initialize(
|
||||
calculator_state_.get(), node_type_info.InputStreamTypes().TagMap(),
|
||||
node_type_info.OutputStreamTypes().TagMap(),
|
||||
calculator_state_.get(), node_type_info_->InputStreamTypes().TagMap(),
|
||||
node_type_info_->OutputStreamTypes().TagMap(),
|
||||
/*calculator_run_in_parallel=*/max_in_flight_ > 1);
|
||||
|
||||
// The graph specified InputStreamHandler takes priority.
|
||||
const bool graph_specified =
|
||||
node_config.input_stream_handler().has_input_stream_handler();
|
||||
const bool calc_specified = !(node_type_info.GetInputStreamHandler().empty());
|
||||
node_config->input_stream_handler().has_input_stream_handler();
|
||||
const bool calc_specified =
|
||||
!(node_type_info_->GetInputStreamHandler().empty());
|
||||
|
||||
// Only use calculator ISH if available, and if the graph ISH is not set.
|
||||
InputStreamHandlerConfig handler_config;
|
||||
const bool use_calc_specified = calc_specified && !graph_specified;
|
||||
if (use_calc_specified) {
|
||||
*(handler_config.mutable_input_stream_handler()) =
|
||||
node_type_info.GetInputStreamHandler();
|
||||
node_type_info_->GetInputStreamHandler();
|
||||
*(handler_config.mutable_options()) =
|
||||
node_type_info.GetInputStreamHandlerOptions();
|
||||
node_type_info_->GetInputStreamHandlerOptions();
|
||||
}
|
||||
|
||||
// Use calculator or graph specified InputStreamHandler, or the default ISH
|
||||
// already set from graph.
|
||||
MP_RETURN_IF_ERROR(InitializeInputStreamHandler(
|
||||
use_calc_specified ? handler_config : node_config.input_stream_handler(),
|
||||
node_type_info.InputStreamTypes()));
|
||||
use_calc_specified ? handler_config : node_config->input_stream_handler(),
|
||||
node_type_info_->InputStreamTypes()));
|
||||
|
||||
for (auto& stream : output_stream_handler_->OutputStreams()) {
|
||||
stream->Spec()->offset_enabled =
|
||||
@@ -209,9 +223,7 @@ absl::Status CalculatorNode::InitializeOutputSidePackets(
|
||||
OutputSidePacketImpl* output_side_packets) {
|
||||
output_side_packets_ =
|
||||
absl::make_unique<OutputSidePacketSet>(output_side_packet_types.TagMap());
|
||||
const NodeTypeInfo& node_type_info =
|
||||
validated_graph_->CalculatorInfos()[node_id_];
|
||||
int base_index = node_type_info.OutputSidePacketBaseIndex();
|
||||
int base_index = node_type_info_->OutputSidePacketBaseIndex();
|
||||
RET_CHECK_LE(0, base_index);
|
||||
for (CollectionItemId id = output_side_packets_->BeginId();
|
||||
id < output_side_packets_->EndId(); ++id) {
|
||||
@@ -223,13 +235,11 @@ absl::Status CalculatorNode::InitializeOutputSidePackets(
|
||||
|
||||
absl::Status CalculatorNode::InitializeInputSidePackets(
|
||||
OutputSidePacketImpl* output_side_packets) {
|
||||
const NodeTypeInfo& node_type_info =
|
||||
validated_graph_->CalculatorInfos()[node_id_];
|
||||
int base_index = node_type_info.InputSidePacketBaseIndex();
|
||||
int base_index = node_type_info_->InputSidePacketBaseIndex();
|
||||
RET_CHECK_LE(0, base_index);
|
||||
// Set all the mirrors.
|
||||
for (CollectionItemId id = node_type_info.InputSidePacketTypes().BeginId();
|
||||
id < node_type_info.InputSidePacketTypes().EndId(); ++id) {
|
||||
for (CollectionItemId id = node_type_info_->InputSidePacketTypes().BeginId();
|
||||
id < node_type_info_->InputSidePacketTypes().EndId(); ++id) {
|
||||
int output_side_packet_index =
|
||||
validated_graph_->InputSidePacketInfos()[base_index + id.value()]
|
||||
.upstream;
|
||||
@@ -252,11 +262,9 @@ absl::Status CalculatorNode::InitializeInputSidePackets(
|
||||
absl::Status CalculatorNode::InitializeOutputStreams(
|
||||
OutputStreamManager* output_stream_managers) {
|
||||
RET_CHECK(output_stream_managers) << "output_stream_managers is NULL";
|
||||
const NodeTypeInfo& node_type_info =
|
||||
validated_graph_->CalculatorInfos()[node_id_];
|
||||
RET_CHECK_LE(0, node_type_info.OutputStreamBaseIndex());
|
||||
RET_CHECK_LE(0, node_type_info_->OutputStreamBaseIndex());
|
||||
OutputStreamManager* current_output_stream_managers =
|
||||
&output_stream_managers[node_type_info.OutputStreamBaseIndex()];
|
||||
&output_stream_managers[node_type_info_->OutputStreamBaseIndex()];
|
||||
return output_stream_handler_->InitializeOutputStreamManagers(
|
||||
current_output_stream_managers);
|
||||
}
|
||||
@@ -266,20 +274,18 @@ absl::Status CalculatorNode::InitializeInputStreams(
|
||||
OutputStreamManager* output_stream_managers) {
|
||||
RET_CHECK(input_stream_managers) << "input_stream_managers is NULL";
|
||||
RET_CHECK(output_stream_managers) << "output_stream_managers is NULL";
|
||||
const NodeTypeInfo& node_type_info =
|
||||
validated_graph_->CalculatorInfos()[node_id_];
|
||||
RET_CHECK_LE(0, node_type_info.InputStreamBaseIndex());
|
||||
RET_CHECK_LE(0, node_type_info_->InputStreamBaseIndex());
|
||||
InputStreamManager* current_input_stream_managers =
|
||||
&input_stream_managers[node_type_info.InputStreamBaseIndex()];
|
||||
&input_stream_managers[node_type_info_->InputStreamBaseIndex()];
|
||||
MP_RETURN_IF_ERROR(input_stream_handler_->InitializeInputStreamManagers(
|
||||
current_input_stream_managers));
|
||||
|
||||
// Set all the mirrors.
|
||||
for (CollectionItemId id = node_type_info.InputStreamTypes().BeginId();
|
||||
id < node_type_info.InputStreamTypes().EndId(); ++id) {
|
||||
for (CollectionItemId id = node_type_info_->InputStreamTypes().BeginId();
|
||||
id < node_type_info_->InputStreamTypes().EndId(); ++id) {
|
||||
int output_stream_index =
|
||||
validated_graph_
|
||||
->InputStreamInfos()[node_type_info.InputStreamBaseIndex() +
|
||||
->InputStreamInfos()[node_type_info_->InputStreamBaseIndex() +
|
||||
id.value()]
|
||||
.upstream;
|
||||
RET_CHECK_LE(0, output_stream_index);
|
||||
@@ -287,7 +293,7 @@ absl::Status CalculatorNode::InitializeInputStreams(
|
||||
&output_stream_managers[output_stream_index];
|
||||
VLOG(2) << "Adding mirror for input stream with id " << id.value()
|
||||
<< " and flat index "
|
||||
<< node_type_info.InputStreamBaseIndex() + id.value()
|
||||
<< node_type_info_->InputStreamBaseIndex() + id.value()
|
||||
<< " which will be connected to output stream with flat index "
|
||||
<< output_stream_index;
|
||||
origin_output_stream_manager->AddMirror(input_stream_handler_.get(), id);
|
||||
@@ -391,10 +397,9 @@ absl::Status CalculatorNode::PrepareForRun(
|
||||
std::move(schedule_callback), error_callback);
|
||||
output_stream_handler_->PrepareForRun(error_callback);
|
||||
|
||||
const PacketTypeSet* packet_types =
|
||||
&validated_graph_->CalculatorInfos()[node_id_].InputSidePacketTypes();
|
||||
const auto& contract = node_type_info_->Contract();
|
||||
input_side_packet_types_ = RemoveOmittedPacketTypes(
|
||||
*packet_types, all_side_packets, validated_graph_);
|
||||
contract.InputSidePackets(), all_side_packets, validated_graph_);
|
||||
MP_RETURN_IF_ERROR(input_side_packet_handler_.PrepareForRun(
|
||||
input_side_packet_types_.get(), all_side_packets,
|
||||
[this]() { CalculatorNode::InputSidePacketsReady(); },
|
||||
@@ -404,8 +409,6 @@ absl::Status CalculatorNode::PrepareForRun(
|
||||
calculator_state_->SetOutputSidePackets(output_side_packets_.get());
|
||||
calculator_state_->SetCounterFactory(counter_factory);
|
||||
|
||||
const auto& contract =
|
||||
validated_graph_->CalculatorInfos()[node_id_].Contract();
|
||||
for (const auto& svc_req : contract.ServiceRequests()) {
|
||||
const auto& req = svc_req.second;
|
||||
auto it = service_packets.find(req.Service().key);
|
||||
|
||||
@@ -70,7 +70,9 @@ class CalculatorNode {
|
||||
CalculatorNode();
|
||||
CalculatorNode(const CalculatorNode&) = delete;
|
||||
CalculatorNode& operator=(const CalculatorNode&) = delete;
|
||||
int Id() const { return node_id_; }
|
||||
int Id() const {
|
||||
return node_type_info_ ? node_type_info_->Node().index : -1;
|
||||
}
|
||||
|
||||
// Returns a value according to which the scheduler queue determines the
|
||||
// relative priority between runnable source nodes; a smaller value means
|
||||
@@ -106,7 +108,7 @@ class CalculatorNode {
|
||||
// OutputSidePacketImpls corresponding to the output side packet indexes in
|
||||
// validated_graph.
|
||||
absl::Status Initialize(const ValidatedGraphConfig* validated_graph,
|
||||
int node_id,
|
||||
NodeTypeInfo::NodeRef node_ref,
|
||||
InputStreamManager* input_stream_managers,
|
||||
OutputStreamManager* output_stream_managers,
|
||||
OutputSidePacketImpl* output_side_packets,
|
||||
@@ -287,7 +289,6 @@ class CalculatorNode {
|
||||
// Keeps data which a Calculator subclass needs access to.
|
||||
std::unique_ptr<CalculatorState> calculator_state_;
|
||||
|
||||
int node_id_ = -1;
|
||||
std::string name_; // Optional user-defined name
|
||||
// Name of the executor which the node will execute on. If empty, the node
|
||||
// will execute on the default executor.
|
||||
@@ -372,6 +373,8 @@ class CalculatorNode {
|
||||
internal::SchedulerQueue* scheduler_queue_ = nullptr;
|
||||
|
||||
const ValidatedGraphConfig* validated_graph_ = nullptr;
|
||||
|
||||
const NodeTypeInfo* node_type_info_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace mediapipe
|
||||
|
||||
@@ -158,11 +158,11 @@ class CalculatorNodeTest : public ::testing::Test {
|
||||
input_side_packets_.emplace("input_a", Adopt(new int(42)));
|
||||
input_side_packets_.emplace("input_b", Adopt(new int(42)));
|
||||
|
||||
node_.reset(new CalculatorNode());
|
||||
node_ = absl::make_unique<CalculatorNode>();
|
||||
MP_ASSERT_OK(node_->Initialize(
|
||||
&validated_graph_, 2, input_stream_managers_.get(),
|
||||
output_stream_managers_.get(), output_side_packets_.get(),
|
||||
&buffer_size_hint_, graph_profiler_));
|
||||
&validated_graph_, {NodeTypeInfo::NodeType::CALCULATOR, 2},
|
||||
input_stream_managers_.get(), output_stream_managers_.get(),
|
||||
output_side_packets_.get(), &buffer_size_hint_, graph_profiler_));
|
||||
}
|
||||
|
||||
absl::Status PrepareNodeForRun() {
|
||||
|
||||
@@ -30,6 +30,14 @@ bzl_library(
|
||||
visibility = ["//mediapipe/framework:__subpackages__"],
|
||||
)
|
||||
|
||||
bzl_library(
|
||||
name = "descriptor_set_bzl",
|
||||
srcs = [
|
||||
"descriptor_set.bzl",
|
||||
],
|
||||
visibility = ["//mediapipe/framework:__subpackages__"],
|
||||
)
|
||||
|
||||
proto_library(
|
||||
name = "proto_descriptor_proto",
|
||||
srcs = ["proto_descriptor.proto"],
|
||||
@@ -281,7 +289,8 @@ cc_library(
|
||||
# Use this library through "mediapipe/framework/port:gtest_main".
|
||||
visibility = ["//mediapipe/framework/port:__pkg__"],
|
||||
deps = [
|
||||
":status",
|
||||
"//mediapipe/framework/port:statusor",
|
||||
"@com_google_absl//absl/status",
|
||||
"@com_google_googletest//:gtest",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
"""Outputs a FileDescriptorSet with all transitive dependencies.
|
||||
Copied from tools/build_defs/proto/descriptor_set.bzl.
|
||||
"""
|
||||
|
||||
TransitiveDescriptorInfo = provider(
|
||||
"The transitive descriptors from a set of protos.",
|
||||
fields = ["descriptors"],
|
||||
)
|
||||
|
||||
DirectDescriptorInfo = provider(
|
||||
"The direct descriptors from a set of protos.",
|
||||
fields = ["descriptors"],
|
||||
)
|
||||
|
||||
def calculate_transitive_descriptor_set(actions, deps, output):
|
||||
"""Calculates the transitive dependencies of the deps.
|
||||
|
||||
Args:
|
||||
actions: the actions (typically ctx.actions) used to run commands
|
||||
deps: the deps to get the transitive dependencies of
|
||||
output: the output file the data will be written to
|
||||
|
||||
Returns:
|
||||
The same output file passed as the input arg, for convenience.
|
||||
"""
|
||||
|
||||
# Join all proto descriptors in a single file.
|
||||
transitive_descriptor_sets = depset(transitive = [
|
||||
dep[ProtoInfo].transitive_descriptor_sets if ProtoInfo in dep else dep[TransitiveDescriptorInfo].descriptors
|
||||
for dep in deps
|
||||
])
|
||||
args = actions.args()
|
||||
args.use_param_file(param_file_arg = "--arg-file=%s")
|
||||
args.add_all(transitive_descriptor_sets)
|
||||
|
||||
# Because `xargs` must take its arguments before the command to execute,
|
||||
# we cannot simply put a reference to the argument list at the end, as in the
|
||||
# case of param file spooling, since the entire argument list will get
|
||||
# replaced by "--arg-file=bazel-out/..." which needs to be an `xargs`
|
||||
# argument rather than a `cat` argument.
|
||||
#
|
||||
# We look to see if the first argument begins with a '--arg-file=' and
|
||||
# selectively choose xargs vs. just supplying the arguments to `cat`.
|
||||
actions.run_shell(
|
||||
outputs = [output],
|
||||
inputs = transitive_descriptor_sets,
|
||||
progress_message = "Joining descriptors.",
|
||||
command = ("if [[ \"$1\" =~ ^--arg-file=.* ]]; then xargs \"$1\" cat; " +
|
||||
"else cat \"$@\"; fi >{output}".format(output = output.path)),
|
||||
arguments = [args],
|
||||
)
|
||||
return output
|
||||
|
||||
def _transitive_descriptor_set_impl(ctx):
|
||||
"""Combine descriptors for all transitive proto dependencies into one file.
|
||||
|
||||
Warning: Concatenating all of the descriptor files with a single `cat` command
|
||||
could exceed system limits (1MB+). For example, a dependency on gwslog.proto
|
||||
will trigger this edge case.
|
||||
|
||||
When writing new code, prefer to accept a list of descriptor files instead of
|
||||
just one so that this limitation won't impact you.
|
||||
"""
|
||||
output = ctx.actions.declare_file(ctx.attr.name + "-transitive-descriptor-set.proto.bin")
|
||||
calculate_transitive_descriptor_set(ctx.actions, ctx.attr.deps, output)
|
||||
return DefaultInfo(
|
||||
files = depset([output]),
|
||||
runfiles = ctx.runfiles(files = [output]),
|
||||
)
|
||||
|
||||
# transitive_descriptor_set outputs a single file containing a binary
|
||||
# FileDescriptorSet with all transitive dependencies of the given proto
|
||||
# dependencies.
|
||||
#
|
||||
# Example usage:
|
||||
#
|
||||
# transitive_descriptor_set(
|
||||
# name = "my_descriptors",
|
||||
# deps = [":my_proto"],
|
||||
# )
|
||||
transitive_descriptor_set = rule(
|
||||
attrs = {
|
||||
"deps": attr.label_list(providers = [[ProtoInfo], [TransitiveDescriptorInfo]]),
|
||||
},
|
||||
outputs = {
|
||||
"out": "%{name}-transitive-descriptor-set.proto.bin",
|
||||
},
|
||||
implementation = _transitive_descriptor_set_impl,
|
||||
)
|
||||
|
||||
def calculate_direct_descriptor_set(actions, deps, output):
|
||||
"""Calculates the direct dependencies of the deps.
|
||||
|
||||
Args:
|
||||
actions: the actions (typically ctx.actions) used to run commands
|
||||
deps: the deps to get the direct dependencies of
|
||||
output: the output file the data will be written to
|
||||
|
||||
Returns:
|
||||
The same output file passed as the input arg, for convenience.
|
||||
"""
|
||||
descriptor_set = depset(
|
||||
[dep[ProtoInfo].direct_descriptor_set for dep in deps if ProtoInfo in dep],
|
||||
transitive = [dep[DirectDescriptorInfo].descriptors for dep in deps if ProtoInfo not in dep],
|
||||
)
|
||||
|
||||
actions.run_shell(
|
||||
outputs = [output],
|
||||
inputs = descriptor_set,
|
||||
progress_message = "Joining direct descriptors.",
|
||||
command = ("cat %s > %s") % (
|
||||
" ".join([d.path for d in descriptor_set.to_list()]),
|
||||
output.path,
|
||||
),
|
||||
)
|
||||
return output
|
||||
|
||||
def _direct_descriptor_set_impl(ctx):
|
||||
calculate_direct_descriptor_set(ctx.actions, ctx.attr.deps, ctx.outputs.out)
|
||||
|
||||
# direct_descriptor_set outputs a single file containing a binary
|
||||
# FileDescriptorSet with all direct, non transitive dependencies of
|
||||
# the given proto dependencies.
|
||||
#
|
||||
# Example usage:
|
||||
#
|
||||
# direct_descriptor_set(
|
||||
# name = "my_direct_descriptors",
|
||||
# deps = [":my_proto"],
|
||||
# )
|
||||
direct_descriptor_set = rule(
|
||||
attrs = {
|
||||
"deps": attr.label_list(providers = [[ProtoInfo], [DirectDescriptorInfo]]),
|
||||
},
|
||||
outputs = {
|
||||
"out": "%{name}-direct-descriptor-set.proto.bin",
|
||||
},
|
||||
implementation = _direct_descriptor_set_impl,
|
||||
)
|
||||
@@ -15,48 +15,74 @@
|
||||
#ifndef MEDIAPIPE_DEPS_MESSAGE_MATCHERS_H_
|
||||
#define MEDIAPIPE_DEPS_MESSAGE_MATCHERS_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "mediapipe/framework/port/core_proto_inc.h"
|
||||
#include "mediapipe/framework/port/gmock.h"
|
||||
|
||||
namespace mediapipe {
|
||||
|
||||
namespace internal {
|
||||
bool EqualsMessage(const proto_ns::MessageLite& m_1,
|
||||
const proto_ns::MessageLite& m_2) {
|
||||
std::string s_1, s_2;
|
||||
m_1.SerializeToString(&s_1);
|
||||
m_2.SerializeToString(&s_2);
|
||||
return s_1 == s_2;
|
||||
}
|
||||
} // namespace internal
|
||||
|
||||
template <typename MessageType>
|
||||
class ProtoMatcher : public testing::MatcherInterface<MessageType> {
|
||||
using MatchResultListener = testing::MatchResultListener;
|
||||
|
||||
class ProtoMatcher {
|
||||
public:
|
||||
explicit ProtoMatcher(const MessageType& message) : message_(message) {}
|
||||
virtual bool MatchAndExplain(MessageType m, MatchResultListener*) const {
|
||||
return internal::EqualsMessage(message_, m);
|
||||
using is_gtest_matcher = void;
|
||||
using MessageType = proto_ns::MessageLite;
|
||||
|
||||
explicit ProtoMatcher(const MessageType& message)
|
||||
: message_(CloneMessage(message)) {}
|
||||
|
||||
bool MatchAndExplain(const MessageType& m,
|
||||
testing::MatchResultListener*) const {
|
||||
return EqualsMessage(*message_, m);
|
||||
}
|
||||
bool MatchAndExplain(const MessageType* m,
|
||||
testing::MatchResultListener*) const {
|
||||
return EqualsMessage(*message_, *m);
|
||||
}
|
||||
|
||||
virtual void DescribeTo(::std::ostream* os) const {
|
||||
#if defined(MEDIAPIPE_PROTO_LITE)
|
||||
*os << "Protobuf messages have identical serializations.";
|
||||
#else
|
||||
*os << message_.DebugString();
|
||||
#endif
|
||||
void DescribeTo(std::ostream* os) const {
|
||||
*os << "has the same serialization as " << ExpectedMessageDescription();
|
||||
}
|
||||
|
||||
void DescribeNegationTo(std::ostream* os) const {
|
||||
*os << "does not have the same serialization as "
|
||||
<< ExpectedMessageDescription();
|
||||
}
|
||||
|
||||
private:
|
||||
const MessageType message_;
|
||||
std::unique_ptr<MessageType> CloneMessage(const MessageType& message) {
|
||||
std::unique_ptr<MessageType> clone(message.New());
|
||||
clone->CheckTypeAndMergeFrom(message);
|
||||
return clone;
|
||||
}
|
||||
|
||||
bool EqualsMessage(const proto_ns::MessageLite& m_1,
|
||||
const proto_ns::MessageLite& m_2) const {
|
||||
std::string s_1, s_2;
|
||||
m_1.SerializeToString(&s_1);
|
||||
m_2.SerializeToString(&s_2);
|
||||
return s_1 == s_2;
|
||||
}
|
||||
|
||||
std::string ExpectedMessageDescription() const {
|
||||
#if defined(MEDIAPIPE_PROTO_LITE)
|
||||
return "the expected message";
|
||||
#else
|
||||
return message_->DebugString();
|
||||
#endif
|
||||
}
|
||||
|
||||
const std::shared_ptr<MessageType> message_;
|
||||
};
|
||||
|
||||
template <typename MessageType>
|
||||
inline testing::PolymorphicMatcher<ProtoMatcher<MessageType>> EqualsProto(
|
||||
const MessageType& message) {
|
||||
return testing::PolymorphicMatcher<ProtoMatcher<MessageType>>(
|
||||
ProtoMatcher<MessageType>(message));
|
||||
inline ProtoMatcher EqualsProto(const proto_ns::MessageLite& message) {
|
||||
return ProtoMatcher(message);
|
||||
}
|
||||
|
||||
// for Pointwise
|
||||
MATCHER(EqualsProto, "") {
|
||||
const auto& a = ::testing::get<0>(arg);
|
||||
const auto& b = ::testing::get<1>(arg);
|
||||
return ::testing::ExplainMatchResult(EqualsProto(b), a, result_listener);
|
||||
}
|
||||
|
||||
} // namespace mediapipe
|
||||
|
||||
@@ -15,24 +15,102 @@
|
||||
#ifndef MEDIAPIPE_DEPS_STATUS_MATCHERS_H_
|
||||
#define MEDIAPIPE_DEPS_STATUS_MATCHERS_H_
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "mediapipe/framework/deps/status.h"
|
||||
#include "mediapipe/framework/port/statusor.h"
|
||||
|
||||
namespace mediapipe {
|
||||
|
||||
inline const ::absl::Status& GetStatus(const ::absl::Status& status) {
|
||||
return status;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline const ::absl::Status& GetStatus(const ::absl::StatusOr<T>& status) {
|
||||
return status.status();
|
||||
}
|
||||
|
||||
// Monomorphic implementation of matcher IsOkAndHolds(m). StatusOrType is a
|
||||
// reference to StatusOr<T>.
|
||||
template <typename StatusOrType>
|
||||
class IsOkAndHoldsMatcherImpl
|
||||
: public ::testing::MatcherInterface<StatusOrType> {
|
||||
public:
|
||||
typedef
|
||||
typename std::remove_reference<StatusOrType>::type::value_type value_type;
|
||||
|
||||
template <typename InnerMatcher>
|
||||
explicit IsOkAndHoldsMatcherImpl(InnerMatcher&& inner_matcher)
|
||||
: inner_matcher_(::testing::SafeMatcherCast<const value_type&>(
|
||||
std::forward<InnerMatcher>(inner_matcher))) {}
|
||||
|
||||
void DescribeTo(std::ostream* os) const override {
|
||||
*os << "is OK and has a value that ";
|
||||
inner_matcher_.DescribeTo(os);
|
||||
}
|
||||
|
||||
void DescribeNegationTo(std::ostream* os) const override {
|
||||
*os << "isn't OK or has a value that ";
|
||||
inner_matcher_.DescribeNegationTo(os);
|
||||
}
|
||||
|
||||
bool MatchAndExplain(
|
||||
StatusOrType actual_value,
|
||||
::testing::MatchResultListener* result_listener) const override {
|
||||
if (!actual_value.ok()) {
|
||||
*result_listener << "which has status " << actual_value.status();
|
||||
return false;
|
||||
}
|
||||
|
||||
::testing::StringMatchResultListener inner_listener;
|
||||
const bool matches =
|
||||
inner_matcher_.MatchAndExplain(*actual_value, &inner_listener);
|
||||
const std::string inner_explanation = inner_listener.str();
|
||||
if (!inner_explanation.empty()) {
|
||||
*result_listener << "which contains value "
|
||||
<< ::testing::PrintToString(*actual_value) << ", "
|
||||
<< inner_explanation;
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
private:
|
||||
const ::testing::Matcher<const value_type&> inner_matcher_;
|
||||
};
|
||||
|
||||
// Implements IsOkAndHolds(m) as a polymorphic matcher.
|
||||
template <typename InnerMatcher>
|
||||
class IsOkAndHoldsMatcher {
|
||||
public:
|
||||
explicit IsOkAndHoldsMatcher(InnerMatcher inner_matcher)
|
||||
: inner_matcher_(std::move(inner_matcher)) {}
|
||||
|
||||
// Converts this polymorphic matcher to a monomorphic matcher of the
|
||||
// given type. StatusOrType can be either StatusOr<T> or a
|
||||
// reference to StatusOr<T>.
|
||||
template <typename StatusOrType>
|
||||
operator ::testing::Matcher<StatusOrType>() const { // NOLINT
|
||||
return ::testing::Matcher<StatusOrType>(
|
||||
new IsOkAndHoldsMatcherImpl<const StatusOrType&>(inner_matcher_));
|
||||
}
|
||||
|
||||
private:
|
||||
const InnerMatcher inner_matcher_;
|
||||
};
|
||||
|
||||
// Monomorphic implementation of matcher IsOk() for a given type T.
|
||||
// T can be Status, StatusOr<>, or a reference to either of them.
|
||||
template <typename T>
|
||||
class MonoIsOkMatcherImpl : public testing::MatcherInterface<T> {
|
||||
class MonoIsOkMatcherImpl : public ::testing::MatcherInterface<T> {
|
||||
public:
|
||||
void DescribeTo(std::ostream* os) const override { *os << "is OK"; }
|
||||
void DescribeNegationTo(std::ostream* os) const override {
|
||||
*os << "is not OK";
|
||||
}
|
||||
bool MatchAndExplain(T actual_value,
|
||||
testing::MatchResultListener*) const override {
|
||||
return actual_value.ok();
|
||||
::testing::MatchResultListener*) const override {
|
||||
return GetStatus(actual_value).ok();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -40,11 +118,20 @@ class MonoIsOkMatcherImpl : public testing::MatcherInterface<T> {
|
||||
class IsOkMatcher {
|
||||
public:
|
||||
template <typename T>
|
||||
operator testing::Matcher<T>() const { // NOLINT
|
||||
return testing::Matcher<T>(new MonoIsOkMatcherImpl<T>());
|
||||
operator ::testing::Matcher<T>() const { // NOLINT
|
||||
return ::testing::Matcher<T>(new MonoIsOkMatcherImpl<T>());
|
||||
}
|
||||
};
|
||||
|
||||
// Returns a gMock matcher that matches a StatusOr<> whose status is
|
||||
// OK and whose value matches the inner matcher.
|
||||
template <typename InnerMatcher>
|
||||
IsOkAndHoldsMatcher<typename std::decay<InnerMatcher>::type> IsOkAndHolds(
|
||||
InnerMatcher&& inner_matcher) {
|
||||
return IsOkAndHoldsMatcher<typename std::decay<InnerMatcher>::type>(
|
||||
std::forward<InnerMatcher>(inner_matcher));
|
||||
}
|
||||
|
||||
// Returns a gMock matcher that matches a Status or StatusOr<> which is OK.
|
||||
inline IsOkMatcher IsOk() { return IsOkMatcher(); }
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ mediapipe_register_type(
|
||||
types = [
|
||||
"::mediapipe::Classification",
|
||||
"::mediapipe::ClassificationList",
|
||||
"::mediapipe::ClassificationListCollection",
|
||||
"::std::vector<::mediapipe::Classification>",
|
||||
"::std::vector<::mediapipe::ClassificationList>",
|
||||
],
|
||||
@@ -262,8 +263,10 @@ mediapipe_register_type(
|
||||
types = [
|
||||
"::mediapipe::Landmark",
|
||||
"::mediapipe::LandmarkList",
|
||||
"::mediapipe::LandmarkListCollection",
|
||||
"::mediapipe::NormalizedLandmark",
|
||||
"::mediapipe::NormalizedLandmarkList",
|
||||
"::mediapipe::NormalizedLandmarkListCollection",
|
||||
"::std::vector<::mediapipe::Landmark>",
|
||||
"::std::vector<::mediapipe::LandmarkList>",
|
||||
"::std::vector<::mediapipe::NormalizedLandmark>",
|
||||
|
||||
@@ -39,3 +39,8 @@ message Classification {
|
||||
message ClassificationList {
|
||||
repeated Classification classification = 1;
|
||||
}
|
||||
|
||||
// Group of ClassificationList protos.
|
||||
message ClassificationListCollection {
|
||||
repeated ClassificationList classification_list = 1;
|
||||
}
|
||||
|
||||
@@ -47,6 +47,11 @@ message LandmarkList {
|
||||
repeated Landmark landmark = 1;
|
||||
}
|
||||
|
||||
// Group of LandmarkList protos.
|
||||
message LandmarkListCollection {
|
||||
repeated LandmarkList landmark_list = 1;
|
||||
}
|
||||
|
||||
// A normalized version of above Landmark proto. All coordinates should be
|
||||
// within [0, 1].
|
||||
message NormalizedLandmark {
|
||||
@@ -61,3 +66,8 @@ message NormalizedLandmark {
|
||||
message NormalizedLandmarkList {
|
||||
repeated NormalizedLandmark landmark = 1;
|
||||
}
|
||||
|
||||
// Group of NormalizedLandmarkList protos.
|
||||
message NormalizedLandmarkListCollection {
|
||||
repeated NormalizedLandmarkList landmark_list = 1;
|
||||
}
|
||||
|
||||
@@ -428,37 +428,37 @@ Tensor::CpuReadView Tensor::GetCpuReadView() const {
|
||||
} else
|
||||
#endif // MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_31
|
||||
|
||||
// Transfer data from texture if not transferred from SSBO/MTLBuffer
|
||||
// yet.
|
||||
if (valid_ & kValidOpenGlTexture2d) {
|
||||
gl_context_->Run([this]() {
|
||||
const int padded_size =
|
||||
texture_height_ * texture_width_ * 4 * element_size();
|
||||
auto temp_buffer = absl::make_unique<uint8_t[]>(padded_size);
|
||||
uint8_t* buffer = temp_buffer.get();
|
||||
// Transfer data from texture if not transferred from SSBO/MTLBuffer
|
||||
// yet.
|
||||
if (valid_ & kValidOpenGlTexture2d) {
|
||||
gl_context_->Run([this]() {
|
||||
const int padded_size =
|
||||
texture_height_ * texture_width_ * 4 * element_size();
|
||||
auto temp_buffer = absl::make_unique<uint8_t[]>(padded_size);
|
||||
uint8_t* buffer = temp_buffer.get();
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, frame_buffer_);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D, opengl_texture2d_, 0);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 4);
|
||||
glReadPixels(0, 0, texture_width_, texture_height_, GL_RGBA, GL_FLOAT,
|
||||
buffer);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, frame_buffer_);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D, opengl_texture2d_, 0);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 4);
|
||||
glReadPixels(0, 0, texture_width_, texture_height_, GL_RGBA, GL_FLOAT,
|
||||
buffer);
|
||||
|
||||
uint8_t* dest_buffer = reinterpret_cast<uint8_t*>(cpu_buffer_);
|
||||
const int actual_depth_size =
|
||||
BhwcDepthFromShape(shape_) * element_size();
|
||||
const int num_slices = (BhwcDepthFromShape(shape_) + 3) / 4;
|
||||
const int padded_depth_size = num_slices * 4 * element_size();
|
||||
const int num_elements = BhwcWidthFromShape(shape_) *
|
||||
BhwcHeightFromShape(shape_) *
|
||||
BhwcBatchFromShape(shape_);
|
||||
for (int e = 0; e < num_elements; e++) {
|
||||
std::memcpy(dest_buffer, buffer, actual_depth_size);
|
||||
dest_buffer += actual_depth_size;
|
||||
buffer += padded_depth_size;
|
||||
}
|
||||
});
|
||||
}
|
||||
uint8_t* dest_buffer = reinterpret_cast<uint8_t*>(cpu_buffer_);
|
||||
const int actual_depth_size =
|
||||
BhwcDepthFromShape(shape_) * element_size();
|
||||
const int num_slices = (BhwcDepthFromShape(shape_) + 3) / 4;
|
||||
const int padded_depth_size = num_slices * 4 * element_size();
|
||||
const int num_elements = BhwcWidthFromShape(shape_) *
|
||||
BhwcHeightFromShape(shape_) *
|
||||
BhwcBatchFromShape(shape_);
|
||||
for (int e = 0; e < num_elements; e++) {
|
||||
std::memcpy(dest_buffer, buffer, actual_depth_size);
|
||||
dest_buffer += actual_depth_size;
|
||||
buffer += padded_depth_size;
|
||||
}
|
||||
});
|
||||
}
|
||||
#endif // MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_30
|
||||
valid_ |= kValidCpu;
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ const proto_ns::MessageLite& Packet::GetProtoMessageLite() const {
|
||||
}
|
||||
|
||||
StatusOr<std::vector<const proto_ns::MessageLite*>>
|
||||
Packet::GetVectorOfProtoMessageLitePtrs() {
|
||||
Packet::GetVectorOfProtoMessageLitePtrs() const {
|
||||
if (holder_ == nullptr) {
|
||||
return absl::InternalError("Packet is empty.");
|
||||
}
|
||||
|
||||
@@ -175,7 +175,7 @@ class Packet {
|
||||
// Note: This function is meant to be used internally within the MediaPipe
|
||||
// framework only.
|
||||
StatusOr<std::vector<const proto_ns::MessageLite*>>
|
||||
GetVectorOfProtoMessageLitePtrs();
|
||||
GetVectorOfProtoMessageLitePtrs() const;
|
||||
|
||||
// Returns an error if the packet does not contain data of type T.
|
||||
template <typename T>
|
||||
@@ -391,7 +391,7 @@ class HolderBase {
|
||||
// underlying object is a vector of protocol buffer objects, otherwise,
|
||||
// returns an error.
|
||||
virtual StatusOr<std::vector<const proto_ns::MessageLite*>>
|
||||
GetVectorOfProtoMessageLite() = 0;
|
||||
GetVectorOfProtoMessageLite() const = 0;
|
||||
|
||||
private:
|
||||
size_t type_id_;
|
||||
@@ -563,7 +563,7 @@ class Holder : public HolderBase {
|
||||
// underlying object is a vector of protocol buffer objects, otherwise,
|
||||
// returns an error.
|
||||
StatusOr<std::vector<const proto_ns::MessageLite*>>
|
||||
GetVectorOfProtoMessageLite() override {
|
||||
GetVectorOfProtoMessageLite() const override {
|
||||
return ConvertToVectorOfProtoMessageLitePtrs(ptr_, is_proto_vector<T>());
|
||||
}
|
||||
|
||||
|
||||
@@ -370,7 +370,8 @@ absl::Status PacketGeneratorGraph::Initialize(
|
||||
|
||||
absl::Status PacketGeneratorGraph::RunGraphSetup(
|
||||
const std::map<std::string, Packet>& input_side_packets,
|
||||
std::map<std::string, Packet>* output_side_packets) const {
|
||||
std::map<std::string, Packet>* output_side_packets,
|
||||
std::vector<int>* non_scheduled_generators) const {
|
||||
*output_side_packets = base_packets_;
|
||||
for (const std::pair<const std::string, Packet>& item : input_side_packets) {
|
||||
auto iter = output_side_packets->find(item.first);
|
||||
@@ -380,7 +381,9 @@ absl::Status PacketGeneratorGraph::RunGraphSetup(
|
||||
}
|
||||
output_side_packets->insert(iter, item);
|
||||
}
|
||||
std::vector<int> non_scheduled_generators;
|
||||
std::vector<int> non_scheduled_generators_local;
|
||||
if (!non_scheduled_generators)
|
||||
non_scheduled_generators = &non_scheduled_generators_local;
|
||||
|
||||
MP_RETURN_IF_ERROR(
|
||||
validated_graph_->CanAcceptSidePackets(input_side_packets));
|
||||
@@ -389,11 +392,7 @@ absl::Status PacketGeneratorGraph::RunGraphSetup(
|
||||
MP_RETURN_IF_ERROR(
|
||||
validated_graph_->ValidateRequiredSidePackets(*output_side_packets));
|
||||
MP_RETURN_IF_ERROR(ExecuteGenerators(
|
||||
output_side_packets, &non_scheduled_generators, /*initial=*/false));
|
||||
RET_CHECK(non_scheduled_generators.empty())
|
||||
<< "Some Generators were unrunnable (validation should have failed).\n"
|
||||
"Generator indexes: "
|
||||
<< absl::StrJoin(non_scheduled_generators, ", ");
|
||||
output_side_packets, non_scheduled_generators, /*initial=*/false));
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
|
||||
@@ -76,7 +76,8 @@ class PacketGeneratorGraph {
|
||||
// must now be runnable) to produce output_side_packets.
|
||||
virtual absl::Status RunGraphSetup(
|
||||
const std::map<std::string, Packet>& input_side_packets,
|
||||
std::map<std::string, Packet>* output_side_packets) const;
|
||||
std::map<std::string, Packet>* output_side_packets,
|
||||
std::vector<int>* non_scheduled_generators = nullptr) const;
|
||||
|
||||
// Get the base packets: the packets which are produced when Initialize
|
||||
// is called.
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "mediapipe/framework/deps/message_matchers.h"
|
||||
#include "mediapipe/framework/packet_test.pb.h"
|
||||
#include "mediapipe/framework/port/core_proto_inc.h"
|
||||
#include "mediapipe/framework/port/gmock.h"
|
||||
@@ -214,6 +215,21 @@ TEST(PacketTest, ValidateAsProtoMessageLite) {
|
||||
EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
|
||||
}
|
||||
|
||||
TEST(PacketTest, GetVectorOfProtos) {
|
||||
std::vector<mediapipe::PacketTestProto> protos(2);
|
||||
protos[0].add_x(123);
|
||||
protos[1].add_x(456);
|
||||
// Normally we'd move here, but we copy to use the protos for comparison.
|
||||
const Packet packet =
|
||||
MakePacket<std::vector<mediapipe::PacketTestProto>>(protos);
|
||||
auto maybe_proto_ptrs = packet.GetVectorOfProtoMessageLitePtrs();
|
||||
EXPECT_THAT(maybe_proto_ptrs,
|
||||
IsOkAndHolds(testing::Pointwise(EqualsProto(), protos)));
|
||||
|
||||
const Packet wrong = MakePacket<int>(1);
|
||||
EXPECT_THAT(wrong.GetVectorOfProtoMessageLitePtrs(), testing::Not(IsOk()));
|
||||
}
|
||||
|
||||
TEST(PacketTest, SyncedPacket) {
|
||||
Packet synced_packet = AdoptAsSyncedPacket(new int(100));
|
||||
Packet value_packet =
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
""".bzl file for mediapipe open source build configs."""
|
||||
|
||||
load("@com_google_protobuf//:protobuf.bzl", "cc_proto_library", "py_proto_library")
|
||||
load("//mediapipe/framework/tool:mediapipe_graph.bzl", "mediapipe_options_library")
|
||||
|
||||
def provided_args(**kwargs):
|
||||
"""Returns the keyword arguments omitting None arguments."""
|
||||
@@ -47,6 +48,7 @@ def mediapipe_proto_library(
|
||||
def_objc_proto = True,
|
||||
def_java_proto = True,
|
||||
def_jspb_proto = True,
|
||||
def_options_lib = True,
|
||||
portable_deps = None):
|
||||
"""Defines the proto_library targets needed for all mediapipe platforms.
|
||||
|
||||
@@ -67,6 +69,7 @@ def mediapipe_proto_library(
|
||||
def_objc_proto: define the objc_proto_library target
|
||||
def_java_proto: define the java_proto_library target
|
||||
def_jspb_proto: define the jspb_proto_library target
|
||||
def_options_lib: define the mediapipe_options_library target
|
||||
"""
|
||||
_ignore = [def_portable_proto, def_objc_proto, def_java_proto, def_jspb_proto, portable_deps]
|
||||
|
||||
@@ -116,6 +119,17 @@ def mediapipe_proto_library(
|
||||
compatible_with = compatible_with,
|
||||
))
|
||||
|
||||
if def_options_lib:
|
||||
cc_deps = replace_deps(deps, "_proto", "_cc_proto")
|
||||
mediapipe_options_library(**provided_args(
|
||||
name = replace_suffix(name, "_proto", "_options_lib"),
|
||||
proto_lib = name,
|
||||
deps = cc_deps,
|
||||
visibility = visibility,
|
||||
testonly = testonly,
|
||||
compatible_with = compatible_with,
|
||||
))
|
||||
|
||||
def mediapipe_py_proto_library(
|
||||
name,
|
||||
srcs,
|
||||
|
||||
@@ -113,6 +113,7 @@ cc_library(
|
||||
"//mediapipe/framework/port:advanced_proto_lite",
|
||||
"//mediapipe/framework/port:integral_types",
|
||||
"//mediapipe/framework/port:logging",
|
||||
"//mediapipe/framework/port:re2",
|
||||
"//mediapipe/framework/port:ret_check",
|
||||
"//mediapipe/framework/port:status",
|
||||
"//mediapipe/framework/tool:name_util",
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "mediapipe/framework/port/canonical_errors.h"
|
||||
#include "mediapipe/framework/port/logging.h"
|
||||
#include "mediapipe/framework/port/proto_ns.h"
|
||||
#include "mediapipe/framework/port/re2.h"
|
||||
#include "mediapipe/framework/port/ret_check.h"
|
||||
#include "mediapipe/framework/port/status.h"
|
||||
#include "mediapipe/framework/profiler/profiler_resource_util.h"
|
||||
@@ -71,6 +72,8 @@ bool IsTracerEnabled(const ProfilerConfig& profiler_config) {
|
||||
}
|
||||
|
||||
// Returns true if trace events are written to a log file.
|
||||
// Note that for now, file output is only for graph-trace and not for
|
||||
// calculator-profile.
|
||||
bool IsTraceLogEnabled(const ProfilerConfig& profiler_config) {
|
||||
return IsTracerEnabled(profiler_config) &&
|
||||
!profiler_config.trace_log_disabled();
|
||||
@@ -117,6 +120,39 @@ PacketInfo* GetPacketInfo(PacketInfoMap* map, const PacketId& packet_id) {
|
||||
|
||||
} // namespace
|
||||
|
||||
// Builds GraphProfile records from profiler timing data.
|
||||
class GraphProfiler::GraphProfileBuilder {
|
||||
public:
|
||||
GraphProfileBuilder(GraphProfiler* profiler)
|
||||
: profiler_(profiler), calculator_regex_(".*") {
|
||||
auto& filter = profiler_->profiler_config().calculator_filter();
|
||||
calculator_regex_ = filter.empty() ? calculator_regex_ : RE2(filter);
|
||||
}
|
||||
|
||||
bool ProfileIncluded(const CalculatorProfile& p) {
|
||||
return RE2::FullMatch(p.name(), calculator_regex_);
|
||||
}
|
||||
|
||||
private:
|
||||
GraphProfiler* profiler_;
|
||||
RE2 calculator_regex_;
|
||||
};
|
||||
|
||||
GraphProfiler::GraphProfiler()
|
||||
: is_initialized_(false),
|
||||
is_profiling_(false),
|
||||
calculator_profiles_(1000),
|
||||
packets_info_(1000),
|
||||
is_running_(false),
|
||||
previous_log_end_time_(absl::InfinitePast()),
|
||||
previous_log_index_(-1),
|
||||
validated_graph_(nullptr) {
|
||||
clock_ = std::shared_ptr<mediapipe::Clock>(
|
||||
mediapipe::MonotonicClock::CreateSynchronizedMonotonicClock());
|
||||
}
|
||||
|
||||
GraphProfiler::~GraphProfiler() {}
|
||||
|
||||
void GraphProfiler::Initialize(
|
||||
const ValidatedGraphConfig& validated_graph_config) {
|
||||
absl::WriterMutexLock lock(&profiler_mutex_);
|
||||
@@ -156,6 +192,7 @@ void GraphProfiler::Initialize(
|
||||
CHECK(iter.second) << absl::Substitute(
|
||||
"Calculator \"$0\" has already been added.", node_name);
|
||||
}
|
||||
profile_builder_ = std::make_unique<GraphProfileBuilder>(this);
|
||||
is_initialized_ = true;
|
||||
}
|
||||
|
||||
@@ -554,15 +591,43 @@ class OstreamStream : public proto_ns::io::ZeroCopyOutputStream {
|
||||
};
|
||||
|
||||
// Sets the canonical node name in each CalculatorGraphConfig::Node
|
||||
// and also in GraphTrace.
|
||||
// and also in the GraphTrace if present.
|
||||
void AssignNodeNames(GraphProfile* profile) {
|
||||
CalculatorGraphConfig* graph_config = profile->mutable_config();
|
||||
GraphTrace* graph_trace = profile->mutable_graph_trace(0);
|
||||
graph_trace->clear_calculator_name();
|
||||
GraphTrace* graph_trace = profile->graph_trace_size() > 0
|
||||
? profile->mutable_graph_trace(0)
|
||||
: nullptr;
|
||||
if (graph_trace) {
|
||||
graph_trace->clear_calculator_name();
|
||||
}
|
||||
for (int i = 0; i < graph_config->node().size(); ++i) {
|
||||
std::string node_name = CanonicalNodeName(*graph_config, i);
|
||||
graph_config->mutable_node(i)->set_name(node_name);
|
||||
graph_trace->add_calculator_name(node_name);
|
||||
if (graph_trace) {
|
||||
graph_trace->add_calculator_name(node_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clears fields containing their default values.
|
||||
void CleanTimeHistogram(TimeHistogram* histogram) {
|
||||
if (histogram->num_intervals() == 1) {
|
||||
histogram->clear_num_intervals();
|
||||
}
|
||||
if (histogram->interval_size_usec() == 1000000) {
|
||||
histogram->clear_interval_size_usec();
|
||||
}
|
||||
}
|
||||
|
||||
// Clears fields containing their default values.
|
||||
void CleanCalculatorProfiles(GraphProfile* profile) {
|
||||
for (CalculatorProfile& p : *profile->mutable_calculator_profiles()) {
|
||||
CleanTimeHistogram(p.mutable_process_runtime());
|
||||
CleanTimeHistogram(p.mutable_process_input_latency());
|
||||
CleanTimeHistogram(p.mutable_process_output_latency());
|
||||
for (StreamProfile& s : *p.mutable_input_stream_profiles()) {
|
||||
CleanTimeHistogram(s.mutable_latency());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -588,11 +653,13 @@ absl::Status GraphProfiler::CaptureProfile(GraphProfile* result) {
|
||||
absl::Time end_time =
|
||||
clock_->TimeNow() -
|
||||
absl::Microseconds(profiler_config_.trace_log_margin_usec());
|
||||
GraphTrace* trace = result->add_graph_trace();
|
||||
if (!profiler_config_.trace_log_instant_events()) {
|
||||
tracer()->GetTrace(previous_log_end_time_, end_time, trace);
|
||||
} else {
|
||||
tracer()->GetLog(previous_log_end_time_, end_time, trace);
|
||||
if (tracer()) {
|
||||
GraphTrace* trace = result->add_graph_trace();
|
||||
if (!profiler_config_.trace_log_instant_events()) {
|
||||
tracer()->GetTrace(previous_log_end_time_, end_time, trace);
|
||||
} else {
|
||||
tracer()->GetLog(previous_log_end_time_, end_time, trace);
|
||||
}
|
||||
}
|
||||
previous_log_end_time_ = end_time;
|
||||
|
||||
@@ -601,9 +668,12 @@ absl::Status GraphProfiler::CaptureProfile(GraphProfile* result) {
|
||||
std::vector<CalculatorProfile> profiles;
|
||||
status.Update(GetCalculatorProfiles(&profiles));
|
||||
for (CalculatorProfile& p : profiles) {
|
||||
*result->mutable_calculator_profiles()->Add() = std::move(p);
|
||||
if (profile_builder_->ProfileIncluded(p)) {
|
||||
*result->mutable_calculator_profiles()->Add() = std::move(p);
|
||||
}
|
||||
}
|
||||
this->Reset();
|
||||
CleanCalculatorProfiles(result);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
@@ -97,18 +97,8 @@ class GraphProfilerTestPeer;
|
||||
// The client can overwrite this by calling SetClock().
|
||||
class GraphProfiler : public std::enable_shared_from_this<ProfilingContext> {
|
||||
public:
|
||||
GraphProfiler()
|
||||
: is_initialized_(false),
|
||||
is_profiling_(false),
|
||||
calculator_profiles_(1000),
|
||||
packets_info_(1000),
|
||||
is_running_(false),
|
||||
previous_log_end_time_(absl::InfinitePast()),
|
||||
previous_log_index_(-1),
|
||||
validated_graph_(nullptr) {
|
||||
clock_ = std::shared_ptr<mediapipe::Clock>(
|
||||
mediapipe::MonotonicClock::CreateSynchronizedMonotonicClock());
|
||||
}
|
||||
GraphProfiler();
|
||||
~GraphProfiler();
|
||||
|
||||
// Not copyable or movable.
|
||||
GraphProfiler(const GraphProfiler&) = delete;
|
||||
@@ -230,6 +220,8 @@ class GraphProfiler : public std::enable_shared_from_this<ProfilingContext> {
|
||||
int64 start_time_usec_;
|
||||
};
|
||||
|
||||
const ProfilerConfig& profiler_config() { return profiler_config_; }
|
||||
|
||||
private:
|
||||
// This can be used to add packet info for the input streams to the graph.
|
||||
// It treats the stream defined by |stream_name| as a stream produced by a
|
||||
@@ -303,6 +295,7 @@ class GraphProfiler : public std::enable_shared_from_this<ProfilingContext> {
|
||||
// Helper method to get the clock time in microsecond.
|
||||
int64 TimeNowUsec() { return ToUnixMicros(clock_->TimeNow()); }
|
||||
|
||||
private:
|
||||
// The settings for this tracer.
|
||||
ProfilerConfig profiler_config_;
|
||||
|
||||
@@ -345,6 +338,10 @@ class GraphProfiler : public std::enable_shared_from_this<ProfilingContext> {
|
||||
// The configuration for the graph being profiled.
|
||||
const ValidatedGraphConfig* validated_graph_;
|
||||
|
||||
// A private resource for creating GraphProfiles.
|
||||
class GraphProfileBuilder;
|
||||
std::unique_ptr<GraphProfileBuilder> profile_builder_;
|
||||
|
||||
// For testing.
|
||||
friend GraphProfilerTestPeer;
|
||||
};
|
||||
|
||||
@@ -1205,5 +1205,68 @@ TEST(GraphProfilerTest, ParallelReads) {
|
||||
EXPECT_EQ(1001, out_1_packets.size());
|
||||
}
|
||||
|
||||
// Returns the set of calculator names in a GraphProfile captured from
|
||||
// CalculatorGraph initialized from a certain CalculatorGraphConfig.
|
||||
std::set<std::string> GetCalculatorNames(const CalculatorGraphConfig& config) {
|
||||
std::set<std::string> result;
|
||||
CalculatorGraph graph;
|
||||
MP_EXPECT_OK(graph.Initialize(config));
|
||||
GraphProfile profile;
|
||||
MP_EXPECT_OK(graph.profiler()->CaptureProfile(&profile));
|
||||
for (auto& p : profile.calculator_profiles()) {
|
||||
result.insert(p.name());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
TEST(GraphProfilerTest, CalculatorProfileFilter) {
|
||||
CalculatorGraphConfig config;
|
||||
QCHECK(proto2::TextFormat::ParseFromString(R"(
|
||||
profiler_config {
|
||||
enable_profiler: true
|
||||
}
|
||||
node {
|
||||
calculator: "RangeCalculator"
|
||||
input_side_packet: "range_step"
|
||||
output_stream: "out"
|
||||
output_stream: "sum"
|
||||
output_stream: "mean"
|
||||
}
|
||||
node {
|
||||
calculator: "PassThroughCalculator"
|
||||
input_stream: "out"
|
||||
input_stream: "sum"
|
||||
input_stream: "mean"
|
||||
output_stream: "out_1"
|
||||
output_stream: "sum_1"
|
||||
output_stream: "mean_1"
|
||||
}
|
||||
output_stream: "OUT:0:the_integers"
|
||||
)",
|
||||
&config));
|
||||
|
||||
std::set<std::string> expected_names;
|
||||
expected_names = {"RangeCalculator", "PassThroughCalculator"};
|
||||
EXPECT_EQ(GetCalculatorNames(config), expected_names);
|
||||
|
||||
*config.mutable_profiler_config()->mutable_calculator_filter() =
|
||||
"RangeCalculator";
|
||||
expected_names = {"RangeCalculator"};
|
||||
EXPECT_EQ(GetCalculatorNames(config), expected_names);
|
||||
|
||||
*config.mutable_profiler_config()->mutable_calculator_filter() = "Range.*";
|
||||
expected_names = {"RangeCalculator"};
|
||||
EXPECT_EQ(GetCalculatorNames(config), expected_names);
|
||||
|
||||
*config.mutable_profiler_config()->mutable_calculator_filter() =
|
||||
".*Calculator";
|
||||
expected_names = {"RangeCalculator", "PassThroughCalculator"};
|
||||
EXPECT_EQ(GetCalculatorNames(config), expected_names);
|
||||
|
||||
*config.mutable_profiler_config()->mutable_calculator_filter() = ".*Clock.*";
|
||||
expected_names = {};
|
||||
EXPECT_EQ(GetCalculatorNames(config), expected_names);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace mediapipe
|
||||
|
||||
Vendored
+10
-33
@@ -13,63 +13,40 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
load("//mediapipe/framework/port:build_config.bzl", "mediapipe_proto_library")
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
package(default_visibility = ["//visibility:private"])
|
||||
|
||||
load("//mediapipe/framework/port:build_config.bzl", "mediapipe_cc_proto_library")
|
||||
|
||||
proto_library(
|
||||
mediapipe_proto_library(
|
||||
name = "sky_light_calculator_proto",
|
||||
srcs = ["sky_light_calculator.proto"],
|
||||
deps = ["//mediapipe/framework:calculator_proto"],
|
||||
)
|
||||
|
||||
mediapipe_cc_proto_library(
|
||||
name = "sky_light_calculator_cc_proto",
|
||||
srcs = ["sky_light_calculator.proto"],
|
||||
cc_deps = ["//mediapipe/framework:calculator_cc_proto"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [":sky_light_calculator_proto"],
|
||||
)
|
||||
|
||||
proto_library(
|
||||
mediapipe_proto_library(
|
||||
name = "night_light_calculator_proto",
|
||||
srcs = ["night_light_calculator.proto"],
|
||||
deps = ["//mediapipe/framework:calculator_proto"],
|
||||
)
|
||||
|
||||
mediapipe_cc_proto_library(
|
||||
name = "night_light_calculator_cc_proto",
|
||||
srcs = ["night_light_calculator.proto"],
|
||||
cc_deps = ["//mediapipe/framework:calculator_cc_proto"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [":night_light_calculator_proto"],
|
||||
deps = [
|
||||
"//mediapipe/framework:calculator_options_proto",
|
||||
"//mediapipe/framework:calculator_proto",
|
||||
],
|
||||
)
|
||||
|
||||
proto_library(
|
||||
mediapipe_proto_library(
|
||||
name = "zoo_mutator_proto",
|
||||
srcs = ["zoo_mutator.proto"],
|
||||
deps = ["@com_google_protobuf//:any_proto"],
|
||||
)
|
||||
|
||||
mediapipe_cc_proto_library(
|
||||
name = "zoo_mutator_cc_proto",
|
||||
srcs = ["zoo_mutator.proto"],
|
||||
cc_deps = ["@com_google_protobuf//:cc_wkt_protos"],
|
||||
visibility = ["//mediapipe:__subpackages__"],
|
||||
deps = [":zoo_mutator_proto"],
|
||||
)
|
||||
|
||||
proto_library(
|
||||
mediapipe_proto_library(
|
||||
name = "zoo_mutation_calculator_proto",
|
||||
srcs = ["zoo_mutation_calculator.proto"],
|
||||
features = ["-proto_dynamic_mode_static_link"],
|
||||
visibility = ["//mediapipe:__subpackages__"],
|
||||
deps = [
|
||||
":zoo_mutator_proto",
|
||||
"//mediapipe/framework:calculator_options_proto",
|
||||
"//mediapipe/framework:packet_factory_proto",
|
||||
"//mediapipe/framework:packet_generator_proto",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -9,6 +9,9 @@ import "mediapipe/framework/testdata/zoo_mutator.proto";
|
||||
|
||||
// Configuration of a ZooMutator is stored as an extension of
|
||||
// mediapipe.PacketGeneratorOptions.
|
||||
extend mediapipe.PacketGeneratorOptions {
|
||||
optional ZooMutatorConfig zoo_mutator_config_ext = 235240278;
|
||||
message ZooMutationCalculatorOptions {
|
||||
extend mediapipe.PacketGeneratorOptions {
|
||||
optional ZooMutationCalculatorOptions ext = 235240278;
|
||||
}
|
||||
optional ZooMutatorConfig zoo_mutator_config = 1;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ package(default_visibility = ["//visibility:private"])
|
||||
|
||||
exports_files([
|
||||
"simple_subgraph_template.cc",
|
||||
"options_lib_template.cc",
|
||||
])
|
||||
|
||||
bzl_library(
|
||||
@@ -40,6 +41,7 @@ bzl_library(
|
||||
":build_defs_bzl",
|
||||
"//mediapipe/framework:encode_binary_proto",
|
||||
"//mediapipe/framework:transitive_protos_bzl",
|
||||
"//mediapipe/framework/deps:descriptor_set_bzl",
|
||||
"//mediapipe/framework/deps:expand_template_bzl",
|
||||
],
|
||||
)
|
||||
@@ -71,6 +73,7 @@ cc_library(
|
||||
mediapipe_proto_library(
|
||||
name = "calculator_graph_template_proto",
|
||||
srcs = ["calculator_graph_template.proto"],
|
||||
def_options_lib = False,
|
||||
def_py_proto = False,
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
@@ -80,6 +83,17 @@ mediapipe_proto_library(
|
||||
],
|
||||
)
|
||||
|
||||
mediapipe_proto_library(
|
||||
name = "packet_generator_wrapper_calculator_proto",
|
||||
srcs = ["packet_generator_wrapper_calculator.proto"],
|
||||
def_py_proto = False,
|
||||
visibility = ["//mediapipe/framework:mediapipe_internal"],
|
||||
deps = [
|
||||
"//mediapipe/framework:calculator_options_proto",
|
||||
"//mediapipe/framework:packet_generator_proto",
|
||||
],
|
||||
)
|
||||
|
||||
mediapipe_proto_library(
|
||||
name = "source_proto",
|
||||
srcs = ["source.proto"],
|
||||
@@ -159,10 +173,10 @@ cc_library(
|
||||
hdrs = ["options_map.h"],
|
||||
visibility = ["//mediapipe/framework:mediapipe_internal"],
|
||||
deps = [
|
||||
":type_util",
|
||||
"//mediapipe/framework:calculator_cc_proto",
|
||||
"//mediapipe/framework/port:any_proto",
|
||||
"//mediapipe/framework/port:status",
|
||||
"//mediapipe/framework/tool:type_util",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -190,13 +204,41 @@ cc_library(
|
||||
],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "message_type_util",
|
||||
srcs = ["message_type_util.cc"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//mediapipe/framework/port:advanced_proto",
|
||||
"//mediapipe/framework/port:file_helpers",
|
||||
"//mediapipe/framework/port:logging",
|
||||
"@com_google_absl//absl/flags:flag",
|
||||
"@com_google_absl//absl/flags:parse",
|
||||
"@com_google_absl//absl/strings",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "options_registry",
|
||||
srcs = ["options_registry.cc"],
|
||||
hdrs = ["options_registry.h"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//mediapipe/framework/deps:registration",
|
||||
"//mediapipe/framework/port:advanced_proto",
|
||||
"//mediapipe/framework/port:logging",
|
||||
],
|
||||
)
|
||||
|
||||
mediapipe_cc_test(
|
||||
name = "options_util_test",
|
||||
size = "small",
|
||||
srcs = ["options_util_test.cc"],
|
||||
# A non-empty "data" param is needed to build the "_test_wasm" target.
|
||||
data = [":node_chain_subgraph.proto"],
|
||||
requires_full_emulation = False,
|
||||
deps = [
|
||||
":options_registry",
|
||||
":options_util",
|
||||
"//mediapipe/calculators/core:flow_limiter_calculator",
|
||||
"//mediapipe/calculators/core:flow_limiter_calculator_cc_proto",
|
||||
@@ -207,11 +249,26 @@ mediapipe_cc_test(
|
||||
"//mediapipe/framework/port:gtest_main",
|
||||
"//mediapipe/framework/port:parse_text_proto",
|
||||
"//mediapipe/framework/port:status",
|
||||
"//mediapipe/framework/testdata:night_light_calculator_cc_proto",
|
||||
"//mediapipe/framework/testdata:night_light_calculator_options_lib",
|
||||
"//mediapipe/framework/tool:node_chain_subgraph_options_lib",
|
||||
"//mediapipe/util:header_util",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "packet_generator_wrapper_calculator",
|
||||
srcs = ["packet_generator_wrapper_calculator.cc"],
|
||||
visibility = ["//mediapipe/framework:mediapipe_internal"],
|
||||
deps = [
|
||||
":packet_generator_wrapper_calculator_cc_proto",
|
||||
"//mediapipe/framework:calculator_base",
|
||||
"//mediapipe/framework:calculator_registry",
|
||||
"//mediapipe/framework:output_side_packet",
|
||||
"//mediapipe/framework:packet_generator",
|
||||
],
|
||||
alwayslink = 1,
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "proto_util_lite",
|
||||
srcs = ["proto_util_lite.cc"],
|
||||
@@ -776,6 +833,7 @@ cc_test(
|
||||
"//mediapipe/framework/port:ret_check",
|
||||
"//mediapipe/framework/port:status",
|
||||
"//mediapipe/framework/stream_handler:immediate_input_stream_handler",
|
||||
"@com_google_absl//absl/strings",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ load("//mediapipe/framework:encode_binary_proto.bzl", "encode_binary_proto", "ge
|
||||
load("//mediapipe/framework:transitive_protos.bzl", "transitive_protos")
|
||||
load("//mediapipe/framework/deps:expand_template.bzl", "expand_template")
|
||||
load("//mediapipe/framework/tool:build_defs.bzl", "clean_dep")
|
||||
load("//mediapipe/framework/deps:descriptor_set.bzl", "direct_descriptor_set", "transitive_descriptor_set")
|
||||
|
||||
def mediapipe_binary_graph(name, graph = None, output_name = None, deps = [], testonly = False, **kwargs):
|
||||
"""Converts a graph from text format to binary format."""
|
||||
@@ -152,3 +153,115 @@ def mediapipe_simple_subgraph(
|
||||
testonly = testonly,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
def mediapipe_reexport_library(
|
||||
name,
|
||||
actual,
|
||||
**kwargs):
|
||||
"""Defines a cc_library that exports the headers of other libraries.
|
||||
|
||||
Normally cc_library does not export the headers of its dependencies,
|
||||
and the clang "layering_check" requires clients to depend on them
|
||||
directly. Header files can be exported by listing them in either
|
||||
cc_library's "hdrs" or "textual_hdrs" argument. The "textual_hdrs"
|
||||
argument can also accept library targets and has the effect of
|
||||
exporting their header files and permitting client references to them.
|
||||
The result is a new library target that combines and exports the public
|
||||
interfaces of several existing library targets.
|
||||
|
||||
Args:
|
||||
name: the name for the combined target.
|
||||
actual: the targets to combine and export together.
|
||||
**kwargs: Remaining keyword args, forwarded to cc_library.
|
||||
"""
|
||||
native.cc_library(
|
||||
name = name,
|
||||
textual_hdrs = actual,
|
||||
deps = actual,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
def mediapipe_options_library(
|
||||
name,
|
||||
proto_lib,
|
||||
deps = [],
|
||||
visibility = None,
|
||||
testonly = None,
|
||||
**kwargs):
|
||||
"""Registers options protobuf metadata for defining options packets.
|
||||
|
||||
Args:
|
||||
name: name of the options_lib target to define.
|
||||
proto_lib: the proto_library target to register.
|
||||
deps: any additional protobuf dependencies.
|
||||
visibility: The list of packages the subgraph should be visible to.
|
||||
testonly: pass 1 if the graph is to be used only for tests.
|
||||
**kwargs: Remaining keyword args, forwarded to cc_library.
|
||||
"""
|
||||
|
||||
transitive_descriptor_set(
|
||||
name = proto_lib + "_transitive",
|
||||
deps = [proto_lib],
|
||||
testonly = testonly,
|
||||
)
|
||||
direct_descriptor_set(
|
||||
name = proto_lib + "_direct",
|
||||
deps = [proto_lib],
|
||||
testonly = testonly,
|
||||
)
|
||||
data_as_c_string(
|
||||
name = name + "_inc",
|
||||
srcs = [proto_lib + "_transitive-transitive-descriptor-set.proto.bin"],
|
||||
outs = [proto_lib + "_descriptors.inc"],
|
||||
)
|
||||
native.genrule(
|
||||
name = name + "_type_name",
|
||||
srcs = [proto_lib + "_direct-direct-descriptor-set.proto.bin"],
|
||||
outs = [name + "_type_name.h"],
|
||||
cmd = ("$(location " + "//mediapipe/framework/tool:message_type_util" + ") " +
|
||||
("--input_path=$(location %s) " % (proto_lib + "_direct-direct-descriptor-set.proto.bin")) +
|
||||
("--root_type_macro_output_path=$(location %s) " % (name + "_type_name.h"))),
|
||||
tools = ["//mediapipe/framework/tool:message_type_util"],
|
||||
visibility = visibility,
|
||||
testonly = testonly,
|
||||
)
|
||||
expand_template(
|
||||
name = name + "_cc",
|
||||
template = clean_dep("//mediapipe/framework/tool:options_lib_template.cc"),
|
||||
out = name + ".cc",
|
||||
substitutions = {
|
||||
"{{MESSAGE_NAME_HEADER}}": native.package_name() + "/" + name + "_type_name.h",
|
||||
"{{MESSAGE_PROTO_HEADER}}": native.package_name() + "/" + proto_lib.replace("_proto", ".pb.h"),
|
||||
"{{DESCRIPTOR_INC_FILE_PATH}}": native.package_name() + "/" + proto_lib + "_descriptors.inc",
|
||||
},
|
||||
testonly = testonly,
|
||||
)
|
||||
native.cc_library(
|
||||
name = proto_lib.replace("_proto", "_options_registry"),
|
||||
srcs = [
|
||||
name + ".cc",
|
||||
proto_lib + "_descriptors.inc",
|
||||
name + "_type_name.h",
|
||||
],
|
||||
deps = [
|
||||
clean_dep("//mediapipe/framework:calculator_framework"),
|
||||
clean_dep("//mediapipe/framework/port:advanced_proto"),
|
||||
clean_dep("//mediapipe/framework/tool:options_registry"),
|
||||
proto_lib.replace("_proto", "_cc_proto"),
|
||||
] + deps,
|
||||
alwayslink = 1,
|
||||
visibility = visibility,
|
||||
testonly = testonly,
|
||||
features = ["-no_undefined"],
|
||||
**kwargs
|
||||
)
|
||||
mediapipe_reexport_library(
|
||||
name = name,
|
||||
actual = [
|
||||
proto_lib.replace("_proto", "_cc_proto"),
|
||||
proto_lib.replace("_proto", "_options_registry"),
|
||||
],
|
||||
visibility = visibility,
|
||||
testonly = testonly,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "absl/flags/flag.h"
|
||||
#include "absl/flags/parse.h"
|
||||
#include "absl/strings/ascii.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/str_replace.h"
|
||||
#include "mediapipe/framework/port/advanced_proto_inc.h"
|
||||
#include "mediapipe/framework/port/file_helpers.h"
|
||||
#include "mediapipe/framework/port/logging.h"
|
||||
|
||||
ABSL_FLAG(std::string, input_path, "",
|
||||
"Full path of the FileDescriptorSet to summarize. ");
|
||||
ABSL_FLAG(std::string, root_type_name_output_path, "",
|
||||
"Where to write the output root message type name. ");
|
||||
ABSL_FLAG(std::string, root_type_macro_output_path, "",
|
||||
"Where to write the output root message type macro. ");
|
||||
|
||||
namespace mediapipe {
|
||||
|
||||
using proto_ns::DescriptorProto;
|
||||
using proto_ns::FileDescriptorProto;
|
||||
using proto_ns::FileDescriptorSet;
|
||||
|
||||
// Utility to extract summary data about protobuf descriptors.
|
||||
//
|
||||
// This utility is currently used by the build rule mediapipe_options_library()
|
||||
// to recover the package-name and type-name associated with each
|
||||
// mediapipe_proto_library() target.
|
||||
class DescriptorReader {
|
||||
public:
|
||||
// Returns a FileDescriptor that is not referenced by other FileDescriptors
|
||||
// in a FileDescriptorSet.
|
||||
static FileDescriptorProto FindTopFile(const FileDescriptorSet& files) {
|
||||
std::set<std::string> file_names;
|
||||
for (const FileDescriptorProto& file : files.file()) {
|
||||
file_names.insert(file.name());
|
||||
}
|
||||
for (const FileDescriptorProto& file : files.file()) {
|
||||
for (const std::string& dep : file.dependency()) {
|
||||
file_names.erase(dep);
|
||||
}
|
||||
}
|
||||
for (const FileDescriptorProto& file : files.file()) {
|
||||
if (file_names.count(file.name()) > 0) {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
return FileDescriptorProto();
|
||||
}
|
||||
|
||||
static std::string CleanTypeName(const std::string& type_name) {
|
||||
return (type_name.rfind('.', 0) == 0) ? type_name.substr(1) : type_name;
|
||||
}
|
||||
|
||||
static std::string CleanTypeName(const std::string& package,
|
||||
const std::string& name) {
|
||||
return absl::StrCat(package, ".", name);
|
||||
}
|
||||
|
||||
// Returns the length of the common prefix between two strings.
|
||||
static int MatchingPrefixLength(const std::string& s, const std::string& t) {
|
||||
int i = 0;
|
||||
while (i < std::min(s.size(), t.size()) && s[i] == t[i]) {
|
||||
++i;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
// Returns the type-name that best matches the descriptor file-name.
|
||||
static std::string BestTypeName(const std::set<std::string>& type_names,
|
||||
const FileDescriptorProto& file) {
|
||||
std::string proto_name = std::string(file::Basename(file.name()));
|
||||
proto_name = proto_name.substr(
|
||||
0, proto_name.size() - file::Extension(proto_name).size() - 1);
|
||||
proto_name.erase(std::remove(proto_name.begin(), proto_name.end(), '_'),
|
||||
proto_name.end());
|
||||
std::string result = "";
|
||||
int best_match = -1;
|
||||
for (const std::string& type_name : type_names) {
|
||||
std::string name = absl::AsciiStrToLower(type_name);
|
||||
if (name.rfind('.') != std::string::npos) {
|
||||
name = name.substr(name.rfind('.') + 1);
|
||||
}
|
||||
int m = MatchingPrefixLength(proto_name, name);
|
||||
if (m > best_match) {
|
||||
best_match = m;
|
||||
result = type_name;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Returns a DescriptorProto that is not referenced by other DescriptorProtos
|
||||
// in a FileDescriptorProto.
|
||||
static DescriptorProto FindTopDescriptor(const FileDescriptorProto& file) {
|
||||
std::set<std::string> type_names;
|
||||
std::set<std::string> refs;
|
||||
for (const DescriptorProto& descriptor : file.message_type()) {
|
||||
type_names.insert(CleanTypeName(file.package(), descriptor.name()));
|
||||
}
|
||||
std::string best_name = BestTypeName(type_names, file);
|
||||
for (const DescriptorProto& descriptor : file.message_type()) {
|
||||
if (best_name == CleanTypeName(file.package(), descriptor.name())) {
|
||||
return descriptor;
|
||||
}
|
||||
}
|
||||
return DescriptorProto();
|
||||
}
|
||||
|
||||
static std::string FindTopTypeName(const FileDescriptorSet& files) {
|
||||
FileDescriptorProto file = FindTopFile(files);
|
||||
DescriptorProto descriptor = FindTopDescriptor(file);
|
||||
return CleanTypeName(file.package(), descriptor.name());
|
||||
}
|
||||
|
||||
static FileDescriptorSet ReadFileDescriptorSet(const std::string& path) {
|
||||
std::string contents;
|
||||
CHECK_OK(file::GetContents(path, &contents));
|
||||
proto_ns::FileDescriptorSet result;
|
||||
result.ParseFromString(contents);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void WriteFile(const std::string& path, const std::string& contents) {
|
||||
CHECK_OK(file::SetContents(path, contents));
|
||||
}
|
||||
|
||||
static void WriteMessageTypeName(const std::string& path,
|
||||
const FileDescriptorSet& files) {
|
||||
FileDescriptorProto file = FindTopFile(files);
|
||||
DescriptorProto descriptor = FindTopDescriptor(file);
|
||||
std::string type_name = mediapipe::DescriptorReader::FindTopTypeName(files);
|
||||
mediapipe::DescriptorReader::WriteFile(
|
||||
absl::GetFlag(FLAGS_root_type_name_output_path), type_name);
|
||||
}
|
||||
|
||||
static void WriteMessageTypeMacro(const std::string& path,
|
||||
const FileDescriptorSet& files) {
|
||||
FileDescriptorProto file = FindTopFile(files);
|
||||
DescriptorProto descriptor = FindTopDescriptor(file);
|
||||
std::string type_package =
|
||||
absl::StrReplaceAll(file.package(), {{".", "::"}});
|
||||
std::string type_name = descriptor.name();
|
||||
std::string contents =
|
||||
absl::StrCat("#define MP_OPTION_TYPE_NS ", type_package, "\n") +
|
||||
absl::StrCat("#define MP_OPTION_TYPE_NAME ", type_name, "\n");
|
||||
WriteFile(path, contents);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mediapipe
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
absl::ParseCommandLine(argc, argv);
|
||||
auto files = mediapipe::DescriptorReader::ReadFileDescriptorSet(
|
||||
absl::GetFlag(FLAGS_input_path));
|
||||
if (!absl::GetFlag(FLAGS_root_type_name_output_path).empty()) {
|
||||
mediapipe::DescriptorReader::WriteMessageTypeName(
|
||||
absl::GetFlag(FLAGS_root_type_name_output_path), files);
|
||||
}
|
||||
if (!absl::GetFlag(FLAGS_root_type_macro_output_path).empty()) {
|
||||
mediapipe::DescriptorReader::WriteMessageTypeMacro(
|
||||
absl::GetFlag(FLAGS_root_type_macro_output_path), files);
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// 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.
|
||||
//
|
||||
// This template is used by the mediapipe_simple_subgraph macro in
|
||||
// //mediapipe/framework/tool/mediapipe_graph.bzl
|
||||
|
||||
#include "mediapipe/framework/port/advanced_proto_inc.h"
|
||||
#include "mediapipe/framework/tool/options_registry.h"
|
||||
#include "{{MESSAGE_NAME_HEADER}}"
|
||||
#include "{{MESSAGE_PROTO_HEADER}}"
|
||||
|
||||
namespace {
|
||||
constexpr char kDescriptorContents[] =
|
||||
#include "{{DESCRIPTOR_INC_FILE_PATH}}"
|
||||
; // NOLINT(whitespace/semicolon)
|
||||
|
||||
mediapipe::proto_ns::FileDescriptorSet ParseFileDescriptorSet(
|
||||
const std::string& pb) {
|
||||
mediapipe::proto_ns::FileDescriptorSet files;
|
||||
files.ParseFromString(pb);
|
||||
return files;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace mediapipe {
|
||||
// The protobuf descriptor for an options message type.
|
||||
template <>
|
||||
const RegistrationToken tool::OptionsRegistry::registration_token<
|
||||
MP_OPTION_TYPE_NS::MP_OPTION_TYPE_NAME> =
|
||||
tool::OptionsRegistry::Register(ParseFileDescriptorSet(
|
||||
std::string(kDescriptorContents, sizeof(kDescriptorContents) - 1)));
|
||||
} // namespace mediapipe
|
||||
@@ -0,0 +1,47 @@
|
||||
#include "mediapipe/framework/tool/options_registry.h"
|
||||
|
||||
namespace mediapipe {
|
||||
namespace tool {
|
||||
|
||||
proto_ns::DescriptorPool* OptionsRegistry::options_descriptor_pool() {
|
||||
static proto_ns::DescriptorPool* result = new proto_ns::DescriptorPool();
|
||||
return result;
|
||||
}
|
||||
|
||||
RegistrationToken OptionsRegistry::Register(
|
||||
const proto_ns::FileDescriptorSet& files) {
|
||||
for (auto& file : files.file()) {
|
||||
options_descriptor_pool()->BuildFile(file);
|
||||
}
|
||||
return RegistrationToken([]() {});
|
||||
}
|
||||
|
||||
const proto_ns::Descriptor* OptionsRegistry::GetProtobufDescriptor(
|
||||
const std::string& type_name) {
|
||||
const proto_ns::Descriptor* result =
|
||||
proto_ns::DescriptorPool::generated_pool()->FindMessageTypeByName(
|
||||
type_name);
|
||||
if (!result) {
|
||||
result = options_descriptor_pool()->FindMessageTypeByName(type_name);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void OptionsRegistry::FindAllExtensions(
|
||||
const proto_ns::Descriptor& extendee,
|
||||
std::vector<const proto_ns::FieldDescriptor*>* result) {
|
||||
using proto_ns::DescriptorPool;
|
||||
std::vector<const proto_ns::FieldDescriptor*> extensions;
|
||||
DescriptorPool::generated_pool()->FindAllExtensions(&extendee, &extensions);
|
||||
options_descriptor_pool()->FindAllExtensions(&extendee, &extensions);
|
||||
absl::flat_hash_set<int> numbers;
|
||||
for (const proto_ns::FieldDescriptor* extension : extensions) {
|
||||
bool inserted = numbers.insert(extension->number()).second;
|
||||
if (inserted) {
|
||||
result->push_back(extension);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace tool
|
||||
} // namespace mediapipe
|
||||
@@ -0,0 +1,40 @@
|
||||
#ifndef MEDIAPIPE_FRAMEWORK_TOOL_OPTIONS_REGISTRY_H_
|
||||
#define MEDIAPIPE_FRAMEWORK_TOOL_OPTIONS_REGISTRY_H_
|
||||
|
||||
#include "mediapipe/framework/deps/registration.h"
|
||||
#include "mediapipe/framework/port/advanced_proto_inc.h"
|
||||
|
||||
namespace mediapipe {
|
||||
namespace tool {
|
||||
|
||||
// A static registry that stores descriptors for protobufs used in MediaPipe
|
||||
// calculator options. Lite-proto builds do not normally include descriptors.
|
||||
// These registered descriptors allow individual protobuf fields to be
|
||||
// referenced and specified separately within CalculatorGraphConfigs.
|
||||
class OptionsRegistry {
|
||||
public:
|
||||
// Registers the protobuf descriptors for a MessageLite.
|
||||
static RegistrationToken Register(const proto_ns::FileDescriptorSet& files);
|
||||
|
||||
// Finds the descriptor for a protobuf.
|
||||
static const proto_ns::Descriptor* GetProtobufDescriptor(
|
||||
const std::string& type_name);
|
||||
|
||||
// Returns all known proto2 extensions to a type.
|
||||
static void FindAllExtensions(
|
||||
const proto_ns::Descriptor& extendee,
|
||||
std::vector<const proto_ns::FieldDescriptor*>* result);
|
||||
|
||||
private:
|
||||
// Stores the descriptors for each options protobuf type.
|
||||
static proto_ns::DescriptorPool* options_descriptor_pool();
|
||||
|
||||
// Registers the descriptors for each options protobuf type.
|
||||
template <class MessageT>
|
||||
static const RegistrationToken registration_token;
|
||||
};
|
||||
|
||||
} // namespace tool
|
||||
} // namespace mediapipe
|
||||
|
||||
#endif // MEDIAPIPE_FRAMEWORK_TOOL_OPTIONS_REGISTRY_H_
|
||||
@@ -19,6 +19,8 @@
|
||||
#include "mediapipe/framework/port/gtest.h"
|
||||
#include "mediapipe/framework/port/parse_text_proto.h"
|
||||
#include "mediapipe/framework/port/status_matchers.h"
|
||||
#include "mediapipe/framework/testdata/night_light_calculator.pb.h"
|
||||
#include "mediapipe/framework/tool/options_registry.h"
|
||||
|
||||
namespace mediapipe {
|
||||
namespace {
|
||||
@@ -42,5 +44,13 @@ TEST_F(OptionsUtilTest, GetProtobufDescriptor) {
|
||||
#endif
|
||||
}
|
||||
|
||||
// Retrieves the description of a protobuf from the OptionsRegistry.
|
||||
TEST_F(OptionsUtilTest, GetProtobufDescriptorRegistered) {
|
||||
const proto_ns::Descriptor* descriptor =
|
||||
tool::OptionsRegistry::GetProtobufDescriptor(
|
||||
"mediapipe.NightLightCalculatorOptions");
|
||||
EXPECT_NE(nullptr, descriptor);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace mediapipe
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
#include "mediapipe/framework/calculator_base.h"
|
||||
#include "mediapipe/framework/calculator_registry.h"
|
||||
#include "mediapipe/framework/output_side_packet.h"
|
||||
#include "mediapipe/framework/packet_generator.h"
|
||||
#include "mediapipe/framework/tool/packet_generator_wrapper_calculator.pb.h"
|
||||
|
||||
namespace mediapipe {
|
||||
|
||||
class PacketGeneratorWrapperCalculator : public CalculatorBase {
|
||||
public:
|
||||
static absl::Status GetContract(CalculatorContract* cc) {
|
||||
const auto& options =
|
||||
cc->Options<::mediapipe::PacketGeneratorWrapperCalculatorOptions>();
|
||||
ASSIGN_OR_RETURN(auto static_access,
|
||||
mediapipe::internal::StaticAccessToGeneratorRegistry::
|
||||
CreateByNameInNamespace(options.package(),
|
||||
options.packet_generator()));
|
||||
MP_RETURN_IF_ERROR(static_access->FillExpectations(
|
||||
options.options(), &cc->InputSidePackets(),
|
||||
&cc->OutputSidePackets()))
|
||||
.SetPrepend()
|
||||
<< options.packet_generator() << "::FillExpectations() failed: ";
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status Open(CalculatorContext* cc) override {
|
||||
const auto& options =
|
||||
cc->Options<::mediapipe::PacketGeneratorWrapperCalculatorOptions>();
|
||||
ASSIGN_OR_RETURN(auto static_access,
|
||||
mediapipe::internal::StaticAccessToGeneratorRegistry::
|
||||
CreateByNameInNamespace(options.package(),
|
||||
options.packet_generator()));
|
||||
mediapipe::PacketSet output_packets(cc->OutputSidePackets().TagMap());
|
||||
MP_RETURN_IF_ERROR(static_access->Generate(options.options(),
|
||||
cc->InputSidePackets(),
|
||||
&output_packets))
|
||||
.SetPrepend()
|
||||
<< options.packet_generator() << "::Generate() failed: ";
|
||||
for (auto id = output_packets.BeginId(); id < output_packets.EndId();
|
||||
++id) {
|
||||
cc->OutputSidePackets().Get(id).Set(output_packets.Get(id));
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status Process(CalculatorContext* cc) override {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
};
|
||||
REGISTER_CALCULATOR(PacketGeneratorWrapperCalculator);
|
||||
|
||||
} // namespace mediapipe
|
||||
@@ -0,0 +1,19 @@
|
||||
syntax = "proto2";
|
||||
|
||||
package mediapipe;
|
||||
|
||||
import "mediapipe/framework/calculator_options.proto";
|
||||
import "mediapipe/framework/packet_generator.proto";
|
||||
|
||||
message PacketGeneratorWrapperCalculatorOptions {
|
||||
extend CalculatorOptions {
|
||||
optional PacketGeneratorWrapperCalculatorOptions ext = 381945445;
|
||||
}
|
||||
|
||||
// Same as the corresponding fields in PacketGeneratorConfig.
|
||||
optional string packet_generator = 1;
|
||||
optional PacketGeneratorOptions options = 2;
|
||||
// Same as CalculatorGraphConfig.package. Copied here since the graph config
|
||||
// is not available to the calculator.
|
||||
optional string package = 3;
|
||||
}
|
||||
@@ -186,7 +186,6 @@ absl::Status FindCorrespondingStreams(
|
||||
absl::Status ValidateSubgraphFields(
|
||||
const CalculatorGraphConfig::Node& subgraph_node) {
|
||||
if (subgraph_node.source_layer() || subgraph_node.buffer_size_hint() ||
|
||||
subgraph_node.has_input_stream_handler() ||
|
||||
subgraph_node.has_output_stream_handler() ||
|
||||
subgraph_node.input_stream_info_size() != 0 ||
|
||||
!subgraph_node.executor().empty()) {
|
||||
|
||||
@@ -59,6 +59,11 @@ using mediapipe::SwitchContainerOptions;
|
||||
// or contained_node 1, given "ENABLE:false" or "ENABLE:true" respectively.
|
||||
// Input-side-packet "ENABLE" and input-stream "SELECT" can also be used
|
||||
// similarly to specify the active channel.
|
||||
//
|
||||
// Note that this container defaults to use ImmediateInputStreamHandler,
|
||||
// which can be used to accept infrequent "enable" packets asynchronously.
|
||||
// However, it can be overridden to work with DefaultInputStreamHandler,
|
||||
// which can be used to accept frequent "enable" packets synchronously.
|
||||
class SwitchContainer : public Subgraph {
|
||||
public:
|
||||
SwitchContainer() = default;
|
||||
@@ -79,11 +84,16 @@ std::string ChannelName(const std::string& name, int channel) {
|
||||
// Returns a SwitchDemuxCalculator node.
|
||||
CalculatorGraphConfig::Node* BuildDemuxNode(
|
||||
const std::map<TagIndex, std::string>& input_tags,
|
||||
const CalculatorGraphConfig::Node& container_node,
|
||||
CalculatorGraphConfig* config) {
|
||||
CalculatorGraphConfig::Node* result = config->add_node();
|
||||
*result->mutable_calculator() = "SwitchDemuxCalculator";
|
||||
*result->mutable_input_stream_handler()->mutable_input_stream_handler() =
|
||||
"ImmediateInputStreamHandler";
|
||||
if (container_node.has_input_stream_handler()) {
|
||||
*result->mutable_input_stream_handler() =
|
||||
container_node.input_stream_handler();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -233,7 +243,7 @@ absl::StatusOr<CalculatorGraphConfig> SwitchContainer::GetConfig(
|
||||
ParseTags(container_streams.output_side_packet(), &side_output_tags);
|
||||
|
||||
// Add a graph node for the demux, mux.
|
||||
auto demux = BuildDemuxNode(input_tags, &config);
|
||||
auto demux = BuildDemuxNode(input_tags, container_node, &config);
|
||||
CopyOptions(container_node, demux);
|
||||
ClearContainerOptions(demux);
|
||||
demux->add_input_stream("SELECT:gate_select");
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "absl/strings/str_replace.h"
|
||||
#include "mediapipe/framework/calculator.pb.h"
|
||||
#include "mediapipe/framework/calculator_framework.h"
|
||||
#include "mediapipe/framework/deps/message_matchers.h"
|
||||
@@ -66,8 +67,9 @@ REGISTER_CALCULATOR(TripleIntCalculator);
|
||||
// A testing example of a SwitchContainer containing two subnodes.
|
||||
// Note that the input and output tags supplied to the container node,
|
||||
// must match the input and output tags required by the subnodes.
|
||||
CalculatorGraphConfig SubnodeContainerExample() {
|
||||
return mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"pb(
|
||||
CalculatorGraphConfig SubnodeContainerExample(
|
||||
const std::string& input_stream_handler = "") {
|
||||
std::string config = R"pb(
|
||||
input_stream: "foo"
|
||||
input_stream: "enable"
|
||||
input_side_packet: "timezone"
|
||||
@@ -81,7 +83,7 @@ CalculatorGraphConfig SubnodeContainerExample() {
|
||||
contained_node: { calculator: "TripleIntCalculator" }
|
||||
contained_node: { calculator: "PassThroughCalculator" }
|
||||
}
|
||||
}
|
||||
} $input_stream_handler
|
||||
}
|
||||
node {
|
||||
calculator: "PassThroughCalculator"
|
||||
@@ -90,7 +92,11 @@ CalculatorGraphConfig SubnodeContainerExample() {
|
||||
output_stream: "output_foo"
|
||||
output_stream: "output_bar"
|
||||
}
|
||||
)pb");
|
||||
)pb";
|
||||
|
||||
return mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(
|
||||
absl::StrReplaceAll(config,
|
||||
{{"$input_stream_handler", input_stream_handler}}));
|
||||
}
|
||||
|
||||
// A testing example of a SwitchContainer containing two subnodes.
|
||||
@@ -124,7 +130,8 @@ CalculatorGraphConfig SideSubnodeContainerExample() {
|
||||
}
|
||||
|
||||
// Runs the test container graph with a few input packets.
|
||||
void RunTestContainer(CalculatorGraphConfig supergraph) {
|
||||
void RunTestContainer(CalculatorGraphConfig supergraph,
|
||||
bool send_bounds = false) {
|
||||
CalculatorGraph graph;
|
||||
std::vector<Packet> out_foo, out_bar;
|
||||
tool::AddVectorSink("output_foo", &supergraph, &out_foo);
|
||||
@@ -132,17 +139,23 @@ void RunTestContainer(CalculatorGraphConfig supergraph) {
|
||||
MP_ASSERT_OK(graph.Initialize(supergraph, {}));
|
||||
MP_ASSERT_OK(graph.StartRun({{"timezone", MakePacket<int>(3)}}));
|
||||
|
||||
// Send enable == true signal at 5000 us.
|
||||
const int64 enable_ts = 5000;
|
||||
MP_EXPECT_OK(graph.AddPacketToInputStream(
|
||||
"enable", MakePacket<bool>(true).At(Timestamp(enable_ts))));
|
||||
MP_ASSERT_OK(graph.WaitUntilIdle());
|
||||
if (!send_bounds) {
|
||||
// Send enable == true signal at 5000 us.
|
||||
const int64 enable_ts = 5000;
|
||||
MP_EXPECT_OK(graph.AddPacketToInputStream(
|
||||
"enable", MakePacket<bool>(true).At(Timestamp(enable_ts))));
|
||||
MP_ASSERT_OK(graph.WaitUntilIdle());
|
||||
}
|
||||
|
||||
const int packet_count = 10;
|
||||
// Send int value packets at {10K, 20K, 30K, ..., 100K}.
|
||||
for (uint64 t = 1; t <= packet_count; ++t) {
|
||||
MP_EXPECT_OK(graph.AddPacketToInputStream(
|
||||
"foo", MakePacket<int>(t).At(Timestamp(t * 10000))));
|
||||
if (send_bounds) {
|
||||
MP_EXPECT_OK(graph.AddPacketToInputStream(
|
||||
"enable", MakePacket<bool>(true).At(Timestamp(t * 10000))));
|
||||
}
|
||||
MP_ASSERT_OK(graph.WaitUntilIdle());
|
||||
// The inputs are sent to the input stream "foo", they should pass through.
|
||||
EXPECT_EQ(out_foo.size(), t);
|
||||
@@ -153,15 +166,21 @@ void RunTestContainer(CalculatorGraphConfig supergraph) {
|
||||
EXPECT_EQ(out_bar.back().Get<int>(), t);
|
||||
}
|
||||
|
||||
// Send enable == false signal at 105K us.
|
||||
MP_EXPECT_OK(graph.AddPacketToInputStream(
|
||||
"enable", MakePacket<bool>(false).At(Timestamp(105000))));
|
||||
MP_ASSERT_OK(graph.WaitUntilIdle());
|
||||
if (!send_bounds) {
|
||||
// Send enable == false signal at 105K us.
|
||||
MP_EXPECT_OK(graph.AddPacketToInputStream(
|
||||
"enable", MakePacket<bool>(false).At(Timestamp(105000))));
|
||||
MP_ASSERT_OK(graph.WaitUntilIdle());
|
||||
}
|
||||
|
||||
// Send int value packets at {110K, 120K, ..., 200K}.
|
||||
for (uint64 t = 11; t <= packet_count * 2; ++t) {
|
||||
MP_EXPECT_OK(graph.AddPacketToInputStream(
|
||||
"foo", MakePacket<int>(t).At(Timestamp(t * 10000))));
|
||||
if (send_bounds) {
|
||||
MP_EXPECT_OK(graph.AddPacketToInputStream(
|
||||
"enable", MakePacket<bool>(false).At(Timestamp(t * 10000))));
|
||||
}
|
||||
MP_ASSERT_OK(graph.WaitUntilIdle());
|
||||
// The inputs are sent to the input stream "foo", they should pass through.
|
||||
EXPECT_EQ(out_foo.size(), t);
|
||||
@@ -351,6 +370,86 @@ TEST(SwitchContainerTest, ValidateInputStreamHandler) {
|
||||
EXPECT_THAT(graph.Config(), mediapipe::EqualsProto(expected_graph));
|
||||
}
|
||||
|
||||
// Expands the SwitchContainer with a node-level input_stream_handler.
|
||||
TEST(SwitchContainerTest, OverrideInputStreamHandler) {
|
||||
EXPECT_TRUE(SubgraphRegistry::IsRegistered("SwitchContainer"));
|
||||
CalculatorGraph graph;
|
||||
CalculatorGraphConfig supergraph = SubnodeContainerExample(
|
||||
R"pb(input_stream_handler {
|
||||
input_stream_handler: "DefaultInputStreamHandler"
|
||||
})pb");
|
||||
*supergraph.mutable_node(0)
|
||||
->mutable_input_stream_handler()
|
||||
->mutable_input_stream_handler() = "DefaultInputStreamHandler";
|
||||
MP_ASSERT_OK(graph.Initialize(supergraph, {}));
|
||||
CalculatorGraphConfig expected_graph =
|
||||
mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"pb(
|
||||
node {
|
||||
name: "switchcontainer__SwitchDemuxCalculator"
|
||||
calculator: "SwitchDemuxCalculator"
|
||||
input_stream: "ENABLE:enable"
|
||||
input_stream: "foo"
|
||||
output_stream: "C0__:switchcontainer__c0__foo"
|
||||
output_stream: "C1__:switchcontainer__c1__foo"
|
||||
options {
|
||||
[mediapipe.SwitchContainerOptions.ext] {}
|
||||
}
|
||||
input_stream_handler {
|
||||
input_stream_handler: "DefaultInputStreamHandler"
|
||||
}
|
||||
}
|
||||
node {
|
||||
name: "switchcontainer__TripleIntCalculator"
|
||||
calculator: "TripleIntCalculator"
|
||||
input_stream: "switchcontainer__c0__foo"
|
||||
output_stream: "switchcontainer__c0__bar"
|
||||
}
|
||||
node {
|
||||
name: "switchcontainer__PassThroughCalculator"
|
||||
calculator: "PassThroughCalculator"
|
||||
input_stream: "switchcontainer__c1__foo"
|
||||
output_stream: "switchcontainer__c1__bar"
|
||||
}
|
||||
node {
|
||||
name: "switchcontainer__SwitchMuxCalculator"
|
||||
calculator: "SwitchMuxCalculator"
|
||||
input_stream: "ENABLE:enable"
|
||||
input_stream: "C0__:switchcontainer__c0__bar"
|
||||
input_stream: "C1__:switchcontainer__c1__bar"
|
||||
output_stream: "bar"
|
||||
options {
|
||||
[mediapipe.SwitchContainerOptions.ext] {}
|
||||
}
|
||||
input_stream_handler {
|
||||
input_stream_handler: "ImmediateInputStreamHandler"
|
||||
}
|
||||
}
|
||||
node {
|
||||
calculator: "PassThroughCalculator"
|
||||
input_stream: "foo"
|
||||
input_stream: "bar"
|
||||
output_stream: "output_foo"
|
||||
output_stream: "output_bar"
|
||||
}
|
||||
input_stream: "foo"
|
||||
input_stream: "enable"
|
||||
executor {}
|
||||
input_side_packet: "timezone"
|
||||
)pb");
|
||||
EXPECT_THAT(graph.Config(), mediapipe::EqualsProto(expected_graph));
|
||||
}
|
||||
|
||||
// Runs the SwitchContainer with a node-level input_stream_handler.
|
||||
TEST(SwitchContainerTest, RunsWithInputStreamHandler) {
|
||||
EXPECT_TRUE(SubgraphRegistry::IsRegistered("SwitchContainer"));
|
||||
CalculatorGraphConfig supergraph = SubnodeContainerExample(
|
||||
R"pb(input_stream_handler {
|
||||
input_stream_handler: "DefaultInputStreamHandler"
|
||||
})pb");
|
||||
MP_EXPECT_OK(tool::ExpandSubgraphs(&supergraph));
|
||||
RunTestContainer(supergraph, true);
|
||||
}
|
||||
|
||||
// Shows the SwitchContainer container applied to a pair of simple subnodes.
|
||||
TEST(SwitchContainerTest, ApplyToSideSubnodes) {
|
||||
EXPECT_TRUE(SubgraphRegistry::IsRegistered("SwitchContainer"));
|
||||
|
||||
@@ -53,7 +53,7 @@ absl::Status RunGeneratorFillExpectations(
|
||||
<< " is not a registered packet generator.");
|
||||
|
||||
CalculatorContract contract;
|
||||
MP_RETURN_IF_ERROR(contract.Initialize(config));
|
||||
MP_RETURN_IF_ERROR(contract.Initialize(config, ""));
|
||||
|
||||
{
|
||||
LegacyCalculatorSupport::Scoped<CalculatorContract> s(&contract);
|
||||
|
||||
@@ -279,7 +279,7 @@ absl::Status NodeTypeInfo::Initialize(
|
||||
const PacketGeneratorConfig& node, int node_index) {
|
||||
node_.type = NodeType::PACKET_GENERATOR;
|
||||
node_.index = node_index;
|
||||
MP_RETURN_IF_ERROR(contract_.Initialize(node));
|
||||
MP_RETURN_IF_ERROR(contract_.Initialize(node, validated_graph.Package()));
|
||||
|
||||
// Run FillExpectations.
|
||||
const std::string& node_class = node.packet_generator();
|
||||
|
||||
@@ -161,10 +161,10 @@ class NodeTypeInfo {
|
||||
// all_input_streams
|
||||
// [node_info.InputStreamBaseIndex() +
|
||||
// node_info.InputStreamTypes().GetId("TAG", 2).value()];
|
||||
int input_side_packet_base_index_ = -1;
|
||||
int output_side_packet_base_index_ = -1;
|
||||
int input_stream_base_index_ = -1;
|
||||
int output_stream_base_index_ = -1;
|
||||
int input_side_packet_base_index_ = 0;
|
||||
int output_side_packet_base_index_ = 0;
|
||||
int input_stream_base_index_ = 0;
|
||||
int output_stream_base_index_ = 0;
|
||||
|
||||
// The type and index of this node.
|
||||
NodeRef node_;
|
||||
|
||||
Reference in New Issue
Block a user