Project import generated by Copybara.

PiperOrigin-RevId: 263889205
This commit is contained in:
MediaPipe Team
2019-08-16 18:56:48 -07:00
committed by jqtang
parent dc40414468
commit 294687295d
443 changed files with 33160 additions and 2011 deletions
+44 -2
View File
@@ -45,7 +45,7 @@ proto_library(
"//mediapipe/framework:packet_generator_proto",
"//mediapipe/framework:status_handler_proto",
"//mediapipe/framework:stream_handler_proto",
"@protobuf_archive//:any_proto",
"@com_google_protobuf//:any_proto",
],
)
@@ -137,7 +137,7 @@ mediapipe_cc_proto_library(
":packet_generator_cc_proto",
":status_handler_cc_proto",
":stream_handler_cc_proto",
"@protobuf_archive//:cc_wkt_protos",
"@com_google_protobuf//:cc_wkt_protos",
],
visibility = ["//mediapipe:__subpackages__"],
deps = [":calculator_proto"],
@@ -1083,6 +1083,13 @@ cc_library(
"scheduler_queue.h",
"scheduler_shared.h",
],
copts = select({
"//conditions:default": [],
"//mediapipe:apple": [
"-std=c++11",
"-ObjC++",
],
}),
visibility = [":mediapipe_internal"],
deps = [
":calculator_context",
@@ -1482,6 +1489,26 @@ cc_test(
],
)
cc_test(
name = "calculator_graph_bounds_test",
size = "small",
srcs = [
"calculator_graph_bounds_test.cc",
],
visibility = ["//visibility:public"],
deps = [
":calculator_context",
":calculator_framework",
":timestamp",
"//mediapipe/calculators/core:pass_through_calculator",
"//mediapipe/framework/port:gtest_main",
"//mediapipe/framework/port:logging",
"//mediapipe/framework/port:parse_text_proto",
"//mediapipe/framework/port:status",
"//mediapipe/framework/stream_handler:immediate_input_stream_handler",
],
)
cc_test(
name = "collection_test",
size = "small",
@@ -1636,3 +1663,18 @@ cc_test(
"//mediapipe/framework/tool:template_parser",
],
)
cc_test(
name = "subgraph_test",
srcs = ["subgraph_test.cc"],
deps = [
":calculator_framework",
":subgraph",
":test_calculators",
"//mediapipe/calculators/core:pass_through_calculator",
"//mediapipe/framework/port:gtest_main",
"//mediapipe/framework/port:status",
"//mediapipe/framework/tool:sink",
"//mediapipe/framework/tool/testdata:dub_quad_test_subgraph",
],
)
+7 -4
View File
@@ -170,6 +170,7 @@ message ProfilerConfig {
bool use_packet_timestamp_for_added_packet = 6;
// The maximum number of trace events buffered in memory.
// The default value buffers up to 20000 events.
int64 trace_log_capacity = 7;
// Trace event types that are not logged.
@@ -185,8 +186,7 @@ message ProfilerConfig {
int32 trace_log_count = 10;
// The interval in microseconds between trace log output.
// The value -1 specifies output only when the graph is closed.
// The default value specifies trace log output once every 1 sec.
// The default value specifies trace log output once every 0.5 sec.
int64 trace_log_interval_usec = 11;
// The interval in microseconds between TimeNow and the highest times
@@ -194,8 +194,8 @@ message ProfilerConfig {
// to be appended to the TraceBuffer.
int64 trace_log_margin_usec = 12;
// True specifies an event for each calculator invocation.
// False specifies a separate event for each start and finish time.
// False specifies an event for each calculator invocation.
// True specifies a separate event for each start and finish time.
bool trace_log_duration_events = 13;
// The number of trace log intervals per file. The total log duration is:
@@ -206,6 +206,9 @@ message ProfilerConfig {
// An option to turn ON/OFF writing trace files to disk. Saving trace files to
// disk is enabled by default.
bool trace_log_disabled = 15;
// If true, tracer timing events are recorded and reported.
bool trace_enabled = 16;
}
// Describes the topology and function of a MediaPipe Graph. The graph of
@@ -50,10 +50,14 @@ class CalculatorContract {
::mediapipe::Status Initialize(const CalculatorGraphConfig::Node& node);
::mediapipe::Status Initialize(const PacketGeneratorConfig& node);
::mediapipe::Status Initialize(const StatusHandlerConfig& node);
void SetNodeName(const std::string& node_name) { node_name_ = node_name; }
// Returns the options given to this node.
const CalculatorOptions& Options() const { return node_config_->options(); }
// Returns the name given to this node.
const std::string& GetNodeName() { return node_name_; }
// Returns the options given to this calculator. Template argument T must
// be the type of the protobuf extension message or the protobuf::Any
// message containing the options.
@@ -141,6 +145,7 @@ class CalculatorContract {
std::unique_ptr<PacketTypeSet> output_side_packets_;
std::string input_stream_handler_;
MediaPipeOptions input_stream_handler_options_;
std::string node_name_;
std::map<std::string, GraphServiceRequest> service_requests_;
};
+4 -4
View File
@@ -56,7 +56,7 @@
#ifndef MEDIAPIPE_DISABLE_GPU
namespace mediapipe {
class GpuResources;
class GpuSharedData;
struct GpuSharedData;
} // namespace mediapipe
#endif // !defined(MEDIAPIPE_DISABLE_GPU)
@@ -77,8 +77,8 @@ typedef ::mediapipe::StatusOr<OutputStreamPoller> StatusOrPoller;
// #include "mediapipe/framework/calculator_framework.h"
//
// mediapipe::CalculatorGraphConfig config;
// RETURN_IF_ERROR(mediapipe::tool::ParseGraphFromString(THE_CONFIG,
// &config)); mediapipe::CalculatorGraph graph;
// RETURN_IF_ERROR(mediapipe::tool::ParseGraphFromString(kGraphStr, &config));
// mediapipe::CalculatorGraph graph;
// RETURN_IF_ERROR(graph.Initialize(config));
//
// std::map<std::string, mediapipe::Packet> extra_side_packets;
@@ -135,7 +135,7 @@ class CalculatorGraph {
// |input_templates|. Every subgraph must have its graph type specified in
// CalclatorGraphConfig.type. A subgraph can be instantiated directly by
// specifying its type in |graph_type|. A template graph can be instantiated
// directly by specifying its template arguments in |arguments|.
// directly by specifying its template arguments in |options|.
::mediapipe::Status Initialize(
const std::vector<CalculatorGraphConfig>& configs,
const std::vector<CalculatorGraphTemplate>& templates,
@@ -0,0 +1,105 @@
// 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.
#include "mediapipe/framework/calculator_context.h"
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/port/canonical_errors.h"
#include "mediapipe/framework/port/gmock.h"
#include "mediapipe/framework/port/gtest.h"
#include "mediapipe/framework/port/logging.h"
#include "mediapipe/framework/port/parse_text_proto.h"
#include "mediapipe/framework/port/status.h"
#include "mediapipe/framework/port/status_matchers.h"
#include "mediapipe/framework/timestamp.h"
namespace mediapipe {
namespace {
class CustomBoundCalculator : public CalculatorBase {
public:
static ::mediapipe::Status GetContract(CalculatorContract* cc) {
cc->Inputs().Index(0).Set<int>();
cc->Outputs().Index(0).Set<int>();
return ::mediapipe::OkStatus();
}
::mediapipe::Status Open(CalculatorContext* cc) final {
return ::mediapipe::OkStatus();
}
::mediapipe::Status Process(CalculatorContext* cc) final {
cc->Outputs().Index(0).SetNextTimestampBound(cc->InputTimestamp() + 1);
return ::mediapipe::OkStatus();
}
};
REGISTER_CALCULATOR(CustomBoundCalculator);
// Shows that ImmediateInputStreamHandler allows bounds propagation.
TEST(CalculatorGraphBounds, ImmediateHandlerBounds) {
// CustomBoundCalculator produces only timestamp bounds.
// The first PassThroughCalculator propagates bounds using SetOffset(0).
// The second PassthroughCalculator delivers an output packet whenever the
// first PassThroughCalculator delivers a timestamp bound.
CalculatorGraphConfig config =
::mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"(
input_stream: 'input'
node {
calculator: 'CustomBoundCalculator'
input_stream: 'input'
output_stream: 'bounds'
}
node {
calculator: 'PassThroughCalculator'
input_stream: 'bounds'
output_stream: 'bounds_2'
input_stream_handler {
input_stream_handler: "ImmediateInputStreamHandler"
}
}
node {
calculator: 'PassThroughCalculator'
input_stream: 'bounds_2'
input_stream: 'input'
output_stream: 'bounds_output'
output_stream: 'output'
}
)");
CalculatorGraph graph;
std::vector<Packet> output_packets;
MEDIAPIPE_ASSERT_OK(graph.Initialize(config));
MEDIAPIPE_ASSERT_OK(graph.ObserveOutputStream("output", [&](const Packet& p) {
output_packets.push_back(p);
return ::mediapipe::OkStatus();
}));
MEDIAPIPE_ASSERT_OK(graph.StartRun({}));
MEDIAPIPE_ASSERT_OK(graph.WaitUntilIdle());
// Add four packets into the graph.
for (int i = 0; i < 4; ++i) {
Packet p = MakePacket<int>(33).At(Timestamp(i));
MEDIAPIPE_ASSERT_OK(graph.AddPacketToInputStream("input", p));
}
// Four packets arrive at the output only if timestamp bounds are propagated.
MEDIAPIPE_ASSERT_OK(graph.WaitUntilIdle());
EXPECT_EQ(output_packets.size(), 4);
// Eventually four packets arrive.
MEDIAPIPE_ASSERT_OK(graph.CloseAllPacketSources());
MEDIAPIPE_ASSERT_OK(graph.WaitUntilDone());
EXPECT_EQ(output_packets.size(), 4);
}
} // namespace
} // namespace mediapipe
@@ -0,0 +1,45 @@
"""Rule for simple expansion of template files. This performs a simple
search over the template file for the keys in substitutions,
and replaces them with the corresponding values.
Typical usage:
load("//tools/build_rules:expand_template.bzl", "expand_template")
expand_template(
name = "ExpandMyTemplate",
template = "my.template",
out = "my.txt",
substitutions = {
"$VAR1": "foo",
"$VAR2": "bar",
}
)
Args:
name: The name of the rule.
template: The template file to expand
out: The destination of the expanded file
substitutions: A dictionary mapping strings to their substitutions
is_executable: A boolean indicating whether the output file should be executable
"""
def expand_template_impl(ctx):
ctx.actions.expand_template(
template = ctx.file.template,
output = ctx.outputs.out,
substitutions = {
k: ctx.expand_location(v, ctx.attr.data)
for k, v in ctx.attr.substitutions.items()
},
is_executable = ctx.attr.is_executable,
)
expand_template = rule(
implementation = expand_template_impl,
attrs = {
"template": attr.label(mandatory = True, allow_single_file = True),
"substitutions": attr.string_dict(mandatory = True),
"out": attr.output(mandatory = True),
"is_executable": attr.bool(default = False, mandatory = False),
"data": attr.label_list(allow_files = True),
},
)
+27 -8
View File
@@ -23,7 +23,7 @@ Args:
output: The desired name of the output file. Optional.
"""
PROTOC = "@protobuf_archive//:protoc"
PROTOC = "@com_google_protobuf//:protoc"
def _canonicalize_proto_path_oss(all_protos, genfile_path):
"""For the protos from external repository, canonicalize the proto path and the file name.
@@ -42,12 +42,32 @@ def _canonicalize_proto_path_oss(all_protos, genfile_path):
proto_file_names.append(s.path)
return ([" --proto_path=" + path for path in proto_paths], proto_file_names)
def _get_proto_provider(dep):
"""Get the provider for protocol buffers from a dependnecy.
Necessary because Bazel does not provide the .proto. provider but ProtoInfo
cannot be created from Starlark at the moment.
Returns:
The provider containing information about protocol buffers.
"""
if ProtoInfo in dep:
return dep[ProtoInfo]
elif hasattr(dep, "proto"):
return dep.proto
else:
fail("cannot happen, rule definition requires .proto or ProtoInfo")
def _encode_binary_proto_impl(ctx):
"""Implementation of the encode_binary_proto rule."""
all_protos = depset()
for dep in ctx.attr.deps:
if hasattr(dep, "proto"):
all_protos = depset([], transitive = [all_protos, dep.proto.transitive_sources])
provider = _get_proto_provider(dep)
all_protos = depset(
direct = [],
transitive = [all_protos, provider.transitive_sources],
)
textpb = ctx.file.input
binarypb = ctx.outputs.output or ctx.actions.declare_file(
textpb.basename.rsplit(".", 1)[0] + ".binarypb",
@@ -84,7 +104,7 @@ encode_binary_proto = rule(
cfg = "host",
),
"deps": attr.label_list(
providers = ["proto"],
providers = [[ProtoInfo], ["proto"]],
),
"input": attr.label(
mandatory = True,
@@ -100,9 +120,9 @@ encode_binary_proto = rule(
def _generate_proto_descriptor_set_impl(ctx):
"""Implementation of the generate_proto_descriptor_set rule."""
all_protos = depset(transitive = [
dep.proto.transitive_sources
_get_proto_provider(dep).transitive_sources
for dep in ctx.attr.deps
if hasattr(dep, "proto")
if ProtoInfo in dep or hasattr(dep, "proto")
])
descriptor = ctx.outputs.output
@@ -115,7 +135,6 @@ def _generate_proto_descriptor_set_impl(ctx):
executable = ctx.executable._proto_compiler,
arguments = [
"--descriptor_set_out=%s" % descriptor.path,
"--absolute_paths",
"--proto_path=" + ctx.genfiles_dir.path,
"--proto_path=.",
] +
@@ -132,7 +151,7 @@ generate_proto_descriptor_set = rule(
cfg = "host",
),
"deps": attr.label_list(
providers = ["proto"],
providers = [[ProtoInfo], ["proto"]],
),
},
outputs = {"output": "%{name}.proto.bin"},
+18 -2
View File
@@ -186,7 +186,7 @@ cc_library(
"//mediapipe/framework/port:statusor",
"//mediapipe/framework/formats/annotation:rasterization_cc_proto",
] + select({
"//conditions:default": ["@protobuf_archive//:protobuf"],
"//conditions:default": ["@com_google_protobuf//:protobuf"],
}) + select({
"//conditions:default": [
"//mediapipe/framework/port:opencv_imgproc",
@@ -195,6 +195,7 @@ cc_library(
"//conditions:default": [
],
"//mediapipe:android": [],
"//mediapipe:apple": [],
}),
alwayslink = 1,
)
@@ -241,6 +242,21 @@ proto_library(
mediapipe_cc_proto_library(
name = "rect_cc_proto",
srcs = ["rect.proto"],
visibility = ["//mediapipe:__subpackages__"],
visibility = [
"//mediapipe:__subpackages__",
],
deps = [":rect_proto"],
)
proto_library(
name = "landmark_proto",
srcs = ["landmark.proto"],
visibility = ["//mediapipe:__subpackages__"],
)
mediapipe_cc_proto_library(
name = "landmark_cc_proto",
srcs = ["landmark.proto"],
visibility = ["//mediapipe:__subpackages__"],
deps = [":landmark_proto"],
)
-43
View File
@@ -12,29 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
//
// Get a WImageView of the ImageFrame
// WImageView_b wimage_view =
// ::mediapipe::formats::WImageView<WImageView_b>(&const_frame);
// The mutable version.
// WImageView_b wimage_view =
// ::mediapipe::formats::MutableWImageView<WImageView_b>(&frame);
//
// Get an IplImage view of the ImageFrame (this is efficient):
// ::mediapipe::formats::IplView(&frame);
//
// Get a cv::Mat view of the ImageFrame (this is efficient):
// ::mediapipe::formats::MatView(&frame);
//
// Make a constant colored ImageFrame:
// const uint8 kColor[] = {kRed, kGreen, kBlue, kAlpha};
// ImageFrame frame(ImageFormat::SRGB, kWidth, kHeight);
// ::mediapipe::formats::MutableWImageView<WImageView_b>(&frame).Set(kColor);
//
// Copying image data from a WImage:
// ::mediapipe::formats::MutableWImageView<WImageView1_b>(&gray8_image_frame)
// .CopyFrom(grayscale_wimage);
//
// Copying data from raw data (stored contiguously):
// frame.CopyPixelData(format, width, height, raw_data_ptr,
// ImageFrame::kDefaultAlignmentBoundary);
@@ -51,29 +31,6 @@
// cv::Mat destination = ::mediapipe::formats::MatView(&small_image);
// cv::resize(::mediapipe::formats::MatView(&large_image), destination,
// destination.size(), 0, 0, cv::INTER_LINEAR);
//
// Copy an ImageFrame into a RawImage:
// RawImage image;
// frame.CopyToResizeableImage(&image);
//
// Encoding a PNG image:
// WImageIO::EncodePNG(frame.Image<WImage_b>(), &image_string);
//
// Encoding a JPEG image:
// WImageIO::EncodeJPEG(frame.Image<WImage_b>(), 75 /* quality */,
// &image_string);
//
// Decoding a (RGB) JPEG/PNG/WebP image:
// auto wimage = gtl::MakeUnique<WImageBuffer3_b>();
// auto* wimage_ptr = wimage.get();
// WImageIO::DecodeImage(image_string, wimage.get());
// auto frame = gtl::MakeUnique<ImageFrame>(
// /*format=*/ImageFormat::SRGB, /*width=*/wimage->Width(),
// /*height=*/wimage->Height(),
// /*width_step=*/wimage->WidthStep(),
// /*pixel_data=*/wimage->ImageData(),
// /*deleter=*/[wimage_ptr](uint8*) { delete wimage_ptr; });
// wimage.release(); // wimage is owned by frame now.
#ifndef MEDIAPIPE_FRAMEWORK_FORMATS_IMAGE_FRAME_H_
#define MEDIAPIPE_FRAMEWORK_FORMATS_IMAGE_FRAME_H_
@@ -0,0 +1,34 @@
// 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.
syntax = "proto2";
package mediapipe;
// A landmark that can have 1 to 3 dimensions. Use x for 1D points, (x, y) for
// 2D points and (x, y, z) for 3D points. For more dimensions, consider using
// matrix_data.proto.
message Landmark {
optional float x = 1;
optional float y = 2;
optional float z = 3;
}
// A normalized version of above Landmark proto. All coordiates should be within
// [0, 1].
message NormalizedLandmark {
optional float x = 1;
optional float y = 2;
optional float z = 3;
}
+3 -3
View File
@@ -151,15 +151,15 @@ template <typename Container>
// If the caller is MovePackets(), packet's underlying holder should be
// transferred into queue_. Otherwise, queue_ keeps a copy of the packet.
++num_packets_added_;
VLOG(2) << "Input stream:" << name_
<< " has added packet at time: " << packet.Timestamp();
if (std::is_const<
typename std::remove_reference<Container>::type>::value) {
queue_.emplace_back(packet);
} else {
queue_.emplace_back(std::move(packet));
}
++num_packets_added_;
VLOG(2) << "Input stream:" << name_
<< " has added packet at time: " << packet.Timestamp();
}
queue_became_full = (!was_queue_full && max_queue_size_ != -1 &&
queue_.size() >= max_queue_size_);
@@ -16,8 +16,6 @@
namespace mediapipe {
// We only define this variable for two specializations of the template
// because it is only meant to be used for these two types.
#if EMSCRIPTEN_WORKAROUND_FOR_B121216479
template <>
CalculatorContext*
@@ -99,6 +99,23 @@ class LegacyCalculatorSupport {
};
};
// We only declare this variable for two specializations of the template because
// it is only meant to be used for these two types.
#if EMSCRIPTEN_WORKAROUND_FOR_B121216479
template <>
CalculatorContext* LegacyCalculatorSupport::Scoped<CalculatorContext>::current_;
template <>
CalculatorContract*
LegacyCalculatorSupport::Scoped<CalculatorContract>::current_;
#else
template <>
thread_local CalculatorContext*
LegacyCalculatorSupport::Scoped<CalculatorContext>::current_;
template <>
thread_local CalculatorContract*
LegacyCalculatorSupport::Scoped<CalculatorContract>::current_;
#endif // EMSCRIPTEN_WORKAROUND_FOR_B121216479
} // namespace mediapipe
#endif // MEDIAPIPE_FRAMEWORK_LEGACY_CALCULATOR_SUPPORT_H_
-16
View File
@@ -46,12 +46,6 @@ class Packet;
namespace packet_internal {
class HolderBase;
// Defined in packet_serialization.cc
// TODO Remove once friend statements are unneeded.
::mediapipe::StatusOr<std::string> SerializePacket(const Packet& packet);
::mediapipe::StatusOr<std::string> SerializePacketContents(
const Packet& packet);
Packet Create(HolderBase* holder);
Packet Create(HolderBase* holder, Timestamp timestamp);
const HolderBase* GetHolder(const Packet& packet);
@@ -70,9 +64,6 @@ const HolderBase* GetHolder(const Packet& packet);
// PointToForeign allows a Packet to be constructed which does not
// own it's data.
//
// See packet_serialization.h for helper functions to serialize and
// deserialize packets.
//
// This class is thread compatible.
class Packet {
public:
@@ -200,13 +191,6 @@ class Packet {
std::string DebugTypeName() const;
private:
// TODO Change serialize_fn to take a Packet instead of a
// HolderBase, removing the need to friend these classes.
friend ::mediapipe::StatusOr<std::string> SerializePacket(
const Packet& packet);
friend ::mediapipe::StatusOr<std::string> SerializePacketContents(
const Packet& packet);
friend Packet packet_internal::Create(packet_internal::HolderBase* holder);
friend Packet packet_internal::Create(packet_internal::HolderBase* holder,
class Timestamp timestamp);
+3 -2
View File
@@ -22,8 +22,9 @@
// For consistency, we now set MEDIAPIPE_MOBILE there too. However, for the sake
// of projects that may want to build MediaPipe using alternative build systems,
// we also try to set platform-specific defines in this header if missing.
#if !defined(MEDIAPIPE_MOBILE) && \
(defined(__ANDROID__) || defined(__APPLE__) || defined(__EMSCRIPTEN__))
#if !defined(MEDIAPIPE_MOBILE) && \
(defined(__ANDROID__) || (defined(__APPLE__) && !TARGET_OS_OSX) || \
defined(__EMSCRIPTEN__))
#define MEDIAPIPE_MOBILE
#endif
+7 -6
View File
@@ -60,7 +60,7 @@ cc_library(
":core_proto",
"//mediapipe/framework:port",
] + select({
"//conditions:default": ["@protobuf_archive//:protobuf"],
"//conditions:default": ["@com_google_protobuf//:protobuf"],
}),
)
@@ -75,7 +75,7 @@ cc_library(
":core_proto",
"//mediapipe/framework:port",
] + select({
"//conditions:default": ["@protobuf_archive//:protobuf"],
"//conditions:default": ["@com_google_protobuf//:protobuf"],
}),
)
@@ -96,7 +96,7 @@ cc_library(
visibility = ["//visibility:public"],
deps = [
"//mediapipe/framework:port",
"@com_google_glog//:glog",
"@com_github_glog_glog//:glog",
],
)
@@ -110,7 +110,7 @@ cc_library(
deps = [
"//mediapipe/framework:port",
] + select({
"//conditions:default": ["@protobuf_archive//:protobuf"],
"//conditions:default": ["@com_google_protobuf//:protobuf"],
}),
)
@@ -175,7 +175,7 @@ cc_library(
visibility = ["//visibility:public"],
deps = [
"//mediapipe/framework:port",
"@com_google_glog//:glog",
"@com_github_glog_glog//:glog",
],
)
@@ -258,7 +258,7 @@ cc_library(
":logging",
"//mediapipe/framework:port",
] + select({
"//conditions:default": ["@protobuf_archive//:protobuf"],
"//conditions:default": ["@com_google_protobuf//:protobuf"],
}),
)
@@ -351,6 +351,7 @@ cc_library(
deps = select({
"//conditions:default": [":threadpool_impl_default_to_google"],
"//mediapipe:android": [":threadpool_impl_default_to_mediapipe"],
"//mediapipe:apple": [":threadpool_impl_default_to_mediapipe"],
}),
)
@@ -20,10 +20,10 @@
#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
#include "google/protobuf/wire_format_lite.h"
#include "google/protobuf/wire_format_lite_inl.h"
#include "mediapipe/framework/port.h"
#include "mediapipe/framework/port/core_proto_inc.h"
#include "mediapipe/framework/port/proto_ns.h"
namespace mediapipe {
using proto_int64 = google::protobuf::int64;
using proto_uint64 = google::protobuf::uint64;
+8 -8
View File
@@ -3,8 +3,7 @@
""".bzl file for mediapipe open source build configs."""
load("@protobuf_archive//:protobuf.bzl", "cc_proto_library")
load("@protobuf_archive//:protobuf.bzl", "py_proto_library")
load("@com_google_protobuf//:protobuf.bzl", "cc_proto_library", "py_proto_library")
def mediapipe_py_proto_library(
name,
@@ -26,9 +25,9 @@ def mediapipe_py_proto_library(
name = name,
srcs = srcs,
visibility = visibility,
default_runtime = "@protobuf_archive//:protobuf_python",
protoc = "@protobuf_archive//:protoc",
deps = py_proto_deps + ["@protobuf_archive//:protobuf_python"],
default_runtime = "@com_google_protobuf//:protobuf_python",
protoc = "@com_google_protobuf//:protoc",
deps = py_proto_deps + ["@com_google_protobuf//:protobuf_python"],
)
def mediapipe_cc_proto_library(name, srcs, visibility, deps = [], cc_deps = [], testonly = 0):
@@ -48,7 +47,8 @@ def mediapipe_cc_proto_library(name, srcs, visibility, deps = [], cc_deps = [],
visibility = visibility,
deps = cc_deps,
testonly = testonly,
cc_libs = ["@protobuf_archive//:protobuf"],
protoc = "@protobuf_archive//:protoc",
default_runtime = "@protobuf_archive//:protobuf",
cc_libs = ["@com_google_protobuf//:protobuf"],
protoc = "@com_google_protobuf//:protoc",
default_runtime = "@com_google_protobuf//:protobuf",
alwayslink = 1,
)
+13 -1
View File
@@ -21,7 +21,7 @@
#ifdef CV_VERSION_EPOCH // for OpenCV 2.x
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/video/video.hpp>
// Copied from "opencv2/videoio.hpp" in OpenCV 4.0.1
namespace cv {
enum VideoCaptureProperties {
@@ -80,7 +80,19 @@ inline int fourcc(char c1, char c2, char c3, char c4) {
} // namespace mediapipe
#else
#include <opencv2/video.hpp>
#include <opencv2/videoio.hpp>
#if CV_VERSION_MAJOR == 4
#include <opencv2/optflow.hpp>
namespace cv {
inline Ptr<DenseOpticalFlow> createOptFlow_DualTVL1() {
return optflow::createOptFlow_DualTVL1();
}
} // namespace cv
#endif
namespace mediapipe {
inline int fourcc(char c1, char c2, char c3, char c4) {
return cv::VideoWriter::fourcc(c1, c2, c3, c4);
+13 -2
View File
@@ -18,7 +18,7 @@ licenses(["notice"]) # Apache 2.0
package(default_visibility = ["//mediapipe/framework:__subpackages__"])
# This is used to enable the profiler on platforms where it is not on by default.
# To enable, pass --define=MEDIAPIPE_PROFILING=1 to bazel.
# To enable, pass --define MEDIAPIPE_PROFILING=1 to bazel.
config_setting(
name = "graph_profiler_enabled",
values = {
@@ -223,8 +223,8 @@ cc_test(
":graph_profiler",
":graph_tracer",
":test_context_builder",
"//mediapipe/calculators/core:flow_limiter_calculator",
"//mediapipe/calculators/core:immediate_mux_calculator",
"//mediapipe/calculators/core:real_time_flow_limiter_calculator",
"//mediapipe/calculators/core:round_robin_demux_calculator",
"//mediapipe/framework:calculator_cc_proto",
"//mediapipe/framework:calculator_framework",
@@ -268,9 +268,19 @@ cc_library(
srcs = select({
"//conditions:default": ["profiler_resource_util.cc"],
"//mediapipe:android": ["profiler_resource_util_android.cc"],
"//mediapipe:apple": ["profiler_resource_util_apple.cc"],
"//mediapipe:macos": ["profiler_resource_util.cc"],
}),
hdrs = ["profiler_resource_util.h"],
# We use Objective-C++ on iOS.
copts = select({
"//conditions:default": [],
"//mediapipe:apple": [
"-std=c++11",
"-ObjC++",
],
"//mediapipe:macos": [],
}),
visibility = [
"//mediapipe/framework:mediapipe_internal",
],
@@ -285,5 +295,6 @@ cc_library(
"//mediapipe:android": [
"//mediapipe/java/com/google/mediapipe/framework/jni:jni_util",
],
"//mediapipe:apple": [],
}),
)
@@ -66,7 +66,7 @@ bool IsProfilerEnabled(const ProfilerConfig& profiler_config) {
// Returns true if trace events are recorded.
bool IsTracerEnabled(const ProfilerConfig& profiler_config) {
return profiler_config.trace_log_capacity() > 0;
return profiler_config.trace_enabled();
}
// Returns true if trace events are written to a log file.
@@ -586,7 +586,7 @@ void AssignNodeNames(GraphProfile* profile) {
absl::Microseconds(profiler_config_.trace_log_margin_usec());
GraphProfile profile;
GraphTrace* trace = profile.add_graph_trace();
if (profiler_config_.trace_log_duration_events()) {
if (!profiler_config_.trace_log_duration_events()) {
tracer()->GetTrace(previous_log_end_time_, end_time, trace);
} else {
tracer()->GetLog(previous_log_end_time_, end_time, trace);
@@ -0,0 +1,74 @@
// 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.
#import <UIKit/UIKit.h>
#import <XCTest/XCTest.h>
#include "absl/memory/memory.h"
#include "mediapipe/framework/profiler/graph_profiler.h"
#include "mediapipe/framework/profiler/profiler_resource_util.h"
#include "mediapipe/objc/MPPGraph.h"
#include "mediapipe/objc/MPPGraphTestBase.h"
static NSString* const kTraceFilename = @"mediapipe_trace_0.binarypb";
static const char* kOutputStream = "counter";
@interface GraphProfilerTest : MPPGraphTestBase
@end
@implementation GraphProfilerTest
- (void)mediapipeGraph:(MPPGraph*)graph
didOutputPacket:(const mediapipe::Packet&)packet
fromStream:(const std::string&)streamName {
XCTAssertTrue(streamName == kOutputStream);
NSLog(@"Received counter packet.");
}
- (void)testDefaultTraceLogPathValueIsSet {
mediapipe::CalculatorGraphConfig graphConfig;
mediapipe::CalculatorGraphConfig::Node* node = graphConfig.add_node();
node->set_calculator("SimpleCalculator");
node->add_output_stream(kOutputStream);
mediapipe::ProfilerConfig* profilerConfig = graphConfig.mutable_profiler_config();
profilerConfig->set_trace_enabled(true);
profilerConfig->set_enable_profiler(true);
profilerConfig->set_trace_log_disabled(false);
MPPGraph* graph = [[MPPGraph alloc] initWithGraphConfig:graphConfig];
[graph addFrameOutputStream:kOutputStream outputPacketType:MediaPipePacketRaw];
graph.delegate = self;
NSError* error;
BOOL success = [graph startWithError:&error];
XCTAssertTrue(success, @"%@", error.localizedDescription);
// Shut down the graph.
success = [graph waitUntilDoneWithError:&error];
XCTAssertTrue(success, @"%@", error.localizedDescription);
mediapipe::StatusOr<string> getTraceLogDir = mediapipe::GetDefaultTraceLogDirectory();
XCTAssertTrue(getTraceLogDir.ok(), "GetDefaultTraceLogDirectory failed.");
NSString* directoryPath = [NSString stringWithCString:(*getTraceLogDir).c_str()
encoding:[NSString defaultCStringEncoding]];
NSString* traceLogPath = [directoryPath stringByAppendingPathComponent:kTraceFilename];
BOOL traceLogFileExists = [[NSFileManager defaultManager] fileExistsAtPath:traceLogPath];
XCTAssertTrue(traceLogFileExists, @"Trace log file not found at path: %@", traceLogPath);
}
@end
@@ -342,7 +342,7 @@ TEST_F(GraphProfilerTestPeer, Initialize) {
output_stream: "source_stream2"
}
node {
calculator: "RealTimeFlowLimiterCalculator"
calculator: "FlowLimiterCalculator"
input_stream: "FINISHED:my_other_stream"
input_stream: "source_stream2"
input_stream_info: {
@@ -378,7 +378,7 @@ TEST_F(GraphProfilerTestPeer, Initialize) {
CheckHasProfilesWithInputStreamName("A_Normal_Calc",
{"input_stream", "source_stream1"});
CheckHasProfilesWithInputStreamName("Another_Source_Calc", {});
CheckHasProfilesWithInputStreamName("RealTimeFlowLimiterCalculator",
CheckHasProfilesWithInputStreamName("FlowLimiterCalculator",
{"source_stream2", "my_other_stream"});
CheckHasProfilesWithInputStreamName("Another_Normal_Calc",
{"my_stream", "gated_source_stream2"});
+4 -2
View File
@@ -27,7 +27,7 @@ namespace mediapipe {
namespace {
const absl::Duration kDefaultTraceLogInterval = absl::Milliseconds(100);
const absl::Duration kDefaultTraceLogInterval = absl::Milliseconds(500);
// Returns a unique identifier for the current thread.
inline int GetCurrentThreadId() {
@@ -45,7 +45,9 @@ absl::Duration GraphTracer::GetTraceLogInterval() {
}
int64 GraphTracer::GetTraceLogCapacity() {
return profiler_config_.trace_log_capacity();
return profiler_config_.trace_log_capacity()
? profiler_config_.trace_log_capacity()
: 20000;
}
GraphTracer::GraphTracer(const ProfilerConfig& profiler_config)
@@ -70,6 +70,7 @@ class GraphTracerTest : public ::testing::Test {
void SetUpGraphTracer(size_t size) {
ProfilerConfig profiler_config;
profiler_config.set_trace_log_capacity(size);
profiler_config.set_trace_enabled(true);
tracer_ = absl::make_unique<GraphTracer>(profiler_config);
}
@@ -334,7 +335,7 @@ class GraphTracerE2ETest : public ::testing::Test {
profiler_config {
histogram_interval_size_usec: 1000
num_histogram_intervals: 100
trace_log_capacity: 1000000
trace_enabled: true
}
)",
&graph_config_));
@@ -348,7 +349,7 @@ class GraphTracerE2ETest : public ::testing::Test {
output_stream: "input_packets_0"
}
node {
calculator: 'RealTimeFlowLimiterCalculator'
calculator: 'FlowLimiterCalculator'
input_stream_handler {
input_stream_handler: 'ImmediateInputStreamHandler'
}
@@ -392,7 +393,7 @@ class GraphTracerE2ETest : public ::testing::Test {
profiler_config {
histogram_interval_size_usec: 1000
num_histogram_intervals: 100
trace_log_capacity: 1000000
trace_enabled: true
}
)",
&graph_config_));
@@ -928,7 +929,7 @@ TEST_F(GraphTracerE2ETest, DemuxGraphLogFile) {
RunDemuxInFlightGraph();
GraphProfile profile;
ReadGraphProfile(absl::StrCat(log_path, 0, ".binarypb"), &profile);
EXPECT_EQ(117, profile.graph_trace(0).calculator_trace().size());
EXPECT_EQ(89, profile.graph_trace(0).calculator_trace().size());
}
TEST_F(GraphTracerE2ETest, DemuxGraphLogFiles) {
@@ -951,7 +952,7 @@ TEST_F(GraphTracerE2ETest, DemuxGraphLogFiles) {
event_counts.push_back(count);
graph_profiles.push_back(profile);
}
std::vector<int> expected = {45, 50, 22, 0, 0, 0, 0};
std::vector<int> expected = {37, 42, 19, 0, 0, 0, 0};
EXPECT_EQ(event_counts, expected);
GraphProfile& profile_2 = graph_profiles[2];
profile_2.clear_calculator_profiles();
@@ -966,7 +967,7 @@ TEST_F(GraphTracerE2ETest, DemuxGraphLogFiles) {
base_time: 1544086800000000
base_timestamp: 0
calculator_name: "LambdaCalculator_1"
calculator_name: "RealTimeFlowLimiterCalculator"
calculator_name: "FlowLimiterCalculator"
calculator_name: "RoundRobinDemuxCalculator"
calculator_name: "LambdaCalculator_1"
calculator_name: "LambdaCalculator"
@@ -1080,20 +1081,14 @@ TEST_F(GraphTracerE2ETest, DemuxGraphLogFiles) {
input_timestamp: 50000
event_type: PROCESS
start_time: 65004
input_trace { packet_timestamp: 50000 stream_id: 5 }
}
calculator_trace {
node_id: 5
input_timestamp: 50000
event_type: PROCESS
finish_time: 65004
input_trace {
start_time: 65004
finish_time: 65004
packet_timestamp: 50000
stream_id: 5
}
output_trace { packet_timestamp: 50000 stream_id: 6 }
}
calculator_trace {
node_id: 5
input_timestamp: 50000
event_type: PROCESS
finish_time: 65004
output_trace { packet_timestamp: 50000 stream_id: 7 }
}
calculator_trace {
@@ -1121,7 +1116,12 @@ TEST_F(GraphTracerE2ETest, DemuxGraphLogFiles) {
input_timestamp: 50000
event_type: PROCESS
start_time: 65004
input_trace { packet_timestamp: 50000 stream_id: 7 }
input_trace {
start_time: 65004
finish_time: 65004
packet_timestamp: 50000
stream_id: 7
}
}
calculator_trace {
node_id: 1
@@ -1176,13 +1176,13 @@ TEST_F(GraphTracerE2ETest, DemuxGraphLogFiles) {
input_timestamp: 40000
event_type: PROCESS
start_time: 70004
input_trace { packet_timestamp: 40000 stream_id: 8 }
}
calculator_trace {
node_id: 5
input_timestamp: 40000
event_type: PROCESS
finish_time: 70004
input_trace {
start_time: 70004
finish_time: 70004
packet_timestamp: 40000
stream_id: 8
}
output_trace { packet_timestamp: 50001 stream_id: 7 }
}
calculator_trace {
@@ -1205,7 +1205,12 @@ TEST_F(GraphTracerE2ETest, DemuxGraphLogFiles) {
input_timestamp: 50001
event_type: PROCESS
start_time: 70004
input_trace { packet_timestamp: 50001 stream_id: 7 }
input_trace {
start_time: 70004
finish_time: 70004
packet_timestamp: 50001
stream_id: 7
}
}
calculator_trace {
node_id: 1
@@ -1234,8 +1239,8 @@ TEST_F(GraphTracerE2ETest, DemuxGraphLogFiles) {
input_side_packet: "callback_2"
}
node {
name: "RealTimeFlowLimiterCalculator"
calculator: "RealTimeFlowLimiterCalculator"
name: "FlowLimiterCalculator"
calculator: "FlowLimiterCalculator"
input_stream: "input_packets_0"
input_stream: "FINISHED:finish_indicator"
output_stream: "input_0_sampled"
@@ -1281,10 +1286,10 @@ TEST_F(GraphTracerE2ETest, DemuxGraphLogFiles) {
profiler_config {
histogram_interval_size_usec: 1000
num_histogram_intervals: 100
trace_log_capacity: 1000000
trace_log_count: 100
trace_log_interval_usec: 2500
trace_log_interval_count: 10
trace_enabled: true
}
}
)")));
@@ -17,6 +17,7 @@
#include <string>
#include "mediapipe/framework/port/status.h"
#include "mediapipe/framework/port/statusor.h"
namespace mediapipe {
@@ -15,6 +15,7 @@
#import <Foundation/Foundation.h>
#include "mediapipe/framework/port/canonical_errors.h"
#include "mediapipe/framework/profiler/profiler_resource_util.h"
namespace mediapipe {
@@ -24,10 +25,24 @@ StatusOr<std::string> GetDefaultTraceLogDirectory() {
NSURL* documents_directory_url = [[[NSFileManager defaultManager]
URLsForDirectory:NSDocumentDirectory
inDomains:NSUserDomainMask] lastObject];
NSString* ns_documents_directory = [documents_directory_url absoluteString];
std::string documents_directory = [ns_documents_directory UTF8String];
return documents_directory;
// Note: "createDirectoryAtURL:..." method doesn't successfully create
// the directory, hence this code uses "createDirectoryAtPath:..".
NSString* ns_documents_directory = [documents_directory_url absoluteString];
NSError* error;
BOOL success = [[NSFileManager defaultManager]
createDirectoryAtPath:ns_documents_directory
withIntermediateDirectories:YES
attributes:nil
error:&error];
if (!success) {
// TODO: Use NSError+util_status to get status from NSError.
return ::mediapipe::InternalError(
[[error localizedDescription] UTF8String]);
}
std::string trace_log_directory = [ns_documents_directory UTF8String];
return trace_log_directory;
}
} // namespace mediapipe
@@ -0,0 +1,30 @@
# Copyright 2019 The MediaPipe Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
licenses(["notice"]) # Apache 2.0
package(
default_visibility = ["//mediapipe/framework:__subpackages__"],
)
cc_library(
name = "simple_calculator",
srcs = ["simple_calculator.cc"],
deps = [
"//mediapipe/framework:calculator_framework",
"//mediapipe/framework/port:status",
],
alwayslink = 1,
)
@@ -0,0 +1,49 @@
// 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.
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/port/status.h"
namespace mediapipe {
class SimpleCalculator : public CalculatorBase {
public:
static ::mediapipe::Status GetContract(CalculatorContract* cc) {
cc->Outputs().Index(0).Set<int>();
if (cc->InputSidePackets().HasTag("MAX_COUNT")) {
cc->InputSidePackets().Tag("MAX_COUNT").Set<int>();
}
return ::mediapipe::OkStatus();
}
::mediapipe::Status Process(CalculatorContext* cc) final {
LOG(WARNING) << "Simple Calculator Process called, count_: " << count_;
int max_count = 1;
if (cc->InputSidePackets().HasTag("MAX_COUNT")) {
max_count = cc->InputSidePackets().Tag("MAX_COUNT").Get<int>();
}
if (count_ >= max_count) {
return tool::StatusStop();
}
cc->Outputs().Index(0).Add(new int(count_), Timestamp(count_));
++count_;
return ::mediapipe::OkStatus();
}
private:
int count_ = 0;
};
REGISTER_CALCULATOR(SimpleCalculator);
} // namespace mediapipe
@@ -61,9 +61,9 @@ ImmediateInputStreamHandler::ImmediateInputStreamHandler(
timestamp_bounds_(std::move(tag_map)) {}
NodeReadiness ImmediateInputStreamHandler::GetNodeReadiness(
Timestamp* input_timestamp) {
Timestamp min_stream_timestamp = Timestamp::Done();
*input_timestamp = Timestamp::Done();
Timestamp* min_stream_timestamp) {
*min_stream_timestamp = Timestamp::Done();
Timestamp input_timestamp = Timestamp::Done();
bool stream_became_done = false;
for (CollectionItemId i = input_stream_managers_.BeginId();
@@ -72,9 +72,9 @@ NodeReadiness ImmediateInputStreamHandler::GetNodeReadiness(
bool empty;
Timestamp stream_timestamp = stream->MinTimestampOrBound(&empty);
if (!empty) {
*input_timestamp = std::min(*input_timestamp, stream_timestamp);
input_timestamp = std::min(input_timestamp, stream_timestamp);
}
min_stream_timestamp = std::min(min_stream_timestamp, stream_timestamp);
*min_stream_timestamp = std::min(*min_stream_timestamp, stream_timestamp);
if (stream_timestamp != timestamp_bounds_.Get(i)) {
if (stream_timestamp == Timestamp::Done()) {
stream_became_done = true;
@@ -83,16 +83,17 @@ NodeReadiness ImmediateInputStreamHandler::GetNodeReadiness(
}
}
if (min_stream_timestamp == Timestamp::Done()) {
if (*min_stream_timestamp == Timestamp::Done()) {
return NodeReadiness::kReadyForClose;
}
if (*input_timestamp < Timestamp::Done()) {
if (input_timestamp < Timestamp::Done()) {
// On kReadyForProcess, the input_timestamp is returned.
*min_stream_timestamp = input_timestamp;
return NodeReadiness::kReadyForProcess;
}
if (stream_became_done) {
*input_timestamp = min_stream_timestamp;
return NodeReadiness::kReadyForProcess;
}
@@ -1,3 +1,17 @@
// 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.
#include <vector>
#include "mediapipe/framework/calculator_framework.h"
+79
View File
@@ -0,0 +1,79 @@
// 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.
#include "mediapipe/framework/subgraph.h"
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/port/gmock.h"
#include "mediapipe/framework/port/gtest.h"
// Because of portability issues, we include this directly.
#include "mediapipe/framework/port/status_matchers.h" // NOLINT(build/deprecated)
namespace mediapipe {
namespace {
class SubgraphTest : public ::testing::Test {
protected:
void TestGraphEnclosing(const std::string& subgraph_type_name) {
EXPECT_TRUE(SubgraphRegistry::IsRegistered(subgraph_type_name));
CalculatorGraphConfig config;
config.add_input_stream("in");
CalculatorGraphConfig::Node* node = config.add_node();
node->set_calculator(subgraph_type_name);
node->add_input_stream("INTS:in");
node->add_output_stream("DUBS:dubs_tmp");
node->add_output_stream("QUADS:quads");
node = config.add_node();
node->set_calculator("PassThroughCalculator");
node->add_input_stream("dubs_tmp");
node->add_output_stream("dubs");
std::vector<Packet> dubs;
tool::AddVectorSink("dubs", &config, &dubs);
std::vector<Packet> quads;
tool::AddVectorSink("quads", &config, &quads);
CalculatorGraph graph;
MEDIAPIPE_ASSERT_OK(graph.Initialize(config));
MEDIAPIPE_ASSERT_OK(graph.StartRun({}));
constexpr int kCount = 5;
for (int i = 0; i < kCount; ++i) {
MEDIAPIPE_ASSERT_OK(graph.AddPacketToInputStream(
"in", MakePacket<int>(i).At(Timestamp(i))));
}
MEDIAPIPE_ASSERT_OK(graph.CloseInputStream("in"));
MEDIAPIPE_ASSERT_OK(graph.WaitUntilDone());
EXPECT_EQ(dubs.size(), kCount);
EXPECT_EQ(quads.size(), kCount);
for (int i = 0; i < kCount; ++i) {
EXPECT_EQ(i * 2, dubs[i].Get<int>());
EXPECT_EQ(i * 4, quads[i].Get<int>());
}
}
};
// Tests registration of subgraph named "DubQuadTestSubgraph" using target
// "dub_quad_test_subgraph" from macro "mediapipe_simple_subgraph".
TEST_F(SubgraphTest, LinkedSubgraph) {
TestGraphEnclosing("DubQuadTestSubgraph");
}
} // namespace
} // namespace mediapipe
+1 -1
View File
@@ -52,7 +52,7 @@ mediapipe_cc_proto_library(
proto_library(
name = "zoo_mutator_proto",
srcs = ["zoo_mutator.proto"],
deps = ["@protobuf_archive//:any_proto"],
deps = ["@com_google_protobuf//:any_proto"],
)
proto_library(
+122 -3
View File
@@ -17,18 +17,57 @@ licenses(["notice"]) # Apache 2.0
package(default_visibility = ["//visibility:private"])
load("//mediapipe/framework/port:build_config.bzl", "mediapipe_cc_proto_library")
load(
"//mediapipe/framework/port:build_config.bzl",
"mediapipe_cc_proto_library",
)
load(
"//mediapipe/framework/tool:mediapipe_graph.bzl",
"data_as_c_string",
"mediapipe_binary_graph",
)
exports_files([
"simple_subgraph_template.cc",
])
cc_library(
name = "text_to_binary_graph",
srcs = ["text_to_binary_graph.cc"],
visibility = ["//visibility:public"],
deps = [
"//mediapipe/framework:calculator_cc_proto",
"//mediapipe/framework/port:advanced_proto",
"//mediapipe/framework/port:commandlineflags",
"//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status",
],
)
proto_library(
name = "calculator_graph_template_proto",
srcs = ["calculator_graph_template.proto"],
visibility = ["//visibility:public"],
deps = [
"//mediapipe/framework:calculator_options_proto",
"//mediapipe/framework:calculator_proto",
"//mediapipe/framework/deps:proto_descriptor_proto",
],
)
java_proto_library(
name = "calculator_graph_template_java_proto",
visibility = ["//visibility:public"],
deps = [":calculator_graph_template_proto"],
)
java_lite_proto_library(
name = "calculator_graph_template_java_proto_lite",
strict_deps = 0,
visibility = ["//visibility:public"],
deps = [":calculator_graph_template_proto"],
)
proto_library(
name = "source_proto",
srcs = ["source.proto"],
@@ -43,7 +82,10 @@ mediapipe_cc_proto_library(
"//mediapipe/framework:calculator_cc_proto",
"//mediapipe/framework/deps:proto_descriptor_cc_proto",
],
visibility = ["//mediapipe/framework:__subpackages__"],
visibility = [
"//mediapipe/framework:__subpackages__",
"//mediapipe/java/com/google/mediapipe/framework:__subpackages__",
],
deps = [":calculator_graph_template_proto"],
)
@@ -55,6 +97,15 @@ mediapipe_cc_proto_library(
deps = [":source_proto"],
)
cc_binary(
name = "encode_as_c_string",
srcs = ["encode_as_c_string.cc"],
visibility = ["//visibility:public"],
deps = [
"@com_google_absl//absl/strings",
],
)
cc_library(
name = "fill_packet_set",
srcs = ["fill_packet_set.cc"],
@@ -464,8 +515,8 @@ cc_test(
deps = [
":simulation_clock",
":simulation_clock_executor",
"//mediapipe/calculators/core:flow_limiter_calculator",
"//mediapipe/calculators/core:immediate_mux_calculator",
"//mediapipe/calculators/core:real_time_flow_limiter_calculator",
"//mediapipe/calculators/core:round_robin_demux_calculator",
"//mediapipe/framework:calculator_framework",
"//mediapipe/framework:executor",
@@ -483,3 +534,71 @@ cc_test(
"@com_google_absl//absl/strings",
],
)
mediapipe_binary_graph(
name = "test_binarypb",
graph = "//mediapipe/framework/tool/testdata:test_graph",
output_name = "test.binarypb",
visibility = ["//visibility:private"],
)
data_as_c_string(
name = "test_binarypb_inc",
testonly = 1,
srcs = [":test_binarypb"],
outs = ["test_binarypb.inc"],
)
proto_library(
name = "node_chain_subgraph_proto",
srcs = ["node_chain_subgraph.proto"],
deps = [
"//mediapipe/framework:calculator_proto",
],
)
mediapipe_cc_proto_library(
name = "node_chain_subgraph_cc_proto",
srcs = ["node_chain_subgraph.proto"],
cc_deps = ["//mediapipe/framework:calculator_cc_proto"],
visibility = ["//mediapipe:__subpackages__"],
deps = [":node_chain_subgraph_proto"],
)
cc_test(
name = "data_as_c_string_test",
srcs = [
"data_as_c_string_test.cc",
":test_binarypb_inc",
],
deps = [
"//mediapipe/framework:calculator_framework",
"//mediapipe/framework/port:gtest_main",
],
)
cc_test(
name = "subgraph_expansion_test",
size = "small",
srcs = ["subgraph_expansion_test.cc"],
deps = [
":node_chain_subgraph_cc_proto",
":subgraph_expansion",
"//mediapipe/framework:calculator_cc_proto",
"//mediapipe/framework:calculator_framework",
"//mediapipe/framework:mediapipe_options_cc_proto",
"//mediapipe/framework:packet_generator_cc_proto",
"//mediapipe/framework:packet_set",
"//mediapipe/framework:packet_type",
"//mediapipe/framework:status_handler",
"//mediapipe/framework:subgraph",
"//mediapipe/framework/deps:message_matchers",
"//mediapipe/framework/port:gtest_main",
"//mediapipe/framework/port:logging",
"//mediapipe/framework/port:parse_text_proto",
"//mediapipe/framework/port:ret_check",
"//mediapipe/framework/tool/testdata:dub_quad_test_subgraph",
"//mediapipe/framework/tool/testdata:nested_test_subgraph",
"@com_google_absl//absl/strings",
],
)
@@ -5,6 +5,9 @@ package mediapipe;
import "mediapipe/framework/calculator.proto";
import "mediapipe/framework/deps/proto_descriptor.proto";
option java_package = "com.google.mediapipe.proto";
option java_outer_classname = "GraphTemplateProto";
// A template rule or a template rule argument expression.
message TemplateExpression {
// A template parameter name or a literal value.
@@ -0,0 +1,33 @@
// 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.
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/port/gmock.h"
#include "mediapipe/framework/port/gtest.h"
namespace mediapipe {
namespace {
static const char my_graph[] =
#include "mediapipe/framework/tool/test_binarypb.inc"
; // NOLINT(whitespace/semicolon)
TEST(DataAsCString, CanDecodeCalculatorGraphConfig) {
CalculatorGraphConfig config;
bool success = config.ParseFromArray(my_graph, sizeof(my_graph) - 1);
EXPECT_TRUE(success);
}
} // namespace
} // namespace mediapipe
@@ -0,0 +1,62 @@
// 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 program takes one input file and encodes its contents as a C++
// std::string, which can be included in a C++ source file. It is similar to
// filewrapper (and borrows some of its code), but simpler.
#include <fstream>
#include <iostream>
#include <memory>
#include "absl/strings/escaping.h"
int main(int argc, char** argv) {
if (argc != 2) {
std::cerr << "usage: encode_as_c_string input_file\n";
return 1;
}
const std::string input_name = argv[1];
std::ifstream input_file(input_name,
std::ios_base::in | std::ios_base::binary);
if (!input_file.is_open()) {
std::cerr << "cannot open '" << input_name << "'\n";
return 2;
}
constexpr int kBufSize = 4096;
std::unique_ptr<char[]> buf(new char[kBufSize]);
std::cout << "\"";
int line_len = 1;
while (1) {
input_file.read(buf.get(), kBufSize);
int count = input_file.gcount();
if (count == 0) break;
for (int i = 0; i < count; ++i) {
std::string out = absl::CEscape(absl::string_view(&buf[i], 1));
if (line_len + out.size() > 79) {
std::cout << "\"\n\"";
line_len = 1;
}
std::cout << out;
line_len += out.size();
}
}
input_file.close();
if (!input_file.eof()) {
std::cerr << "error reading '" << input_name << "'\n";
return 2;
}
std::cout << "\"\n";
return 0;
}
+111 -50
View File
@@ -16,26 +16,11 @@ Example:
"""
load("//mediapipe/framework:encode_binary_proto.bzl", "encode_binary_proto", "generate_proto_descriptor_set")
load("//mediapipe/framework:transitive_protos.bzl", "transitive_proto_cc_libs", "transitive_proto_descriptor_sets", "transitive_protos")
load("//mediapipe/framework:transitive_protos.bzl", "transitive_protos")
load("//mediapipe/framework/deps:expand_template.bzl", "expand_template")
def mediapipe_binary_graph(name, graph = None, output_name = None, deps = [], testonly = None, **kwargs):
"""Converts a graph from text format to binary format.
Args:
name: the name of the encode_binary_proto rule generated by this macro.
graph: the BUILD label of a text-format MediaPipe graph.
output_name: the name of the file to which the binary serialization is
written.
deps: the BUILD labels of dependencies that provide any additional message
types used by the graph. The basic messages defined in calculator.proto
are always available, but any custom types (e.g. specific calculator
options) should be provided here. It is sufficient to provide targets
that depend on the required protos indirectly: this macro examines the
entire dependency tree, and does not build any dependencies except for
the protos it finds.
testonly: pass 1 if the graph is to be used only for tests.
**kwargs: any other arguments valid for encode_binary_proto.
"""
def mediapipe_binary_graph(name, graph = None, output_name = None, deps = [], testonly = False, **kwargs):
"""Converts a graph from text format to binary format."""
if not graph:
fail("No input graph file specified.")
@@ -44,48 +29,124 @@ def mediapipe_binary_graph(name, graph = None, output_name = None, deps = [], te
fail("Must specify the output_name.")
transitive_protos(
name = name + "_gather_protos",
name = name + "_gather_cc_protos",
deps = deps,
testonly = testonly,
)
# This collects descriptor sets for tools that need them.
transitive_proto_descriptor_sets(
name = name + "_gather_proto_descriptor_sets",
deps = deps,
testonly = testonly,
)
# This collects the generated .a libraries for tools that need them.
transitive_proto_cc_libs(
name = name + "_gather_proto_libs",
deps = deps,
testonly = testonly,
)
# This generates a single descriptor set with a single invocation of the proto compiler.
# May be faster than using the descriptor sets from proto_library.
# We always pass at least the calculator proto since the proto compiler would fail
# if it were passed no protos.
generate_proto_descriptor_set(
name = name + "_proto_descriptor_set",
# Compile a simple proto parser binary using the deps.
native.cc_binary(
name = name + "_text_to_binary_graph",
visibility = ["//visibility:private"],
deps = [
name + "_gather_protos",
"//mediapipe/framework:calculator_proto",
"//mediapipe/framework/tool:text_to_binary_graph",
name + "_gather_cc_protos",
],
tags = ["manual"],
testonly = testonly,
)
return encode_binary_proto(
# Invoke the proto parser binary.
native.genrule(
name = name,
deps = [
name + "_gather_protos",
"//mediapipe/framework:calculator_proto",
"//mediapipe/framework/stream_handler:fixed_size_input_stream_handler_proto",
srcs = [graph],
outs = [output_name],
cmd = (
"$(location " + name + "_text_to_binary_graph" + ") " +
("--proto_source=$(location %s) " % graph) +
("--proto_output=\"$@\" ")
),
tools = [name + "_text_to_binary_graph"],
testonly = testonly,
)
def data_as_c_string(
name,
srcs,
outs = None,
testonly = None):
"""Encodes the data from a file as a C string literal.
This produces a text file containing the quoted C string literal. It can be
included directly in a C++ source file.
Args:
name: The name of the rule.
srcs: A list containing a single item, the file to encode.
outs: A list containing a single item, the name of the output text file.
Defaults to the rule name.
testonly: pass 1 if the graph is to be used only for tests.
"""
if len(srcs) != 1:
fail("srcs must be a single-element list")
if outs == None:
outs = [name]
native.genrule(
name = name,
srcs = srcs,
outs = outs,
cmd = "$(location //mediapipe/framework/tool:encode_as_c_string) \"$<\" > \"$@\"",
tools = ["//mediapipe/framework/tool:encode_as_c_string"],
testonly = testonly,
)
def mediapipe_simple_subgraph(
name,
register_as,
graph,
deps = [],
visibility = None,
testonly = None,
**kwargs):
"""Defines a registered subgraph for inclusion in other graphs.
Args:
name: name of the subgraph target to define.
register_as: name used to invoke this graph in supergraphs. Should be in
CamelCase.
graph: the BUILD label of a text-format MediaPipe graph.
deps: any calculators or subgraphs used by this graph.
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.
"""
graph_base_name = graph.replace(":", "/").split("/")[-1].rsplit(".", 1)[0]
mediapipe_binary_graph(
name = name + "_graph",
graph = graph,
output_name = graph_base_name + ".binarypb",
deps = deps,
testonly = testonly,
)
data_as_c_string(
name = name + "_inc",
srcs = [graph_base_name + ".binarypb"],
outs = [graph_base_name + ".inc"],
)
# cc_library for a linked mediapipe graph.
expand_template(
name = name + "_linked_cc",
template = "//mediapipe/framework/tool:simple_subgraph_template.cc",
out = name + "_linked.cc",
substitutions = {
"{{SUBGRAPH_CLASS_NAME}}": register_as,
"{{SUBGRAPH_INC_FILE_PATH}}": native.package_name() + "/" + graph_base_name + ".inc",
},
testonly = testonly,
)
native.cc_library(
name = name,
srcs = [
name + "_linked.cc",
graph_base_name + ".inc",
],
message_type = "mediapipe.CalculatorGraphConfig",
input = graph,
output = output_name,
deps = [
"//mediapipe/framework:calculator_framework",
"//mediapipe/framework:subgraph",
] + deps,
alwayslink = 1,
visibility = visibility,
testonly = testonly,
**kwargs
)
@@ -0,0 +1,19 @@
syntax = "proto2";
package mediapipe;
import "mediapipe/framework/calculator.proto";
// Options for NodeChainSubgraph.
message NodeChainSubgraphOptions {
extend CalculatorOptions {
optional NodeChainSubgraphOptions ext = 167210579;
}
// The type of the node. The node must have exactly one input stream and
// exactly one output stream.
optional string node_type = 1;
// How many copies of the node should be chained in series.
optional int32 chain_length = 2;
}
@@ -0,0 +1,43 @@
// 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/calculator_framework.h"
#include "mediapipe/framework/subgraph.h"
namespace mediapipe {
static const char binary_graph[] =
#include "{{SUBGRAPH_INC_FILE_PATH}}"
; // NOLINT(whitespace/semicolon)
class {{SUBGRAPH_CLASS_NAME}} : public Subgraph {
public:
::mediapipe::StatusOr<CalculatorGraphConfig> GetConfig(
const SubgraphOptions& /*options*/) {
CalculatorGraphConfig config;
// Note: this is a binary protobuf serialization, and may include NUL
// bytes. The trailing NUL added to the std::string literal should be excluded.
if (config.ParseFromArray(binary_graph, sizeof(binary_graph) - 1)) {
return config;
} else {
return ::mediapipe::InternalError("Could not parse subgraph.");
}
}
};
REGISTER_MEDIAPIPE_GRAPH({{SUBGRAPH_CLASS_NAME}});
} // namespace mediapipe
@@ -46,7 +46,7 @@ class SimulationClockTest : public ::testing::Test {
graph_config_ = ParseTextProtoOrDie<CalculatorGraphConfig>(R"(
input_stream: "input_packets_0"
node {
calculator: 'RealTimeFlowLimiterCalculator'
calculator: 'FlowLimiterCalculator'
input_stream_handler {
input_stream_handler: 'ImmediateInputStreamHandler'
}
@@ -0,0 +1,529 @@
// 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.
#include "mediapipe/framework/tool/subgraph_expansion.h"
#include <memory>
#include "absl/strings/str_cat.h"
#include "mediapipe/framework/calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/deps/message_matchers.h"
#include "mediapipe/framework/packet_set.h"
#include "mediapipe/framework/packet_type.h"
#include "mediapipe/framework/port/gmock.h"
#include "mediapipe/framework/port/gtest.h"
#include "mediapipe/framework/port/logging.h"
#include "mediapipe/framework/port/parse_text_proto.h"
#include "mediapipe/framework/port/proto_ns.h"
#include "mediapipe/framework/port/ret_check.h"
#include "mediapipe/framework/port/status_matchers.h"
#include "mediapipe/framework/status_handler.h"
#include "mediapipe/framework/subgraph.h"
#include "mediapipe/framework/tool/node_chain_subgraph.pb.h"
namespace mediapipe {
namespace {
class SimpleTestCalculator : public CalculatorBase {
public:
::mediapipe::Status Process(CalculatorContext* cc) override {
return ::mediapipe::OkStatus();
}
static ::mediapipe::Status GetContract(CalculatorContract* cc) {
for (PacketType& type : cc->Inputs()) {
type.Set<int>();
}
for (PacketType& type : cc->Outputs()) {
type.Set<int>();
}
for (PacketType& type : cc->InputSidePackets()) {
type.Set<int>();
}
return ::mediapipe::OkStatus();
}
};
REGISTER_CALCULATOR(SimpleTestCalculator);
typedef SimpleTestCalculator SomeSourceCalculator;
typedef SimpleTestCalculator SomeSinkCalculator;
typedef SimpleTestCalculator SomeRegularCalculator;
typedef SimpleTestCalculator SomeAggregator;
REGISTER_CALCULATOR(SomeSourceCalculator);
REGISTER_CALCULATOR(SomeSinkCalculator);
REGISTER_CALCULATOR(SomeRegularCalculator);
REGISTER_CALCULATOR(SomeAggregator);
class TestSubgraph : public Subgraph {
public:
::mediapipe::StatusOr<CalculatorGraphConfig> GetConfig(
const SubgraphOptions& /*options*/) override {
CalculatorGraphConfig config =
::mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"(
input_stream: "DATA:input_1"
node {
name: "regular_node"
calculator: "SomeRegularCalculator"
input_stream: "input_1"
output_stream: "stream_a"
input_side_packet: "side"
}
node {
name: "simple_sink"
calculator: "SomeSinkCalculator"
input_stream: "stream_a"
}
packet_generator {
packet_generator: "SomePacketGenerator"
output_side_packet: "side"
}
)");
return config;
}
};
REGISTER_MEDIAPIPE_GRAPH(TestSubgraph);
class PacketFactoryTestSubgraph : public Subgraph {
public:
::mediapipe::StatusOr<CalculatorGraphConfig> GetConfig(
const SubgraphOptions& /*options*/) override {
CalculatorGraphConfig config =
::mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"(
input_stream: "DATA:input_1"
node {
name: "regular_node"
calculator: "SomeRegularCalculator"
input_stream: "input_1"
output_stream: "stream_a"
input_side_packet: "side"
}
node {
name: "simple_sink"
calculator: "SomeSinkCalculator"
input_stream: "stream_a"
}
packet_factory {
packet_factory: "SomePacketFactory"
output_side_packet: "side"
}
)");
return config;
}
};
REGISTER_MEDIAPIPE_GRAPH(PacketFactoryTestSubgraph);
// This subgraph chains copies of the specified node in series. The node type
// and the number of copies of the node are specified in subgraph options.
class NodeChainSubgraph : public Subgraph {
public:
::mediapipe::StatusOr<CalculatorGraphConfig> GetConfig(
const SubgraphOptions& options) override {
const mediapipe::NodeChainSubgraphOptions& opts =
options.GetExtension(mediapipe::NodeChainSubgraphOptions::ext);
const ProtoString& node_type = opts.node_type();
int chain_length = opts.chain_length();
RET_CHECK(!node_type.empty());
RET_CHECK_GT(chain_length, 0);
CalculatorGraphConfig config;
config.add_input_stream("INPUT:stream_0");
config.add_output_stream(absl::StrCat("OUTPUT:stream_", chain_length));
for (int i = 0; i < chain_length; ++i) {
CalculatorGraphConfig::Node* node = config.add_node();
node->set_calculator(node_type);
node->add_input_stream(absl::StrCat("stream_", i));
node->add_output_stream(absl::StrCat("stream_", i + 1));
}
return config;
}
};
REGISTER_MEDIAPIPE_GRAPH(NodeChainSubgraph);
// A subgraph used in the ExecutorFieldOfNodeInSubgraphPreserved test. The
// subgraph contains a node with the executor field "custom_thread_pool".
class NodeWithExecutorSubgraph : public Subgraph {
public:
::mediapipe::StatusOr<CalculatorGraphConfig> GetConfig(
const SubgraphOptions& options) override {
CalculatorGraphConfig config =
::mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"(
input_stream: "INPUT:foo"
output_stream: "OUTPUT:bar"
node {
calculator: "PassThroughCalculator"
input_stream: "foo"
output_stream: "bar"
executor: "custom_thread_pool"
}
)");
return config;
}
};
REGISTER_MEDIAPIPE_GRAPH(NodeWithExecutorSubgraph);
// A subgraph used in the ExecutorFieldOfNodeInSubgraphPreserved test. The
// subgraph contains a NodeWithExecutorSubgraph.
class EnclosingSubgraph : public Subgraph {
public:
::mediapipe::StatusOr<CalculatorGraphConfig> GetConfig(
const SubgraphOptions& options) override {
CalculatorGraphConfig config =
::mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"(
input_stream: "IN:in"
output_stream: "OUT:out"
node {
calculator: "NodeWithExecutorSubgraph"
input_stream: "INPUT:in"
output_stream: "OUTPUT:out"
}
)");
return config;
}
};
REGISTER_MEDIAPIPE_GRAPH(EnclosingSubgraph);
TEST(SubgraphExpansionTest, TransformStreamNames) {
CalculatorGraphConfig config =
::mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"(
node {
calculator: "SomeSinkCalculator"
input_stream: "input_1"
input_stream: "VIDEO:input_2"
input_stream: "AUDIO:0:input_3"
input_stream: "AUDIO:1:input_4"
}
)");
CalculatorGraphConfig expected_config =
::mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"(
node {
calculator: "SomeSinkCalculator"
input_stream: "input_1_foo"
input_stream: "VIDEO:input_2_foo"
input_stream: "AUDIO:0:input_3_foo"
input_stream: "AUDIO:1:input_4_foo"
}
)");
auto add_foo = [](absl::string_view s) { return absl::StrCat(s, "_foo"); };
MEDIAPIPE_EXPECT_OK(tool::TransformStreamNames(
(*config.mutable_node())[0].mutable_input_stream(), add_foo));
EXPECT_THAT(config, mediapipe::EqualsProto(expected_config));
}
TEST(SubgraphExpansionTest, TransformNames) {
CalculatorGraphConfig config =
::mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"(
input_stream: "input_1"
node {
calculator: "SomeRegularCalculator"
name: "bob"
input_stream: "input_1"
input_stream: "VIDEO:input_2"
input_stream: "AUDIO:0:input_3"
input_stream: "AUDIO:1:input_4"
output_stream: "output_1"
}
node {
calculator: "SomeRegularCalculator"
input_stream: "output_1"
output_stream: "output_2"
}
)");
CalculatorGraphConfig expected_config =
::mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"(
input_stream: "__sg0_input_1"
node {
calculator: "SomeRegularCalculator"
name: "__sg0_bob"
input_stream: "__sg0_input_1"
input_stream: "VIDEO:__sg0_input_2"
input_stream: "AUDIO:0:__sg0_input_3"
input_stream: "AUDIO:1:__sg0_input_4"
output_stream: "__sg0_output_1"
}
node {
calculator: "SomeRegularCalculator"
input_stream: "__sg0_output_1"
output_stream: "__sg0_output_2"
}
)");
auto add_prefix = [](absl::string_view s) {
return absl::StrCat("__sg0_", s);
};
MEDIAPIPE_EXPECT_OK(tool::TransformNames(&config, add_prefix));
EXPECT_THAT(config, mediapipe::EqualsProto(expected_config));
}
TEST(SubgraphExpansionTest, FindCorrespondingStreams) {
CalculatorGraphConfig config1 =
::mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"(
input_stream: "input_1"
input_stream: "VIDEO:input_2"
input_stream: "AUDIO:0:input_3"
input_stream: "AUDIO:1:input_4"
)");
CalculatorGraphConfig config2 =
::mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"(
node {
calculator: "SomeSubgraph"
input_stream: "foo"
input_stream: "VIDEO:bar"
input_stream: "AUDIO:0:baz"
input_stream: "AUDIO:1:qux"
}
)");
std::map<std::string, std::string> stream_map;
MEDIAPIPE_EXPECT_OK(tool::FindCorrespondingStreams(
&stream_map, config1.input_stream(), config2.node()[0].input_stream()));
EXPECT_THAT(stream_map,
testing::UnorderedElementsAre(testing::Pair("input_1", "foo"),
testing::Pair("input_2", "bar"),
testing::Pair("input_3", "baz"),
testing::Pair("input_4", "qux")));
}
TEST(SubgraphExpansionTest, FindCorrespondingStreamsNonexistentTag) {
// The VIDEO tag does not exist in the subgraph.
CalculatorGraphConfig config1 =
::mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"(
input_stream: "input_1"
input_stream: "AUDIO:0:input_3"
input_stream: "AUDIO:1:input_4"
)");
CalculatorGraphConfig config2 =
::mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"(
node {
calculator: "SomeSubgraph"
input_stream: "foo"
input_stream: "VIDEO:bar"
input_stream: "AUDIO:0:baz"
input_stream: "AUDIO:1:qux"
}
)");
std::map<std::string, std::string> stream_map;
auto status = tool::FindCorrespondingStreams(
&stream_map, config1.input_stream(), config2.node()[0].input_stream());
EXPECT_THAT(status.message(),
testing::AllOf(
// Problematic tag.
testing::HasSubstr("VIDEO"),
// Error.
testing::HasSubstr("does not exist")));
}
TEST(SubgraphExpansionTest, FindCorrespondingStreamsTooFewIndexes) {
// The AUDIO tag has too few indexes in the subgraph (1 vs. 2).
CalculatorGraphConfig config1 =
::mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"(
input_stream: "input_1"
input_stream: "VIDEO:input_2"
input_stream: "AUDIO:0:input_3"
)");
CalculatorGraphConfig config2 =
::mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"(
node {
calculator: "SomeSubgraph"
input_stream: "foo"
input_stream: "VIDEO:bar"
input_stream: "AUDIO:0:baz"
input_stream: "AUDIO:1:qux"
}
)");
std::map<std::string, std::string> stream_map;
auto status = tool::FindCorrespondingStreams(
&stream_map, config1.input_stream(), config2.node()[0].input_stream());
EXPECT_THAT(status.message(),
testing::AllOf(
// Problematic tag.
testing::HasSubstr("AUDIO"),
// Error.
testing::HasSubstr(" 2 "), testing::HasSubstr(" 1 ")));
}
TEST(SubgraphExpansionTest, ConnectSubgraphStreams) {
CalculatorGraphConfig subgraph =
::mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"(
input_stream: "A:input_1"
input_stream: "B:input_2"
output_stream: "O:output_2"
input_side_packet: "SI:side_input"
output_side_packet: "SO:side_output"
node {
calculator: "SomeRegularCalculator"
input_stream: "input_1"
input_stream: "VIDEO:input_2"
input_side_packet: "side_input"
output_stream: "output_1"
}
node {
calculator: "SomeRegularCalculator"
input_stream: "input_1"
input_stream: "output_1"
output_stream: "output_2"
}
packet_generator {
packet_generator: "SomeGenerator"
input_side_packet: "side_input"
output_side_packet: "side_output"
}
)");
CalculatorGraphConfig supergraph =
::mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"(
node {
calculator: "SomeSubgraph"
input_stream: "A:foo"
input_stream: "B:bar"
output_stream: "O:foobar"
input_side_packet: "SI:flip"
output_side_packet: "SO:flop"
}
)");
// Note: graph input streams, output streams, and side packets on the
// subgraph are not changed because they are going to be discarded anyway.
CalculatorGraphConfig expected_subgraph =
::mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"(
input_stream: "A:input_1"
input_stream: "B:input_2"
output_stream: "O:output_2"
input_side_packet: "SI:side_input"
output_side_packet: "SO:side_output"
node {
calculator: "SomeRegularCalculator"
input_stream: "foo"
input_stream: "VIDEO:bar"
input_side_packet: "flip"
output_stream: "output_1"
}
node {
calculator: "SomeRegularCalculator"
input_stream: "foo"
input_stream: "output_1"
output_stream: "foobar"
}
packet_generator {
packet_generator: "SomeGenerator"
input_side_packet: "flip"
output_side_packet: "flop"
}
)");
MEDIAPIPE_EXPECT_OK(
tool::ConnectSubgraphStreams(supergraph.node()[0], &subgraph));
EXPECT_THAT(subgraph, mediapipe::EqualsProto(expected_subgraph));
}
TEST(SubgraphExpansionTest, ExpandSubgraphs) {
CalculatorGraphConfig supergraph =
::mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"(
node {
name: "simple_source"
calculator: "SomeSourceCalculator"
output_stream: "foo"
}
node { calculator: "TestSubgraph" input_stream: "DATA:foo" }
)");
CalculatorGraphConfig expected_graph =
::mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"(
node {
name: "simple_source"
calculator: "SomeSourceCalculator"
output_stream: "foo"
}
node {
name: "__sg0_regular_node"
calculator: "SomeRegularCalculator"
input_stream: "foo"
output_stream: "__sg0_stream_a"
input_side_packet: "__sg0_side"
}
node {
name: "__sg0_simple_sink"
calculator: "SomeSinkCalculator"
input_stream: "__sg0_stream_a"
}
packet_generator {
packet_generator: "SomePacketGenerator"
output_side_packet: "__sg0_side"
}
)");
MEDIAPIPE_EXPECT_OK(tool::ExpandSubgraphs(&supergraph));
EXPECT_THAT(supergraph, mediapipe::EqualsProto(expected_graph));
}
TEST(SubgraphExpansionTest, ValidateSubgraphFields) {
CalculatorGraphConfig supergraph =
::mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"(
node {
name: "simple_source"
calculator: "SomeSourceCalculator"
output_stream: "foo"
}
node {
name: "foo_subgraph"
calculator: "TestSubgraph"
input_stream: "DATA:foo"
buffer_size_hint: -1 # This field is only applicable to calculators.
}
)");
::mediapipe::Status s1 = tool::ValidateSubgraphFields(supergraph.node(1));
EXPECT_EQ(s1.code(), ::mediapipe::StatusCode::kInvalidArgument);
EXPECT_THAT(s1.message(), testing::HasSubstr("foo_subgraph"));
::mediapipe::Status s2 = tool::ExpandSubgraphs(&supergraph);
EXPECT_EQ(s2.code(), ::mediapipe::StatusCode::kInvalidArgument);
EXPECT_THAT(s2.message(), testing::HasSubstr("foo_subgraph"));
}
// A test that captures the use case of CL 191001940. The "executor" field of
// a node inside a subgraph should be preserved, not mapped or mangled. This
// test will help us detect breakage of this use case when we implement
// subgraph executor support in the future.
TEST(SubgraphExpansionTest, ExecutorFieldOfNodeInSubgraphPreserved) {
CalculatorGraphConfig supergraph =
::mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"(
input_stream: "input"
executor {
name: "custom_thread_pool"
type: "ThreadPoolExecutor"
options {
[mediapipe.ThreadPoolExecutorOptions.ext] { num_threads: 4 }
}
}
node {
calculator: "EnclosingSubgraph"
input_stream: "IN:input"
output_stream: "OUT:output"
}
)");
CalculatorGraphConfig expected_graph =
::mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"(
input_stream: "input"
executor {
name: "custom_thread_pool"
type: "ThreadPoolExecutor"
options {
[mediapipe.ThreadPoolExecutorOptions.ext] { num_threads: 4 }
}
}
node {
calculator: "PassThroughCalculator"
input_stream: "input"
output_stream: "output"
executor: "custom_thread_pool"
}
)");
MEDIAPIPE_EXPECT_OK(tool::ExpandSubgraphs(&supergraph));
EXPECT_THAT(supergraph, mediapipe::EqualsProto(expected_graph));
}
} // namespace
} // namespace mediapipe
+57
View File
@@ -0,0 +1,57 @@
# 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.
#
licenses(["notice"]) # Apache 2.0
package(default_visibility = ["//mediapipe:__subpackages__"])
load(
"//mediapipe/framework/tool:mediapipe_graph.bzl",
"mediapipe_simple_subgraph",
)
filegroup(
name = "test_graph",
srcs = ["test.pbtxt"],
)
exports_files([
"test.pbtxt",
"dub_quad_test_subgraph.pbtxt",
"nested_test_subgraph.pbtxt",
])
mediapipe_simple_subgraph(
name = "dub_quad_test_subgraph",
testonly = 1,
graph = "dub_quad_test_subgraph.pbtxt",
register_as = "DubQuadTestSubgraph",
visibility = ["//visibility:public"],
deps = [
"//mediapipe/framework:test_calculators",
],
)
mediapipe_simple_subgraph(
name = "nested_test_subgraph",
testonly = 1,
graph = "nested_test_subgraph.pbtxt",
register_as = "NestedTestSubgraph",
visibility = ["//visibility:public"],
deps = [
":dub_quad_test_subgraph",
"//mediapipe/framework:test_calculators",
],
)
@@ -0,0 +1,13 @@
input_stream: "INTS:ints"
output_stream: "DUBS:doubled"
output_stream: "QUADS:quadrupled"
node {
calculator: "DoubleIntCalculator"
input_stream: "ints"
output_stream: "doubled"
}
node {
calculator: "DoubleIntCalculator"
input_stream: "doubled"
output_stream: "quadrupled"
}
@@ -0,0 +1,20 @@
input_stream: "INTS:ints"
output_stream: "DUBS:doubled"
output_stream: "QUADS:quadrupled"
output_stream: "OCTS:octupled"
node {
calculator: "DubQuadTestSubgraph"
input_stream: "INTS:ints"
output_stream: "DUBS:doubled"
output_stream: "QUADS:quadrupled"
}
node {
calculator: "DoubleIntCalculator"
input_stream: "quadrupled"
output_stream: "octupled"
# The following is to ensure we handle NULs correctly.
input_stream_info {
tag_index: ":0" # 'quadrupled'
back_edge: false # The false boolean value is encoded as a zero byte.
}
}
+5
View File
@@ -0,0 +1,5 @@
node {
calculator: "PassThroughCalculator"
input_stream: "in"
output_stream: "out"
}
@@ -0,0 +1,111 @@
// 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.
//
// A command line utility to parse a text proto and output a binary proto.
#include <stdlib.h>
#include <fstream>
#include <string>
#include "mediapipe/framework/calculator.pb.h"
#include "mediapipe/framework/port/advanced_proto_inc.h"
#include "mediapipe/framework/port/canonical_errors.h"
#include "mediapipe/framework/port/commandlineflags.h"
#include "mediapipe/framework/port/ret_check.h"
#include "mediapipe/framework/port/status.h"
DEFINE_string(proto_source, "",
"The template source file containing CalculatorGraphConfig "
"protobuf text with inline template params.");
DEFINE_string(
proto_output, "",
"An output template file in binary CalculatorGraphTemplate form.");
#define EXIT_IF_ERROR(status) \
if (!status.ok()) { \
LOG(ERROR) << status; \
return EXIT_FAILURE; \
}
namespace mediapipe {
mediapipe::Status ReadProto(proto_ns::io::ZeroCopyInputStream* in,
bool read_text, const std::string& source,
proto_ns::Message* result) {
if (read_text) {
RET_CHECK(proto_ns::TextFormat::Parse(in, result))
<< "could not parse text proto: " << source;
} else {
RET_CHECK(result->ParseFromZeroCopyStream(in))
<< "could not parse binary proto: " << source;
}
return mediapipe::OkStatus();
}
mediapipe::Status WriteProto(const proto_ns::Message& message, bool write_text,
const std::string& dest,
proto_ns::io::ZeroCopyOutputStream* out) {
if (write_text) {
RET_CHECK(proto_ns::TextFormat::Print(message, out))
<< "could not write text proto to: " << dest;
} else {
RET_CHECK(message.SerializeToZeroCopyStream(out))
<< "could not write binary proto to: " << dest;
}
return mediapipe::OkStatus();
}
// Read a proto from a text or a binary file.
mediapipe::Status ReadFile(const std::string& proto_source, bool read_text,
proto_ns::Message* result) {
std::ifstream ifs(proto_source);
proto_ns::io::IstreamInputStream in(&ifs);
RETURN_IF_ERROR(ReadProto(&in, read_text, proto_source, result));
return mediapipe::OkStatus();
}
// Write a proto to a text or a binary file.
mediapipe::Status WriteFile(const std::string& proto_output, bool write_text,
const proto_ns::Message& message) {
std::ofstream ofs(proto_output, std::ofstream::out | std::ofstream::trunc);
proto_ns::io::OstreamOutputStream out(&ofs);
RETURN_IF_ERROR(WriteProto(message, write_text, proto_output, &out));
return mediapipe::OkStatus();
}
} // namespace mediapipe
int main(int argc, char** argv) {
google::InitGoogleLogging(argv[0]);
gflags::ParseCommandLineFlags(&argc, &argv, true);
// Validate command line options.
mediapipe::Status status;
if (FLAGS_proto_source.empty()) {
status.Update(
::mediapipe::InvalidArgumentError("--proto_source must be specified"));
}
if (FLAGS_proto_output.empty()) {
status.Update(
::mediapipe::InvalidArgumentError("--proto_output must be specified"));
}
if (!status.ok()) {
return EXIT_FAILURE;
}
mediapipe::CalculatorGraphConfig config;
EXIT_IF_ERROR(mediapipe::ReadFile(FLAGS_proto_source, true, &config));
EXIT_IF_ERROR(mediapipe::WriteFile(FLAGS_proto_output, false, config));
return EXIT_SUCCESS;
}
+38 -171
View File
@@ -1,117 +1,37 @@
"""This rule gathers all .proto files used by all of its dependencies.
"""Extract a cc_library compatible dependency with only the top level proto rules."""
The entire dependency tree is searched. The search crosses through cc_library
rules and portable_proto_library rules to collect the transitive set of all
.proto dependencies. This is provided to other rules in the form of a "proto"
provider, using the transitive_sources field.
ProtoLibsInfo = provider(fields = ["targets", "out"])
This rule uses aspects. For general information on the concept, see:
- go/bazel-aspects-ides-tools
- go/bazel-aspects
def _get_proto_rules(deps, proto_rules = None):
useful_deps = [dep for dep in deps if hasattr(dep, "proto_rules")]
if proto_rules == None:
proto_rules = []
for dep in useful_deps:
proto_rules = proto_rules + dep.proto_rules
return proto_rules
The basic rule is transitive_protos. Example:
def _proto_rules_aspect_impl(target, ctx):
# Make sure the rule has a srcs attribute.
proto_rules = []
found_cc_proto = False
if hasattr(ctx.rule.attr, "srcs") and len(ctx.rule.attr.srcs) == 1:
for f in ctx.rule.attr.srcs[0].files.to_list():
if f.basename.endswith(".pb.cc"):
proto_rules = [target[CcInfo]]
found = True
break
proto_library(
name = "a_proto_library",
srcs = ["a.proto],
)
proto_library(
name = "b_proto_library",
srcs = ["b.proto],
)
cc_library(
name = "a_cc_library",
deps = ["b_proto_library],
)
transitive_protos(
name = "all_my_protos",
deps = [
"a_proto_library",
"a_cc_library",
],
)
all_my_protos will gather all proto files used in its dependency tree; in this
case, ["a.proto", "b.proto"]. These are provided as the default outputs of this
rule, so you can place the rule in any context that requires a list of files,
and also as a "proto" provider, for use by any rules that would normally depend
on proto_library.
The dependency tree is explored using an aspect, transitive_protos_aspect. This
aspect propagates across two attributes, "deps" and "hdrs". The latter is used
for compatibility with portable_proto_library; see comments below and in that
file for more details.
At each visited node in the tree, the aspect collects protos:
- direct_sources from the proto provider in the current node. This is filled in
by proto_library nodes, and also by piggyback_header nodes (see
portable_proto_build_defs.bzl).
- protos from the transitive_protos provider in dependency nodes, found from
both the "deps" and the "hdrs" aspect.
Then it puts all the protos in the protos field of the transitive_protos
provider which it generates. This is how each node sends its gathered protos up
the tree.
"""
def _gather_transitive_protos_deps(deps, my_protos = [], my_descriptors = [], my_proto_libs = []):
useful_deps = [dep for dep in deps if hasattr(dep, "transitive_protos")]
protos = depset(
my_protos,
transitive = [dep.transitive_protos.protos for dep in useful_deps],
)
proto_libs = depset(
my_proto_libs,
transitive = [dep.transitive_protos.proto_libs for dep in useful_deps],
)
descriptors = depset(
my_descriptors,
transitive = [dep.transitive_protos.descriptors for dep in useful_deps],
)
if not found_cc_proto:
deps = ctx.rule.attr.deps[:] if hasattr(ctx.rule.attr, "deps") else []
proto_rules = _get_proto_rules(deps, proto_rules)
return struct(
transitive_protos = struct(
protos = protos,
descriptors = descriptors,
proto_libs = proto_libs,
),
proto_rules = proto_rules,
)
def _transitive_protos_aspect_impl(target, ctx):
"""Implementation of the transitive_protos_aspect aspect.
Args:
target: The current target.
ctx: The current rule context.
Returns:
A transitive_protos provider.
"""
protos = target.proto.direct_sources if hasattr(target, "proto") else []
deps = ctx.rule.attr.deps[:] if hasattr(ctx.rule.attr, "deps") else []
descriptors = [target.proto.direct_descriptor_set] if hasattr(target, "proto") and hasattr(target.proto, "direct_descriptor_set") else []
proto_libs = []
if ctx.rule.kind == "proto_library":
proto_libs = [f for f in target.files.to_list() if f.extension == "a"]
# Searching through the hdrs attribute is necessary because of
# portable_proto_library. In portable mode, that macro
# generates a cc_library that does not depend on any proto_libraries, so
# the .proto files do not appear in its dependency tree.
# portable_proto_library cannot add arbitrary providers or attributes to
# a cc_library rule, so instead it piggybacks the provider on a rule that
# generates a header, which occurs in the hdrs attribute of the cc_library.
if hasattr(ctx.rule.attr, "hdrs"):
deps += ctx.rule.attr.hdrs
result = _gather_transitive_protos_deps(deps, protos, descriptors, proto_libs)
return result
transitive_protos_aspect = aspect(
implementation = _transitive_protos_aspect_impl,
attr_aspects = ["deps", "hdrs"],
attrs = {},
proto_rules_aspect = aspect(
implementation = _proto_rules_aspect_impl,
attr_aspects = ["deps"],
)
def _transitive_protos_impl(ctx):
@@ -123,72 +43,19 @@ def _transitive_protos_impl(ctx):
A proto provider (with transitive_sources and transitive_descriptor_sets filled in),
and marks all transitive sources as default output.
"""
gathered = _gather_transitive_protos_deps(ctx.attr.deps)
protos = gathered.transitive_protos.protos
descriptors = gathered.transitive_protos.descriptors
return struct(
proto = struct(
transitive_sources = protos,
transitive_descriptor_sets = descriptors,
),
files = depset(protos),
)
cc_infos = []
for dep in ctx.attr.deps:
for dep_proto_rule in dep.proto_rules:
cc_infos.append(dep_proto_rule)
return [cc_common.merge_cc_infos(cc_infos = cc_infos)]
transitive_protos = rule(
implementation = _transitive_protos_impl,
attrs = {
"deps": attr.label_list(
aspects = [transitive_protos_aspect],
),
},
)
def _transitive_proto_cc_libs_impl(ctx):
"""Implementation of transitive_proto_cc_libs rule.
NOTE: this only works on Bazel, not exobazel.
Args:
ctx: The rule context.
Returns:
All transitive proto C++ .a files as default output.
"""
gathered = _gather_transitive_protos_deps(ctx.attr.deps)
proto_libs = gathered.transitive_protos.proto_libs
return struct(
files = proto_libs,
)
transitive_proto_cc_libs = rule(
implementation = _transitive_proto_cc_libs_impl,
attrs = {
"deps": attr.label_list(
aspects = [transitive_protos_aspect],
),
},
)
def _transitive_proto_descriptor_sets_impl(ctx):
"""Implementation of transitive_proto_descriptor_sets rule.
Args:
ctx: The rule context.
Returns:
All transitive proto descriptor files as default output.
"""
gathered = _gather_transitive_protos_deps(ctx.attr.deps)
descriptors = gathered.transitive_protos.descriptors
return struct(
files = descriptors,
)
transitive_proto_descriptor_sets = rule(
implementation = _transitive_proto_descriptor_sets_impl,
attrs = {
"deps": attr.label_list(
aspects = [transitive_protos_aspect],
),
},
attrs =
{
"deps": attr.label_list(
aspects = [proto_rules_aspect],
),
},
provides = [CcInfo],
)
@@ -218,6 +218,8 @@ std::string NodeTypeInfo::NodeTypeToString(NodeType node_type) {
node_.type = NodeType::CALCULATOR;
node_.index = node_index;
RETURN_IF_ERROR(contract_.Initialize(node));
contract_.SetNodeName(
CanonicalNodeName(validated_graph.Config(), node_index));
// Ensure input_stream_info field is well formed.
if (!node.input_stream_info().empty()) {