Project import generated by Copybara.
PiperOrigin-RevId: 263889205
This commit is contained in:
@@ -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",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -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_;
|
||||
};
|
||||
|
||||
|
||||
@@ -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),
|
||||
},
|
||||
)
|
||||
@@ -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"},
|
||||
|
||||
@@ -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"],
|
||||
)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"});
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
Vendored
+1
-1
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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.
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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()) {
|
||||
|
||||
Reference in New Issue
Block a user