Project import generated by Copybara.

GitOrigin-RevId: 73d686c40057684f8bfaca285368bf1813f9fc26
This commit is contained in:
MediaPipe Team
2022-03-21 12:12:39 -07:00
committed by jqtang
parent e6c19885c6
commit cc6a2f7af6
266 changed files with 3658 additions and 1681 deletions
+13 -1
View File
@@ -150,6 +150,13 @@ mediapipe_proto_library(
deps = ["//mediapipe/framework:mediapipe_options_proto"],
)
config_setting(
name = "android_no_jni",
define_values = {"MEDIAPIPE_NO_JNI": "1"},
values = {"crosstool_top": "//external:android/crosstool"},
visibility = ["//visibility:public"],
)
cc_library(
name = "calculator_base",
srcs = ["calculator_base.cc"],
@@ -712,6 +719,7 @@ cc_library(
visibility = ["//visibility:public"],
deps = [
"@com_google_absl//absl/memory",
"@com_google_absl//absl/synchronization",
],
)
@@ -916,15 +924,19 @@ cc_library(
":packet",
":packet_set",
":type_map",
"//mediapipe/framework/deps:no_destructor",
"//mediapipe/framework/port:logging",
"//mediapipe/framework/port:map_util",
"//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:source_location",
"//mediapipe/framework/port:status",
"//mediapipe/framework/tool:status_util",
"//mediapipe/framework/tool:type_util",
"//mediapipe/framework/tool:validate_name",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/types:span",
"@com_google_absl//absl/types:variant",
],
)
+1
View File
@@ -134,6 +134,7 @@ cc_test(
deps = [
":packet",
"//mediapipe/framework/port:gtest_main",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/strings",
],
)
+26 -3
View File
@@ -313,8 +313,8 @@ template <class Calc>
class Node : public NodeBase {
public:
Node() : NodeBase(Calc::kCalculatorName) {}
// Overrides the built-in calculator type std::string with the provided
// argument. Can be used to create nodes from pure interfaces.
// Overrides the built-in calculator type string with the provided argument.
// Can be used to create nodes from pure interfaces.
// TODO: only use this for pure interfaces
Node(const std::string& type_override) : NodeBase(type_override) {}
@@ -377,6 +377,29 @@ class PacketGenerator {
return *options_.MutableExtension(T::ext);
}
template <typename B, typename T, bool kIsOptional, bool kIsMultiple>
auto operator[](const PortCommon<B, T, kIsOptional, kIsMultiple>& port) {
using PayloadT =
typename PortCommon<B, T, kIsOptional, kIsMultiple>::PayloadT;
if constexpr (std::is_same_v<B, SideOutputBase>) {
auto* base = &out_sides_[port.Tag()];
if constexpr (kIsMultiple) {
return MultiSideSource<PayloadT>(base);
} else {
return SideSource<PayloadT>(base);
}
} else if constexpr (std::is_same_v<B, SideInputBase>) {
auto* base = &in_sides_[port.Tag()];
if constexpr (kIsMultiple) {
return MultiSideDestination<PayloadT>(base);
} else {
return SideDestination<PayloadT>(base);
}
} else {
static_assert(dependent_false<B>::value, "Type not supported.");
}
}
private:
std::string type_;
TagIndexMap<DestinationBase> in_sides_;
@@ -402,7 +425,7 @@ class Graph {
}
// Creates a node of a specific type. Should be used for pure interfaces,
// which do not have a built-in type std::string.
// which do not have a built-in type string.
template <class Calc>
Node<Calc>& AddNode(const std::string& type) {
auto node = std::make_unique<Node<Calc>>(type);
+2 -2
View File
@@ -6,8 +6,8 @@
namespace mediapipe {
namespace api2 {
// This class stores a constant std::string that can be inspected at compile
// time in constexpr code.
// This class stores a constant string that can be inspected at compile time
// in constexpr code.
class const_str {
public:
constexpr const_str(std::size_t size, const char* data)
+1
View File
@@ -215,6 +215,7 @@ class Packet : public Packet<internal::Generic> {
return typed_payload->data();
}
const T& operator*() const { return Get(); }
const T* operator->() const { return &Get(); }
template <typename U>
T GetOr(U&& v) const {
+22
View File
@@ -1,5 +1,6 @@
#include "mediapipe/framework/api2/packet.h"
#include "absl/memory/memory.h"
#include "absl/strings/str_cat.h"
#include "mediapipe/framework/port/gmock.h"
#include "mediapipe/framework/port/gtest.h"
@@ -18,6 +19,17 @@ class LiveCheck {
bool& alive_;
};
class Base {
public:
virtual ~Base() = default;
virtual absl::string_view name() const { return "Base"; }
};
class Derived : public Base {
public:
absl::string_view name() const override { return "Derived"; }
};
TEST(PacketTest, PacketBaseDefault) {
PacketBase p;
EXPECT_TRUE(p.IsEmpty());
@@ -242,6 +254,16 @@ TEST(PacketTest, OneOfConsume) {
EXPECT_TRUE(p.IsEmpty());
}
TEST(PacketTest, Polymorphism) {
Packet<Base> base = PacketAdopting<Base>(absl::make_unique<Derived>());
EXPECT_EQ(base->name(), "Derived");
// Since packet contents are implicitly immutable, if you need mutability the
// current recommendation is still to wrap the contents in a unique_ptr.
Packet<std::unique_ptr<Base>> mutable_base =
MakePacket<std::unique_ptr<Base>>(absl::make_unique<Derived>());
EXPECT_EQ((**mutable_base).name(), "Derived");
}
} // namespace
} // namespace api2
} // namespace mediapipe
+29 -8
View File
@@ -172,9 +172,14 @@ inline void SetType<NoneType>(CalculatorContract* cc, PacketType& pt) {
pt.SetNone();
}
template <typename... T>
inline void SetTypeOneOf(OneOf<T...>, CalculatorContract* cc, PacketType& pt) {
pt.SetOneOf<T...>();
}
template <typename T, typename std::enable_if<IsOneOf<T>{}, int>::type = 0>
inline void SetType(CalculatorContract* cc, PacketType& pt) {
pt.SetAny();
SetTypeOneOf(T{}, cc, pt);
}
template <typename ValueT>
@@ -294,14 +299,26 @@ struct SideBase<InputBase> {
using type = SideInputBase;
};
// TODO: maybe return a PacketBase instead of a Packet<internal::Generic>?
template <typename T, class = void>
struct ActualPayloadType {
using type = T;
};
template <typename T>
struct ActualPayloadType<
T, std::enable_if_t<std::is_base_of<DynamicType, T>{}, void>> {
using type = internal::Generic;
};
} // namespace internal
// TODO: maybe return a PacketBase instead of a Packet<internal::Generic>?
template <typename T, typename std::enable_if<
!std::is_base_of<DynamicType, T>{}, int>::type = 0>
auto ActualValueT(T) -> T;
// Maps special port value types, such as AnyType, to internal::Generic.
template <typename T>
using ActualPayloadT = typename internal::ActualPayloadType<T>::type;
auto ActualValueT(DynamicType) -> internal::Generic;
static_assert(std::is_same_v<ActualPayloadT<int>, int>, "");
static_assert(std::is_same_v<ActualPayloadT<AnyType>, internal::Generic>, "");
template <typename Base, typename ValueT, bool IsOptional = false,
bool IsMultiple = false>
@@ -325,7 +342,7 @@ class PortCommon : public Base {
explicit constexpr PortCommon(const char (&tag)[N])
: Base(N, tag, &get_type_hash<ValueT>, IsOptionalV, IsMultipleV) {}
using PayloadT = decltype(ActualValueT(std::declval<ValueT>()));
using PayloadT = ActualPayloadT<ValueT>;
auto operator()(CalculatorContext* cc) const {
return internal::AccessPort<PayloadT>(
@@ -385,7 +402,7 @@ class SideFallbackT : public Base {
static constexpr bool kOptional = IsOptionalV;
static constexpr bool kMultiple = IsMultipleV;
using Optional = SideFallbackT<Base, ValueT, true, IsMultipleV>;
using PayloadT = decltype(ActualValueT(std::declval<ValueT>()));
using PayloadT = ActualPayloadT<ValueT>;
const char* Tag() const { return stream_port.Tag(); }
@@ -499,6 +516,10 @@ class OutputShardAccess : public OutputShardAccessBase {
Send(std::move(payload), context_.InputTimestamp());
}
void SetHeader(const PacketBase& header) {
if (output_) output_->SetHeader(ToOldPacket(header));
}
private:
OutputShardAccess(const CalculatorContext& cc, OutputStreamShard* output)
: OutputShardAccessBase(cc, output) {}
+19
View File
@@ -21,6 +21,25 @@ TEST(PortTest, Tag) {
EXPECT_EQ(std::string(port.Tag()), "FOO");
}
struct DeletedCopyType {
DeletedCopyType(const DeletedCopyType&) = delete;
DeletedCopyType& operator=(const DeletedCopyType&) = delete;
};
TEST(PortTest, DeletedCopyConstructorInput) {
static constexpr Input<DeletedCopyType> kInputPort{"INPUT"};
EXPECT_EQ(std::string(kInputPort.Tag()), "INPUT");
static constexpr Output<DeletedCopyType> kOutputPort{"OUTPUT"};
EXPECT_EQ(std::string(kOutputPort.Tag()), "OUTPUT");
static constexpr SideInput<DeletedCopyType> kSideInputPort{"SIDE_INPUT"};
EXPECT_EQ(std::string(kSideInputPort.Tag()), "SIDE_INPUT");
static constexpr SideOutput<DeletedCopyType> kSideOutputPort{"SIDE_OUTPUT"};
EXPECT_EQ(std::string(kSideOutputPort.Tag()), "SIDE_OUTPUT");
}
} // namespace
} // namespace api2
} // namespace mediapipe
+2 -2
View File
@@ -26,8 +26,8 @@ TEST(TagTest, String) {
EXPECT_EQ(kBAR.str(), "BAR");
}
// Separate invocations of MPP_TAG with the same std::string produce objects of
// the same type.
// Separate invocations of MPP_TAG with the same string produce objects of the
// same type.
TEST(TagTest, SameType) { EXPECT_TRUE(same_type(kFOO, kFOO2)); }
// Different tags have different types.
+2 -2
View File
@@ -95,8 +95,8 @@ class CalculatorContract {
input_stream_handler_options_ = options;
}
// Returns the name of this Nodes's InputStreamHandler, or empty std::string
// if none is set.
// Returns the name of this Nodes's InputStreamHandler, or empty string if
// none is set.
std::string GetInputStreamHandler() const { return input_stream_handler_; }
// Returns the MediaPipeOptions of this Node's InputStreamHandler, or empty
+6 -9
View File
@@ -54,15 +54,13 @@
#include "mediapipe/framework/scheduler.h"
#include "mediapipe/framework/thread_pool_executor.pb.h"
#if !MEDIAPIPE_DISABLE_GPU
namespace mediapipe {
#if !MEDIAPIPE_DISABLE_GPU
class GpuResources;
struct GpuSharedData;
} // namespace mediapipe
#endif // !MEDIAPIPE_DISABLE_GPU
namespace mediapipe {
typedef absl::StatusOr<OutputStreamPoller> StatusOrPoller;
// The class representing a DAG of calculator nodes.
@@ -366,10 +364,9 @@ class CalculatorGraph {
#if !MEDIAPIPE_DISABLE_GPU
// Returns a pointer to the GpuResources in use, if any.
// Only meant for internal use.
std::shared_ptr<::mediapipe::GpuResources> GetGpuResources() const;
std::shared_ptr<GpuResources> GetGpuResources() const;
absl::Status SetGpuResources(
std::shared_ptr<::mediapipe::GpuResources> resources);
absl::Status SetGpuResources(std::shared_ptr<GpuResources> resources);
// Helper for PrepareForRun. If it returns a non-empty map, those packets
// must be added to the existing side packets, replacing existing values
@@ -532,7 +529,7 @@ class CalculatorGraph {
#if !MEDIAPIPE_DISABLE_GPU
// Owns the legacy GpuSharedData if we need to create one for backwards
// compatibility.
std::unique_ptr<::mediapipe::GpuSharedData> legacy_gpu_shared_;
std::unique_ptr<GpuSharedData> legacy_gpu_shared_;
#endif // !MEDIAPIPE_DISABLE_GPU
// True if the graph was initialized.
@@ -598,7 +595,7 @@ class CalculatorGraph {
std::unique_ptr<CounterFactory> counter_factory_;
// Executors for the scheduler, keyed by the executor's name. The default
// executor's name is the empty std::string.
// executor's name is the empty string.
std::map<std::string, std::shared_ptr<Executor>> executors_;
// The processed input side packet map for this run.
+6 -7
View File
@@ -768,7 +768,7 @@ typedef TypedStatusHandler<uint32> Uint32StatusHandler;
REGISTER_STATUS_HANDLER(StringStatusHandler);
REGISTER_STATUS_HANDLER(Uint32StatusHandler);
// A std::string generator that will succeed.
// A string generator that will succeed.
class StaticCounterStringGenerator : public PacketGenerator {
public:
static absl::Status FillExpectations(
@@ -1767,15 +1767,14 @@ TEST(CalculatorGraph, StatusHandlerInputVerification) {
EXPECT_FALSE(graph->Run({{"a_uint64", a_uint64}}).ok());
// Should fail verification when the type of an already created packet is
// wrong. Here we give the uint64 packet instead of the std::string packet to
// the StringStatusHandler.
// wrong. Here we give the uint64 packet instead of the string packet to the
// StringStatusHandler.
EXPECT_FALSE(
graph->Run({{"extra_string", a_uint64}, {"a_uint64", a_uint64}}).ok());
// Should fail verification when the type of a packet generated by a base
// packet factory is wrong. Everything is correct except we add a status
// handler expecting a uint32 but give it the std::string from the packet
// factory.
// handler expecting a uint32 but give it the string from the packet factory.
auto* invalid_handler = config.add_status_handler();
invalid_handler->set_status_handler("Uint32StatusHandler");
invalid_handler->add_input_side_packet("created_by_factory");
@@ -1792,8 +1791,8 @@ TEST(CalculatorGraph, StatusHandlerInputVerification) {
MediaPipeTypeStringOrDemangled<uint32>())));
// Should fail verification when the type of a to-be-generated packet is
// wrong. The added handler now expects a std::string but will receive the
// uint32 generated by the existing generator.
// wrong. The added handler now expects a string but will receive the uint32
// generated by the existing generator.
invalid_handler->set_status_handler("StringStatusHandler");
invalid_handler->set_input_side_packet(0, "generated_by_generator");
graph.reset(new CalculatorGraph());
+4 -5
View File
@@ -79,10 +79,9 @@ class CalculatorNode {
// running first. If a node is not a source, this method is not called.
Timestamp SourceProcessOrder(const CalculatorContext* cc) const;
// Retrieves a std::string name for the node. If the node's name was set in
// the calculator graph config, it will be returned. Otherwise, a
// human-readable std::string that uniquely identifies the node is returned,
// e.g.
// Retrieves a string name for the node. If the node's name was set in the
// calculator graph config, it will be returned. Otherwise, a human-readable
// string that uniquely identifies the node is returned, e.g.
// "[FooBarCalculator with first output stream \"foo_bar_output\"]" for
// non-sink nodes and "[FooBarCalculator with node ID: 42 and input streams:
// \"foo_bar_input\"]" for sink nodes. This name should be used in error
@@ -278,7 +277,7 @@ class CalculatorNode {
void CloseInputStreams() ABSL_LOCKS_EXCLUDED(status_mutex_);
void CloseOutputStreams(OutputStreamShardSet* outputs)
ABSL_LOCKS_EXCLUDED(status_mutex_);
// Get a std::string describing the input streams.
// Get a string describing the input streams.
std::string DebugInputStreamNames() const;
// Returns true if all outputs will be identical to the previous graph run.
+1 -1
View File
@@ -62,7 +62,7 @@ class CalculatorRunner {
// )");
explicit CalculatorRunner(const CalculatorGraphConfig::Node& node_config);
#if !defined(MEDIAPIPE_PROTO_LITE)
// Convenience constructor which takes a node_config std::string directly.
// Convenience constructor which takes a node_config string directly.
explicit CalculatorRunner(const std::string& node_config_string);
// Convenience constructor to initialize a calculator which uses indexes
// (not tags) for all its fields.
+4 -3
View File
@@ -51,7 +51,8 @@ std::string JoinPathImpl(bool honor_abs,
//
// Usage:
// std::string path = file::JoinPath("/cns", dirname, filename);
// std::string path = file::JoinPath("./", filename);
// std::string path = file::JoinPath("./",
// filename);
//
// 0, 1, 2-path specializations exist to optimize common cases.
inline std::string JoinPath() { return std::string(); }
@@ -69,7 +70,7 @@ inline std::string JoinPath(absl::string_view path1, absl::string_view path2,
// * If there is a single leading "/" in the path, the result will be the
// leading "/".
// * If there is no "/" in the path, the result is the empty prefix of the
// input std::string.
// input string.
absl::string_view Dirname(absl::string_view path);
// Return the parts of the path, split on the final "/". If there is no
@@ -83,7 +84,7 @@ std::pair<absl::string_view, absl::string_view> SplitPath(
// "/" in the path, the result is the same as the input.
// Note that this function's behavior differs from the Unix basename
// command if path ends with "/". For such paths, this function returns the
// empty std::string.
// empty string.
absl::string_view Basename(absl::string_view path);
// Returns the part of the basename of path after the final ".". If
+2
View File
@@ -15,6 +15,8 @@
#ifndef MEDIAPIPE_DEPS_NUMBERS_H_
#define MEDIAPIPE_DEPS_NUMBERS_H_
#include <string>
#include "absl/strings/numbers.h"
#include "absl/strings/str_cat.h"
#include "mediapipe/framework/port/integral_types.h"
+1 -1
View File
@@ -145,7 +145,7 @@ class Rectangle {
void AddBorder(const T& border_size);
// Debug printing.
friend std::ostream& operator<<<T>(std::ostream&, const Rectangle&);
friend std::ostream& operator<< <T>(std::ostream&, const Rectangle&);
private:
Point2<T> min_;
+1 -1
View File
@@ -370,7 +370,7 @@ class GlobalFactoryRegistry {
GlobalFactoryRegistry() = delete;
};
// Two levels of macros are required to convert __LINE__ into a std::string
// Two levels of macros are required to convert __LINE__ into a string
// containing the line number.
#define REGISTRY_STATIC_VAR_INNER(var_name, line) var_name##_##line##__
#define REGISTRY_STATIC_VAR(var_name, line) \
+4 -4
View File
@@ -25,7 +25,7 @@ class Singleton {
public:
// Returns the pointer to the singleton of type |T|.
// This method is thread-safe.
static T *get() LOCKS_EXCLUDED(mu_) {
static T *get() ABSL_LOCKS_EXCLUDED(mu_) {
absl::MutexLock lock(&mu_);
if (instance_) {
return instance_;
@@ -46,7 +46,7 @@ class Singleton {
// cannot be recreated. However, the callers of this method responsible for
// making sure that no other threads are accessing (or plan to access) the
// singleton any longer.
static void Destruct() LOCKS_EXCLUDED(mu_) {
static void Destruct() ABSL_LOCKS_EXCLUDED(mu_) {
absl::MutexLock lock(&mu_);
T *tmp_ptr = instance_;
instance_ = nullptr;
@@ -55,8 +55,8 @@ class Singleton {
}
private:
static T *instance_ GUARDED_BY(mu_);
static bool destroyed_ GUARDED_BY(mu_);
static T *instance_ ABSL_GUARDED_BY(mu_);
static bool destroyed_ ABSL_GUARDED_BY(mu_);
static absl::Mutex mu_;
};
+1 -1
View File
@@ -47,7 +47,7 @@ class source_location {
// MEDIAPIPE_LOC macro below.
//
// file_name must outlive all copies of the source_location
// object, so in practice it should be a std::string literal.
// object, so in practice it should be a string literal.
constexpr source_location(std::uint_least32_t line, const char* file_name)
: line_(line), file_name_(file_name) {}
+1 -1
View File
@@ -29,7 +29,7 @@ std::string* MediaPipeCheckOpHelperOutOfLine(const absl::Status& v,
r += msg;
r += " status: ";
r += v.ToString();
// Leaks std::string but this is only to be used in a fatal error message
// Leaks string but this is only to be used in a fatal error message
return new std::string(r);
}
+25 -7
View File
@@ -15,6 +15,7 @@
#include "mediapipe/framework/deps/status_builder.h"
#include "absl/memory/memory.h"
#include "absl/status/status.h"
namespace mediapipe {
@@ -23,7 +24,9 @@ StatusBuilder::StatusBuilder(const StatusBuilder& sb) {
file_ = sb.file_;
line_ = sb.line_;
no_logging_ = sb.no_logging_;
stream_ = absl::make_unique<std::ostringstream>(sb.stream_->str());
stream_ = sb.stream_
? absl::make_unique<std::ostringstream>(sb.stream_->str())
: nullptr;
join_style_ = sb.join_style_;
}
@@ -32,43 +35,58 @@ StatusBuilder& StatusBuilder::operator=(const StatusBuilder& sb) {
file_ = sb.file_;
line_ = sb.line_;
no_logging_ = sb.no_logging_;
stream_ = absl::make_unique<std::ostringstream>(sb.stream_->str());
stream_ = sb.stream_
? absl::make_unique<std::ostringstream>(sb.stream_->str())
: nullptr;
join_style_ = sb.join_style_;
return *this;
}
StatusBuilder& StatusBuilder::SetAppend() {
StatusBuilder& StatusBuilder::SetAppend() & {
if (status_.ok()) return *this;
join_style_ = MessageJoinStyle::kAppend;
return *this;
}
StatusBuilder& StatusBuilder::SetPrepend() {
StatusBuilder&& StatusBuilder::SetAppend() && { return std::move(SetAppend()); }
StatusBuilder& StatusBuilder::SetPrepend() & {
if (status_.ok()) return *this;
join_style_ = MessageJoinStyle::kPrepend;
return *this;
}
StatusBuilder& StatusBuilder::SetNoLogging() {
StatusBuilder&& StatusBuilder::SetPrepend() && {
return std::move(SetPrepend());
}
StatusBuilder& StatusBuilder::SetNoLogging() & {
no_logging_ = true;
return *this;
}
StatusBuilder&& StatusBuilder::SetNoLogging() && {
return std::move(SetNoLogging());
}
StatusBuilder::operator Status() const& {
if (stream_->str().empty() || no_logging_) {
if (!stream_ || stream_->str().empty() || no_logging_) {
return status_;
}
return StatusBuilder(*this).JoinMessageToStatus();
}
StatusBuilder::operator Status() && {
if (stream_->str().empty() || no_logging_) {
if (!stream_ || stream_->str().empty() || no_logging_) {
return status_;
}
return JoinMessageToStatus();
}
absl::Status StatusBuilder::JoinMessageToStatus() {
if (!stream_) {
return absl::OkStatus();
}
std::string message;
if (join_style_ == MessageJoinStyle::kAnnotate) {
if (!status_.ok()) {
+38 -10
View File
@@ -15,7 +15,13 @@
#ifndef MEDIAPIPE_DEPS_STATUS_BUILDER_H_
#define MEDIAPIPE_DEPS_STATUS_BUILDER_H_
#include <memory>
#include <sstream>
#include <utility>
#include "absl/base/attributes.h"
#include "absl/memory/memory.h"
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "mediapipe/framework/deps/source_location.h"
@@ -27,6 +33,10 @@ class ABSL_MUST_USE_RESULT StatusBuilder {
public:
StatusBuilder(const StatusBuilder& sb);
StatusBuilder& operator=(const StatusBuilder& sb);
StatusBuilder(StatusBuilder&&) = default;
StatusBuilder& operator=(StatusBuilder&&) = default;
// Creates a `StatusBuilder` based on an original status. If logging is
// enabled, it will use `location` as the location from which the log message
// occurs. A typical user will call this with `MEDIAPIPE_LOC`.
@@ -35,14 +45,14 @@ class ABSL_MUST_USE_RESULT StatusBuilder {
: status_(original_status),
line_(location.line()),
file_(location.file_name()),
stream_(new std::ostringstream) {}
stream_(InitStream(status_)) {}
StatusBuilder(absl::Status&& original_status,
mediapipe::source_location location)
: status_(std::move(original_status)),
line_(location.line()),
file_(location.file_name()),
stream_(new std::ostringstream) {}
stream_(InitStream(status_)) {}
// Creates a `StatusBuilder` from a mediapipe status code. If logging is
// enabled, it will use `location` as the location from which the log message
@@ -51,29 +61,37 @@ class ABSL_MUST_USE_RESULT StatusBuilder {
: status_(code, ""),
line_(location.line()),
file_(location.file_name()),
stream_(new std::ostringstream) {}
stream_(InitStream(status_)) {}
StatusBuilder(const absl::Status& original_status, const char* file, int line)
: status_(original_status),
line_(line),
file_(file),
stream_(new std::ostringstream) {}
stream_(InitStream(status_)) {}
bool ok() const { return status_.ok(); }
StatusBuilder& SetAppend();
StatusBuilder& SetAppend() &;
StatusBuilder&& SetAppend() &&;
StatusBuilder& SetPrepend();
StatusBuilder& SetPrepend() &;
StatusBuilder&& SetPrepend() &&;
StatusBuilder& SetNoLogging();
StatusBuilder& SetNoLogging() &;
StatusBuilder&& SetNoLogging() &&;
template <typename T>
StatusBuilder& operator<<(const T& msg) {
if (status_.ok()) return *this;
StatusBuilder& operator<<(const T& msg) & {
if (!stream_) return *this;
*stream_ << msg;
return *this;
}
template <typename T>
StatusBuilder&& operator<<(const T& msg) && {
return std::move(*this << msg);
}
operator Status() const&;
operator Status() &&;
@@ -88,6 +106,15 @@ class ABSL_MUST_USE_RESULT StatusBuilder {
kPrepend,
};
// Conditionally creates an ostringstream if the status is not ok.
static std::unique_ptr<std::ostringstream> InitStream(
const absl::Status status) {
if (status.ok()) {
return nullptr;
}
return absl::make_unique<std::ostringstream>();
}
// The status that the result will be based on.
absl::Status status_;
// The line to record if this file is logged.
@@ -95,7 +122,8 @@ class ABSL_MUST_USE_RESULT StatusBuilder {
// Not-owned: The file to record if this status is logged.
const char* file_;
bool no_logging_ = false;
// The additional messages added with `<<`.
// The additional messages added with `<<`. This is nullptr when status_ is
// ok.
std::unique_ptr<std::ostringstream> stream_;
// Specifies how to join the message in `status_` and `stream_`.
MessageJoinStyle join_style_ = MessageJoinStyle::kAnnotate;
@@ -18,6 +18,21 @@
namespace mediapipe {
TEST(StatusBuilder, OkStatusLvalue) {
StatusBuilder builder(absl::OkStatus(), MEDIAPIPE_LOC);
builder << "annotated message1 "
<< "annotated message2";
absl::Status status = builder;
ASSERT_EQ(status, absl::OkStatus());
}
TEST(StatusBuilder, OkStatusRvalue) {
absl::Status status = StatusBuilder(absl::OkStatus(), MEDIAPIPE_LOC)
<< "annotated message1 "
<< "annotated message2";
ASSERT_EQ(status, absl::OkStatus());
}
TEST(StatusBuilder, AnnotateMode) {
absl::Status status = StatusBuilder(absl::Status(absl::StatusCode::kNotFound,
"original message"),
@@ -30,7 +45,12 @@ TEST(StatusBuilder, AnnotateMode) {
"original message; annotated message1 annotated message2");
}
TEST(StatusBuilder, PrependMode) {
TEST(StatusBuilder, PrependModeLvalue) {
StatusBuilder builder(
absl::Status(absl::StatusCode::kInvalidArgument, "original message"),
MEDIAPIPE_LOC);
builder.SetPrepend() << "prepended message1 "
<< "prepended message2 ";
absl::Status status =
StatusBuilder(
absl::Status(absl::StatusCode::kInvalidArgument, "original message"),
@@ -44,7 +64,33 @@ TEST(StatusBuilder, PrependMode) {
"prepended message1 prepended message2 original message");
}
TEST(StatusBuilder, AppendMode) {
TEST(StatusBuilder, PrependModeRvalue) {
absl::Status status =
StatusBuilder(
absl::Status(absl::StatusCode::kInvalidArgument, "original message"),
MEDIAPIPE_LOC)
.SetPrepend()
<< "prepended message1 "
<< "prepended message2 ";
ASSERT_FALSE(status.ok());
EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(status.message(),
"prepended message1 prepended message2 original message");
}
TEST(StatusBuilder, AppendModeLvalue) {
StatusBuilder builder(
absl::Status(absl::StatusCode::kInternal, "original message"),
MEDIAPIPE_LOC);
builder.SetAppend() << " extra message1"
<< " extra message2";
absl::Status status = builder;
ASSERT_FALSE(status.ok());
EXPECT_EQ(status.code(), absl::StatusCode::kInternal);
EXPECT_EQ(status.message(), "original message extra message1 extra message2");
}
TEST(StatusBuilder, AppendModeRvalue) {
absl::Status status = StatusBuilder(absl::Status(absl::StatusCode::kInternal,
"original message"),
MEDIAPIPE_LOC)
@@ -56,7 +102,18 @@ TEST(StatusBuilder, AppendMode) {
EXPECT_EQ(status.message(), "original message extra message1 extra message2");
}
TEST(StatusBuilder, NoLoggingMode) {
TEST(StatusBuilder, NoLoggingModeLvalue) {
StatusBuilder builder(
absl::Status(absl::StatusCode::kUnavailable, "original message"),
MEDIAPIPE_LOC);
builder.SetNoLogging() << " extra message";
absl::Status status = builder;
ASSERT_FALSE(status.ok());
EXPECT_EQ(status.code(), absl::StatusCode::kUnavailable);
EXPECT_EQ(status.message(), "original message");
}
TEST(StatusBuilder, NoLoggingModeRvalue) {
absl::Status status =
StatusBuilder(
absl::Status(absl::StatusCode::kUnavailable, "original message"),
+19 -12
View File
@@ -150,21 +150,28 @@
#define STATUS_MACROS_IMPL_GET_VARIADIC_(args) \
STATUS_MACROS_IMPL_GET_VARIADIC_HELPER_ args
#define STATUS_MACROS_IMPL_ASSIGN_OR_RETURN_2_(lhs, rexpr) \
STATUS_MACROS_IMPL_ASSIGN_OR_RETURN_3_(lhs, rexpr, std::move(_))
#define STATUS_MACROS_IMPL_ASSIGN_OR_RETURN_2_(lhs, rexpr) \
STATUS_MACROS_IMPL_ASSIGN_OR_RETURN_( \
STATUS_MACROS_IMPL_CONCAT_(_status_or_value, __LINE__), lhs, rexpr, \
return mediapipe::StatusBuilder( \
std::move(STATUS_MACROS_IMPL_CONCAT_(_status_or_value, __LINE__)) \
.status(), \
__FILE__, __LINE__))
#define STATUS_MACROS_IMPL_ASSIGN_OR_RETURN_3_(lhs, rexpr, error_expression) \
STATUS_MACROS_IMPL_ASSIGN_OR_RETURN_( \
STATUS_MACROS_IMPL_CONCAT_(_status_or_value, __LINE__), lhs, rexpr, \
error_expression)
#define STATUS_MACROS_IMPL_ASSIGN_OR_RETURN_(statusor, lhs, rexpr, \
error_expression) \
auto statusor = (rexpr); \
if (ABSL_PREDICT_FALSE(!statusor.ok())) { \
mediapipe::StatusBuilder _(std::move(statusor).status(), __FILE__, \
__LINE__); \
(void)_; /* error_expression is allowed to not use this variable */ \
return (error_expression); \
} \
mediapipe::StatusBuilder _( \
std::move(STATUS_MACROS_IMPL_CONCAT_(_status_or_value, __LINE__)) \
.status(), \
__FILE__, __LINE__); \
(void)_; /* error_expression is allowed to not use this variable */ \
return (error_expression))
#define STATUS_MACROS_IMPL_ASSIGN_OR_RETURN_(statusor, lhs, rexpr, \
error_expression) \
auto statusor = (rexpr); \
if (ABSL_PREDICT_FALSE(!statusor.ok())) { \
error_expression; \
} \
lhs = std::move(statusor).value()
// Internal helper for concatenating macro values.
+6 -5
View File
@@ -332,15 +332,13 @@ cc_library(
"//mediapipe/framework:port",
"//mediapipe/framework:type_map",
"//mediapipe/framework/port:logging",
"//mediapipe/gpu:gpu_buffer",
"//mediapipe/gpu:gpu_buffer_format",
] + select({
"//conditions:default": [
"//mediapipe/gpu:gpu_buffer",
"//mediapipe/gpu:gpu_buffer_format",
"//mediapipe/gpu:gl_texture_buffer",
],
"//mediapipe:ios": [
"//mediapipe/gpu:gpu_buffer",
"//mediapipe/gpu:gpu_buffer_format",
],
"//mediapipe/gpu:disable_gpu": [],
}) + select({
@@ -430,7 +428,10 @@ cc_test(
cc_library(
name = "tensor",
srcs = ["tensor.cc"],
srcs =
[
"tensor.cc",
],
hdrs = ["tensor.h"],
copts = select({
"//mediapipe:apple": [
+6 -51
View File
@@ -16,48 +16,15 @@
#include "mediapipe/framework/type_map.h"
#if !MEDIAPIPE_DISABLE_GPU
#include "mediapipe/gpu/gl_texture_view.h"
#endif // !MEDIAPIPE_DISABLE_GPU
namespace mediapipe {
// TODO Refactor common code from GpuBufferToImageFrameCalculator
bool Image::ConvertToCpu() const {
if (!use_gpu_) return true; // Already on CPU.
#if !MEDIAPIPE_DISABLE_GPU
#if MEDIAPIPE_GPU_BUFFER_USE_CV_PIXEL_BUFFER
image_frame_ = CreateImageFrameForCVPixelBuffer(GetCVPixelBufferRef());
#else
auto gl_texture = gpu_buffer_.GetGlTextureBufferSharedPtr();
if (!gl_texture->GetProducerContext()) return false;
gl_texture->GetProducerContext()->Run([this, &gl_texture]() {
gl_texture->WaitOnGpu();
const auto gpu_buf = mediapipe::GpuBuffer(GetGlTextureBufferSharedPtr());
#ifdef __ANDROID__
glBindFramebuffer(GL_FRAMEBUFFER, 0); // b/32091368
#endif
GLuint fb = 0;
glDisable(GL_DEPTH_TEST);
// TODO Re-use a shared framebuffer.
glGenFramebuffers(1, &fb);
glBindFramebuffer(GL_FRAMEBUFFER, fb);
glViewport(0, 0, gpu_buf.width(), gpu_buf.height());
glActiveTexture(GL_TEXTURE0);
glBindTexture(gl_texture->target(), gl_texture->name());
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
gl_texture->target(), gl_texture->name(), 0);
auto frame = std::make_shared<ImageFrame>(
mediapipe::ImageFormatForGpuBufferFormat(gpu_buf.format()),
gpu_buf.width(), gpu_buf.height(),
ImageFrame::kGlDefaultAlignmentBoundary);
const auto info = GlTextureInfoForGpuBufferFormat(
gpu_buf.format(), 0, gl_texture->GetProducerContext()->GetGlVersion());
glReadPixels(0, 0, gpu_buf.width(), gpu_buf.height(), info.gl_format,
info.gl_type, frame->MutablePixelData());
glDeleteFramebuffers(1, &fb);
// Cleanup
gl_texture->DidRead(gl_texture->GetProducerContext()->CreateSyncToken());
image_frame_ = frame;
});
#endif // MEDIAPIPE_GPU_BUFFER_USE_CV_PIXEL_BUFFER
#endif // !MEDIAPIPE_DISABLE_GPU
auto view = gpu_buffer_.GetReadView<ImageFrame>();
use_gpu_ = false;
return true;
}
@@ -67,19 +34,7 @@ bool Image::ConvertToGpu() const {
#if MEDIAPIPE_DISABLE_GPU
return false;
#else
if (use_gpu_) return true; // Already on GPU.
#if MEDIAPIPE_GPU_BUFFER_USE_CV_PIXEL_BUFFER
auto packet = PointToForeign<ImageFrame>(image_frame_.get());
CFHolder<CVPixelBufferRef> buffer;
auto status = CreateCVPixelBufferForImageFramePacket(packet, true, &buffer);
CHECK_OK(status);
gpu_buffer_ = mediapipe::GpuBuffer(std::move(buffer));
#else
// GlCalculatorHelperImpl::MakeGlTextureBuffer (CreateSourceTexture)
auto buffer = mediapipe::GlTextureBuffer::Create(*image_frame_);
glFlush();
gpu_buffer_ = mediapipe::GpuBuffer(std::move(buffer));
#endif // MEDIAPIPE_GPU_BUFFER_USE_CV_PIXEL_BUFFER
auto view = gpu_buffer_.GetReadView<GlTextureView>(0);
use_gpu_ = true;
return true;
#endif // MEDIAPIPE_DISABLE_GPU
+34 -85
View File
@@ -21,20 +21,18 @@
#include "mediapipe/framework/formats/image_format.pb.h"
#include "mediapipe/framework/formats/image_frame.h"
#include "mediapipe/framework/port/logging.h"
#if !MEDIAPIPE_DISABLE_GPU
#include "mediapipe/gpu/gpu_buffer.h"
#include "mediapipe/gpu/gpu_buffer_format.h"
#include "mediapipe/gpu/gpu_buffer_storage_image_frame.h"
#include "mediapipe/gpu/image_frame_view.h"
#if !MEDIAPIPE_DISABLE_GPU
#if defined(__APPLE__)
#include <CoreVideo/CoreVideo.h>
#include "mediapipe/objc/CFHolder.h"
#include "mediapipe/objc/util.h"
#if !TARGET_OS_OSX // iOS, use CVPixelBuffer.
#define MEDIAPIPE_GPU_BUFFER_USE_CV_PIXEL_BUFFER 1
#endif // TARGET_OS_OSX
#endif // defined(__APPLE__)
#if !MEDIAPIPE_GPU_BUFFER_USE_CV_PIXEL_BUFFER // OSX, use GL textures.
@@ -73,15 +71,15 @@ class Image {
// Creates an Image representing the same image content as the ImageFrame
// the input shared pointer points to, and retaining shared ownership.
explicit Image(ImageFrameSharedPtr image_frame)
: image_frame_(std::move(image_frame)) {
: gpu_buffer_(std::make_shared<GpuBufferStorageImageFrame>(
std::move(image_frame))) {
use_gpu_ = false;
pixel_mutex_ = std::make_shared<absl::Mutex>();
}
// CPU getters.
const ImageFrameSharedPtr& GetImageFrameSharedPtr() const {
if (use_gpu_ == true) ConvertToCpu();
return image_frame_;
ImageFrameSharedPtr GetImageFrameSharedPtr() const {
// Write view currently because the return type does not point to const IF.
return gpu_buffer_.GetWriteView<ImageFrame>();
}
// Creates an Image representing the same image content as the input GPU
@@ -99,19 +97,18 @@ class Image {
explicit Image(mediapipe::GpuBuffer gpu_buffer) {
use_gpu_ = true;
gpu_buffer_ = gpu_buffer;
pixel_mutex_ = std::make_shared<absl::Mutex>();
}
// GPU getters.
#if MEDIAPIPE_GPU_BUFFER_USE_CV_PIXEL_BUFFER
CVPixelBufferRef GetCVPixelBufferRef() const {
if (use_gpu_ == false) ConvertToGpu();
return gpu_buffer_.GetCVPixelBufferRef();
return mediapipe::GetCVPixelBufferRef(gpu_buffer_);
}
#else
mediapipe::GlTextureBufferSharedPtr GetGlTextureBufferSharedPtr() const {
if (use_gpu_ == false) ConvertToGpu();
return gpu_buffer_.GetGlTextureBufferSharedPtr();
return gpu_buffer_.internal_storage<mediapipe::GlTextureBuffer>();
}
#endif // MEDIAPIPE_GPU_BUFFER_USE_CV_PIXEL_BUFFER
// Get a GPU view. Automatically uploads from CPU if needed.
@@ -128,9 +125,7 @@ class Image {
int step() const; // Row size in bytes.
bool UsesGpu() const { return use_gpu_; }
ImageFormat::Format image_format() const;
#if !MEDIAPIPE_DISABLE_GPU
mediapipe::GpuBufferFormat format() const;
#endif // !MEDIAPIPE_DISABLE_GPU
// Converts to true iff valid.
explicit operator bool() const { return operator!=(nullptr); }
@@ -147,8 +142,8 @@ class Image {
// Lock/Unlock pixel data.
// Should be used exclusively by the PixelLock helper class.
void LockPixels() const ABSL_EXCLUSIVE_LOCK_FUNCTION(pixel_mutex_);
void UnlockPixels() const ABSL_UNLOCK_FUNCTION(pixel_mutex_);
void LockPixels() const ABSL_EXCLUSIVE_LOCK_FUNCTION();
void UnlockPixels() const ABSL_UNLOCK_FUNCTION();
// Helper utility for GPU->CPU data transfer.
bool ConvertToCpu() const;
@@ -157,75 +152,32 @@ class Image {
bool ConvertToGpu() const;
private:
#if !MEDIAPIPE_DISABLE_GPU
mutable mediapipe::GpuBuffer gpu_buffer_;
#endif // !MEDIAPIPE_DISABLE_GPU
mutable ImageFrameSharedPtr image_frame_;
mutable bool use_gpu_ = false;
mutable std::shared_ptr<absl::Mutex> pixel_mutex_; // ImageFrame only.
};
inline int Image::width() const {
#if !MEDIAPIPE_DISABLE_GPU
if (use_gpu_)
return gpu_buffer_.width();
else
#endif // !MEDIAPIPE_DISABLE_GPU
return image_frame_->Width();
}
inline int Image::width() const { return gpu_buffer_.width(); }
inline int Image::height() const {
#if !MEDIAPIPE_DISABLE_GPU
if (use_gpu_)
return gpu_buffer_.height();
else
#endif // !MEDIAPIPE_DISABLE_GPU
return image_frame_->Height();
}
inline int Image::height() const { return gpu_buffer_.height(); }
inline ImageFormat::Format Image::image_format() const {
#if !MEDIAPIPE_DISABLE_GPU
if (use_gpu_)
return mediapipe::ImageFormatForGpuBufferFormat(gpu_buffer_.format());
else
#endif // !MEDIAPIPE_DISABLE_GPU
return image_frame_->Format();
return mediapipe::ImageFormatForGpuBufferFormat(gpu_buffer_.format());
}
#if !MEDIAPIPE_DISABLE_GPU
inline mediapipe::GpuBufferFormat Image::format() const {
if (use_gpu_)
return gpu_buffer_.format();
else
return mediapipe::GpuBufferFormatForImageFormat(image_frame_->Format());
return gpu_buffer_.format();
}
#endif // !MEDIAPIPE_DISABLE_GPU
inline bool Image::operator==(std::nullptr_t other) const {
#if !MEDIAPIPE_DISABLE_GPU
if (use_gpu_)
return gpu_buffer_ == other;
else
#endif // !MEDIAPIPE_DISABLE_GPU
return image_frame_ == other;
return gpu_buffer_ == other;
}
inline bool Image::operator==(const Image& other) const {
#if !MEDIAPIPE_DISABLE_GPU
if (use_gpu_)
return gpu_buffer_ == other.gpu_buffer_;
else
#endif // !MEDIAPIPE_DISABLE_GPU
return image_frame_ == other.image_frame_;
return gpu_buffer_ == other.gpu_buffer_;
}
inline Image& Image::operator=(std::nullptr_t other) {
#if !MEDIAPIPE_DISABLE_GPU
if (use_gpu_)
gpu_buffer_ = other;
else
#endif // !MEDIAPIPE_DISABLE_GPU
image_frame_ = other;
gpu_buffer_ = other;
return *this;
}
@@ -234,19 +186,14 @@ inline int Image::channels() const {
}
inline int Image::step() const {
if (use_gpu_)
return width() * channels() *
ImageFrame::ByteDepthForFormat(image_format());
else
return image_frame_->WidthStep();
return gpu_buffer_.GetReadView<ImageFrame>()->WidthStep();
}
inline void Image::LockPixels() const {
pixel_mutex_->Lock();
ConvertToCpu(); // Download data if necessary.
}
inline void Image::UnlockPixels() const { pixel_mutex_->Unlock(); }
inline void Image::UnlockPixels() const {}
// Helper class for getting access to Image CPU data,
// and handles automatically locking/unlocking CPU data access.
@@ -268,7 +215,10 @@ class PixelReadLock {
public:
explicit PixelReadLock(const Image& image) {
buffer_ = &image;
if (buffer_) buffer_->LockPixels();
if (buffer_) {
buffer_->LockPixels();
frame_ = buffer_->GetImageFrameSharedPtr();
}
}
~PixelReadLock() {
if (buffer_) buffer_->UnlockPixels();
@@ -276,10 +226,7 @@ class PixelReadLock {
PixelReadLock(const PixelReadLock&) = delete;
const uint8* Pixels() const {
if (buffer_ && !buffer_->UsesGpu()) {
ImageFrame* frame = buffer_->GetImageFrameSharedPtr().get();
if (frame) return frame->PixelData();
}
if (frame_) return frame_->PixelData();
return nullptr;
}
@@ -287,13 +234,17 @@ class PixelReadLock {
private:
const Image* buffer_ = nullptr;
std::shared_ptr<ImageFrame> frame_;
};
class PixelWriteLock {
public:
explicit PixelWriteLock(Image* image) {
buffer_ = image;
if (buffer_) buffer_->LockPixels();
if (buffer_) {
buffer_->LockPixels();
frame_ = buffer_->GetImageFrameSharedPtr();
}
}
~PixelWriteLock() {
if (buffer_) buffer_->UnlockPixels();
@@ -301,10 +252,7 @@ class PixelWriteLock {
PixelWriteLock(const PixelWriteLock&) = delete;
uint8* Pixels() {
if (buffer_ && !buffer_->UsesGpu()) {
ImageFrame* frame = buffer_->GetImageFrameSharedPtr().get();
if (frame) return frame->MutablePixelData();
}
if (frame_) return frame_->MutablePixelData();
return nullptr;
}
@@ -312,6 +260,7 @@ class PixelWriteLock {
private:
const Image* buffer_ = nullptr;
std::shared_ptr<ImageFrame> frame_;
};
} // namespace mediapipe
+18 -5
View File
@@ -77,7 +77,16 @@ int GetMatType(const mediapipe::ImageFormat::Format format) {
namespace mediapipe {
namespace formats {
cv::Mat MatView(const mediapipe::Image* image) {
std::shared_ptr<cv::Mat> MatView(const mediapipe::Image* image) {
// Used to hold the lock through the Mat's lifetime.
struct MatWithPixelLock {
// Constructor needed because you cannot use aggregate initialization with
// std::make_shared.
MatWithPixelLock(mediapipe::Image* image) : lock(image) {}
mediapipe::PixelWriteLock lock;
cv::Mat mat;
};
const int dims = 2;
const int sizes[] = {image->height(), image->width()};
const int type =
@@ -85,18 +94,22 @@ cv::Mat MatView(const mediapipe::Image* image) {
const size_t steps[] = {static_cast<size_t>(image->step()),
static_cast<size_t>(ImageFrame::ByteDepthForFormat(
image->image_format()))};
mediapipe::PixelWriteLock dst_lock(const_cast<mediapipe::Image*>(image));
uint8* data_ptr = dst_lock.Pixels();
auto owner =
std::make_shared<MatWithPixelLock>(const_cast<mediapipe::Image*>(image));
uint8* data_ptr = owner->lock.Pixels();
CHECK(data_ptr != nullptr);
// Use Image to initialize in-place. Image still owns memory.
if (steps[0] == sizes[1] * image->channels() *
ImageFrame::ByteDepthForFormat(image->image_format())) {
// Contiguous memory optimization. See b/78570764
return cv::Mat(dims, sizes, type, data_ptr);
owner->mat = cv::Mat(dims, sizes, type, data_ptr);
} else {
// Custom width step.
return cv::Mat(dims, sizes, type, data_ptr, steps);
owner->mat = cv::Mat(dims, sizes, type, data_ptr, steps);
}
// Aliasing constructor makes a shared_ptr<Mat> which keeps the whole
// MatWithPixelLock alive.
return std::shared_ptr<cv::Mat>(owner, &owner->mat);
}
} // namespace formats
} // namespace mediapipe
+3 -1
View File
@@ -29,7 +29,9 @@ namespace formats {
// the const modifier is lost. The caller must be careful
// not to use the returned object to modify the data in a const Image,
// even though the returned data is mutable.
cv::Mat MatView(const mediapipe::Image* image);
// Note: this returns a shared_ptr so it can keep the CPU memory referenced
// by the Mat alive.
std::shared_ptr<cv::Mat> MatView(const mediapipe::Image* image);
} // namespace formats
} // namespace mediapipe
+1 -1
View File
@@ -39,7 +39,7 @@ void MatrixDataProtoFromMatrix(const Matrix& matrix, MatrixData* matrix_data);
void MatrixFromMatrixDataProto(const MatrixData& matrix_data, Matrix* matrix);
#if !defined(MEDIAPIPE_MOBILE) && !defined(MEDIAPIPE_LITE)
// Produce a Text format MatrixData std::string. Mainly useful for test code.
// Produce a Text format MatrixData string. Mainly useful for test code.
std::string MatrixAsTextProto(const Matrix& matrix);
// Produce a Matrix from a text format MatrixData proto representation.
void MatrixFromTextProto(const std::string& text_proto, Matrix* matrix);
+8 -1
View File
@@ -76,7 +76,7 @@ class Tensor {
public:
// No resources are allocated here.
enum class ElementType { kNone, kFloat16, kFloat32 };
enum class ElementType { kNone, kFloat16, kFloat32, kUInt8 };
struct Shape {
Shape() = default;
Shape(std::initializer_list<int> dimensions) : dims(dimensions) {}
@@ -215,6 +215,8 @@ class Tensor {
return 2;
case ElementType::kFloat32:
return sizeof(float);
case ElementType::kUInt8:
return 1;
}
}
int bytes() const { return shape_.num_elements() * element_size(); }
@@ -278,6 +280,11 @@ class Tensor {
#endif // MEDIAPIPE_OPENGL_ES_VERSION >= MEDIAPIPE_OPENGL_ES_30
};
int BhwcBatchFromShape(const Tensor::Shape& shape);
int BhwcHeightFromShape(const Tensor::Shape& shape);
int BhwcWidthFromShape(const Tensor::Shape& shape);
int BhwcDepthFromShape(const Tensor::Shape& shape);
} // namespace mediapipe
#endif // MEDIAPIPE_FRAMEWORK_FORMATS_TENSOR_H_
+25 -2
View File
@@ -16,14 +16,22 @@
#define MEDIAPIPE_FRAMEWORK_FORMATS_TENSOR_INTERNAL_H_
#include <cstdint>
#include <type_traits>
#include "mediapipe/framework/tool/type_util.h"
namespace mediapipe {
// Generates unique view id at compile-time using FILE and LINE.
#define TENSOR_UNIQUE_VIEW_TYPE_ID() \
static constexpr uint64_t kId = tensor_internal::FnvHash64( \
#define TENSOR_UNIQUE_VIEW_TYPE_ID() \
static inline uint64_t kId = tensor_internal::FnvHash64( \
__FILE__, tensor_internal::FnvHash64(TENSOR_INT_TO_STRING(__LINE__)))
// Generates unique view id at compile-time using FILE and LINE and Type of the
// template view's argument.
#define TENSOR_UNIQUE_VIEW_TYPE_ID_T(T) \
static inline uint64_t kId = tool::GetTypeHash<T>();
namespace tensor_internal {
#define TENSOR_INT_TO_STRING2(x) #x
@@ -36,6 +44,21 @@ constexpr uint64_t kFnvOffsetBias = 0xcbf29ce484222325;
constexpr uint64_t FnvHash64(const char* str, uint64_t hash = kFnvOffsetBias) {
return (str[0] == 0) ? hash : FnvHash64(str + 1, (hash ^ str[0]) * kFnvPrime);
}
template <typename... Ts>
struct TypeList {
static constexpr std::size_t size{sizeof...(Ts)};
};
template <typename, typename>
struct TypeInList {};
template <typename T, typename... Ts>
struct TypeInList<T, TypeList<T, Ts...>>
: std::integral_constant<std::size_t, 0> {};
template <typename T, typename TOther, typename... Ts>
struct TypeInList<T, TypeList<TOther, Ts...>>
: std::integral_constant<std::size_t,
1 + TypeInList<T, TypeList<Ts...>>::value> {};
} // namespace tensor_internal
} // namespace mediapipe
+6 -6
View File
@@ -355,8 +355,8 @@ TEST(GraphValidationTest, OptionalInputNotProvidedForSubgraphCalculator) {
output_stream: "OUTPUT:output_0"
node {
calculator: "OptionalSideInputTestCalculator"
input_side_packet: "SIDEINPUT:input_0" # std::string
output_stream: "OUTPUT:output_0" # std::string
input_side_packet: "SIDEINPUT:input_0" # string
output_stream: "OUTPUT:output_0" # string
}
)pb");
@@ -366,7 +366,7 @@ TEST(GraphValidationTest, OptionalInputNotProvidedForSubgraphCalculator) {
output_stream: "OUTPUT:foo_out"
node {
calculator: "PassThroughGraph"
output_stream: "OUTPUT:foo_out" # std::string
output_stream: "OUTPUT:foo_out" # string
}
)pb");
@@ -406,10 +406,10 @@ TEST(GraphValidationTest, MultipleOptionalInputsForSubgraph) {
output_stream: "OUTPUT:output_0"
node {
calculator: "OptionalSideInputTestCalculator"
input_side_packet: "SIDEINPUT:input_0" # std::string
input_side_packet: "SIDEINPUT:input_0" # string
input_stream: "SELECT:select"
input_stream: "ENABLE:enable"
output_stream: "OUTPUT:output_0" # std::string
output_stream: "OUTPUT:output_0" # string
}
)pb");
@@ -421,7 +421,7 @@ TEST(GraphValidationTest, MultipleOptionalInputsForSubgraph) {
node {
calculator: "PassThroughGraph"
input_stream: "SELECT:foo_select"
output_stream: "OUTPUT:foo_out" # std::string
output_stream: "OUTPUT:foo_out" # string
}
)pb");
+1 -2
View File
@@ -147,8 +147,7 @@ class InputStreamHandler {
void Close();
// Returns a std::string that concatenates the stream names of all managed
// streams.
// Returns a string that concatenates the stream names of all managed streams.
std::string DebugStreamNames() const;
// Keeps scheduling new invocations until 1) the node is not ready or 2) the
+2 -2
View File
@@ -51,7 +51,7 @@ class InputStreamShard : public InputStream {
return !packet_queue_.empty() ? packet_queue_.front() : empty_packet_;
}
// Returns a reference to the name std::string of the InputStreamManager.
// Returns a reference to the name string of the InputStreamManager.
const std::string& Name() const { return *name_; }
bool IsDone() const override { return is_done_; }
@@ -75,7 +75,7 @@ class InputStreamShard : public InputStream {
std::queue<Packet> packet_queue_;
Packet empty_packet_;
// Pointer to the name std::string of the InputStreamManager.
// Pointer to the name string of the InputStreamManager.
const std::string* name_;
bool is_done_;
+24 -3
View File
@@ -18,6 +18,7 @@
#include <atomic>
#include "absl/memory/memory.h"
#include "absl/synchronization/mutex.h"
namespace mediapipe {
@@ -33,9 +34,13 @@ class LifetimeTracker {
class Object {
public:
explicit Object(LifetimeTracker* tracker) : tracker_(tracker) {
absl::MutexLock lock(&tracker_->mutex_);
++tracker_->live_count_;
}
~Object() { --tracker_->live_count_; }
~Object() {
absl::MutexLock lock(&tracker_->mutex_);
--tracker_->live_count_;
}
private:
LifetimeTracker* const tracker_;
@@ -47,10 +52,26 @@ class LifetimeTracker {
}
// Returns the number of tracked objects currently alive.
int live_count() { return live_count_; }
int live_count() {
absl::MutexLock lock(&mutex_);
return live_count_;
}
// Waits for all instances of Object to be destroyed / live_count to reach
// zero. Returns true if this occurred within the timeout, false otherwise.
bool WaitForAllObjectsToDie(
absl::Duration timeout = absl::InfiniteDuration()) {
// Condition takes a function pointer. Prefixing the lambda with a +
// resolves it to a pointer.
absl::Condition check_count(
+[](int* value) { return *value == 0; }, &live_count_);
absl::MutexLock lock(&mutex_);
return mutex_.AwaitWithTimeout(check_count, timeout);
}
private:
std::atomic<int> live_count_ = ATOMIC_VAR_INIT(0);
absl::Mutex mutex_;
int live_count_ ABSL_GUARDED_BY(mutex_) = 0;
};
} // namespace mediapipe
+9 -2
View File
@@ -10,10 +10,17 @@ def mediapipe_cc_test(
size = None,
tags = [],
timeout = None,
args = [],
additional_deps = DEFAULT_ADDITIONAL_TEST_DEPS,
# ios_unit_test arguments
ios_minimum_os_version = "9.0",
# android_cc_test arguments
open_gl_driver = None,
emulator_mini_boot = True,
requires_full_emulation = True,
# wasm_web_test arguments
browsers = None,
**kwargs):
# Note: additional_deps are MediaPipe-specific test support deps added by default.
# They are provided as a default argument so they can be disabled if desired.
native.cc_library(
name = name + "_lib",
testonly = 1,
+76
View File
@@ -0,0 +1,76 @@
"""More utilities to help with selects."""
load("@bazel_skylib//lib:selects.bzl", "selects")
# From selects.bzl, but it's not public there.
def _config_setting_always_true(name, visibility):
"""Returns a config_setting with the given name that's always true.
This is achieved by constructing a two-entry OR chain where each
config_setting takes opposite values of a boolean flag.
"""
name_on = name + "_stamp_binary_on_check"
name_off = name + "_stamp_binary_off_check"
native.config_setting(
name = name_on,
values = {"stamp": "1"},
)
native.config_setting(
name = name_off,
values = {"stamp": "0"},
)
return selects.config_setting_group(
name = name,
visibility = visibility,
match_any = [
":" + name_on,
":" + name_off,
],
)
def _config_setting_always_false(name, visibility):
"""Returns a config_setting with the given name that's always false.
This is achieved by constructing a two-entry AND chain where each
config_setting takes opposite values of a boolean flag.
"""
name_on = name + "_stamp_binary_on_check"
name_off = name + "_stamp_binary_off_check"
native.config_setting(
name = name_on,
values = {"stamp": "1"},
)
native.config_setting(
name = name_off,
values = {"stamp": "0"},
)
return selects.config_setting_group(
name = name,
visibility = visibility,
match_all = [
":" + name_on,
":" + name_off,
],
)
def _config_setting_negation(name, negate, visibility = None):
_config_setting_always_true(
name = name + "_true",
visibility = visibility,
)
_config_setting_always_false(
name = name + "_false",
visibility = visibility,
)
native.alias(
name = name,
actual = select({
"//conditions:default": ":%s_true" % name,
negate: ":%s_false" % name,
}),
visibility = visibility,
)
more_selects = struct(
config_setting_negation = _config_setting_negation,
)
+2 -1
View File
@@ -113,7 +113,8 @@ absl::Status Packet::ValidateAsType(const tool::TypeInfo& type_info) const {
MediaPipeTypeStringOrDemangled(type_info),
", but received an empty Packet."));
}
bool holder_is_right_type = holder_->GetTypeId() == type_info.hash_code();
bool holder_is_right_type =
holder_->GetTypeInfo().hash_code() == type_info.hash_code();
if (ABSL_PREDICT_FALSE(!holder_is_right_type)) {
return absl::InvalidArgumentError(absl::StrCat(
"The Packet stores \"", holder_->DebugTypeName(), "\", but \"",
+16 -11
View File
@@ -189,7 +189,11 @@ class Packet {
// Get the type id for the underlying type stored in the Packet.
// Crashes if IsEmpty() == true.
size_t GetTypeId() const;
size_t GetTypeId() const { return GetTypeInfo().hash_code(); }
// Get the type info for the underlying type stored in the Packet.
// Crashes if IsEmpty() == true.
const tool::TypeInfo& GetTypeInfo() const;
// Returns the timestamp.
class Timestamp Timestamp() const;
@@ -201,9 +205,9 @@ class Packet {
// Returns the type name. If the packet is empty or the type is not
// registered (with MEDIAPIPE_REGISTER_TYPE or companion macros) then
// the empty std::string is returned.
// the empty string is returned.
std::string RegisteredTypeName() const;
// Returns a std::string with the best guess at the type name.
// Returns a string with the best guess at the type name.
std::string DebugTypeName() const;
private:
@@ -220,6 +224,7 @@ class Packet {
friend std::shared_ptr<packet_internal::HolderBase>
packet_internal::GetHolderShared(Packet&& packet);
friend class PacketType;
absl::Status ValidateAsType(const tool::TypeInfo& type_info) const;
std::shared_ptr<packet_internal::HolderBase> holder_;
@@ -364,15 +369,15 @@ class HolderBase {
virtual ~HolderBase();
template <typename T>
bool PayloadIsOfType() const {
return GetTypeId() == tool::GetTypeHash<T>();
return GetTypeInfo().hash_code() == tool::GetTypeHash<T>();
}
// Returns a printable std::string identifying the type stored in the holder.
// Returns a printable string identifying the type stored in the holder.
virtual const std::string DebugTypeName() const = 0;
// Returns the registered type name if it's available, otherwise the
// empty std::string.
// empty string.
virtual const std::string RegisteredTypeName() const = 0;
// Get the type id of the underlying data type.
virtual size_t GetTypeId() const = 0;
virtual const tool::TypeInfo& GetTypeInfo() const = 0;
// Downcasts this to Holder<T>. Returns nullptr if deserialization
// failed or if the requested type is not what is stored.
template <typename T>
@@ -440,7 +445,7 @@ ConvertToVectorOfProtoMessageLitePtrs(const T* data,
}
// This registry is used to create Holders of the right concrete C++ type given
// a proto type std::string (which is used as the registration key).
// a proto type string (which is used as the registration key).
class MessageHolderRegistry
: public GlobalFactoryRegistry<std::unique_ptr<HolderBase>> {};
@@ -505,7 +510,7 @@ class Holder : public HolderBase {
HolderSupport<T>::EnsureStaticInit();
return *ptr_;
}
size_t GetTypeId() const final { return tool::GetTypeHash<T>(); }
const tool::TypeInfo& GetTypeInfo() const final { return tool::TypeId<T>(); }
// Releases the underlying data pointer and transfers the ownership to a
// unique pointer.
// This method is dangerous and is only used by Packet::Consume() if the
@@ -741,9 +746,9 @@ inline Packet& Packet::operator=(Packet&& packet) {
inline bool Packet::IsEmpty() const { return holder_ == nullptr; }
inline size_t Packet::GetTypeId() const {
inline const tool::TypeInfo& Packet::GetTypeInfo() const {
CHECK(holder_);
return holder_->GetTypeId();
return holder_->GetTypeInfo();
}
template <typename T>
+162 -70
View File
@@ -19,57 +19,55 @@
#include <unordered_set>
#include <utility>
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "absl/types/span.h"
#include "absl/types/variant.h"
#include "mediapipe/framework/port/canonical_errors.h"
#include "mediapipe/framework/port/logging.h"
#include "mediapipe/framework/port/map_util.h"
#include "mediapipe/framework/port/source_location.h"
#include "mediapipe/framework/port/status_builder.h"
#include "mediapipe/framework/tool/status_util.h"
#include "mediapipe/framework/tool/type_util.h"
#include "mediapipe/framework/tool/validate_name.h"
#include "mediapipe/framework/type_map.h"
namespace mediapipe {
PacketType::PacketType()
: initialized_(false),
no_packets_allowed_(true),
validate_method_(nullptr),
type_name_("[Undefined Type]"),
same_as_(nullptr) {}
absl::Status PacketType::AcceptAny(const TypeSpec& type) {
return absl::OkStatus();
}
absl::Status PacketType::AcceptNone(const TypeSpec& type) {
auto* special = absl::get_if<SpecialType>(&type);
if (special &&
(special->accept_fn_ == AcceptNone || special->accept_fn_ == AcceptAny))
return absl::OkStatus();
return mediapipe::InvalidArgumentErrorBuilder(MEDIAPIPE_LOC)
<< "No packets are allowed for type: [No Type]";
}
PacketType& PacketType::SetAny() {
no_packets_allowed_ = false;
validate_method_ = nullptr;
same_as_ = nullptr;
type_name_ = "[Any Type]";
initialized_ = true;
type_spec_ = SpecialType{"[Any Type]", &AcceptAny};
return *this;
}
PacketType& PacketType::SetNone() {
no_packets_allowed_ = true;
validate_method_ = nullptr;
same_as_ = nullptr;
type_name_ = "[No Type]";
initialized_ = true;
type_spec_ = SpecialType{"[No Type]", &AcceptNone};
return *this;
}
PacketType& PacketType::SetSameAs(const PacketType* type) {
// TODO Union sets together when SetSameAs is called multiple times.
no_packets_allowed_ = false;
validate_method_ = nullptr;
same_as_ = type->GetSameAs();
type_name_ = "";
if (same_as_ == this) {
auto same_as = type->GetSameAs();
if (same_as == this) {
// We're the root of the union-find tree. There's a cycle, which
// means we might as well be an "Any" type.
same_as_ = nullptr;
return SetAny();
}
initialized_ = true;
type_spec_ = SameAs{same_as};
return *this;
}
@@ -78,10 +76,19 @@ PacketType& PacketType::Optional() {
return *this;
}
bool PacketType::IsInitialized() const { return initialized_; }
bool PacketType::IsInitialized() const {
return !absl::holds_alternative<absl::monostate>(type_spec_);
}
const PacketType* PacketType::SameAsPtr() const {
auto* same_as = absl::get_if<SameAs>(&type_spec_);
if (same_as) return same_as->other;
return nullptr;
}
PacketType* PacketType::GetSameAs() {
if (!same_as_) {
auto* same_as = SameAsPtr();
if (!same_as) {
return this;
}
// Don't optimize the union-find algorithm, since updating the pointer
@@ -91,89 +98,174 @@ PacketType* PacketType::GetSameAs() {
// make the current set point to the root of the other tree.
// TODO Remove const_cast by making SetSameAs take a non-const
// PacketType*.
return const_cast<PacketType*>(same_as_->GetSameAs());
return const_cast<PacketType*>(same_as->GetSameAs());
}
const PacketType* PacketType::GetSameAs() const {
if (!same_as_) {
auto* same_as = SameAsPtr();
if (!same_as) {
return this;
}
// See comments in non-const variant.
return same_as_->GetSameAs();
return same_as->GetSameAs();
}
bool PacketType::IsAny() const {
return !no_packets_allowed_ && validate_method_ == nullptr &&
same_as_ == nullptr;
auto* special = absl::get_if<SpecialType>(&type_spec_);
return special && special->accept_fn_ == AcceptAny;
}
bool PacketType::IsNone() const { return no_packets_allowed_; }
bool PacketType::IsNone() const {
auto* special = absl::get_if<SpecialType>(&type_spec_);
// The tests currently require that an uninitialized PacketType return true
// for IsNone. TODO: change it?
return !IsInitialized() || (special && special->accept_fn_ == AcceptNone);
}
bool PacketType::IsOneOf() const {
return absl::holds_alternative<MultiType>(type_spec_);
}
bool PacketType::IsExactType() const {
return absl::holds_alternative<const tool::TypeInfo*>(type_spec_);
}
const std::string* PacketType::RegisteredTypeName() const {
if (same_as_) {
return GetSameAs()->RegisteredTypeName();
}
return registered_type_name_ptr_;
if (auto* same_as = SameAsPtr()) return same_as->RegisteredTypeName();
if (auto* type_info = absl::get_if<const tool::TypeInfo*>(&type_spec_))
return MediaPipeTypeStringFromTypeId((**type_info).hash_code());
if (auto* multi_type = absl::get_if<MultiType>(&type_spec_))
return multi_type->registered_type_name;
return nullptr;
}
const std::string PacketType::DebugTypeName() const {
if (same_as_) {
namespace internal {
struct TypeInfoFormatter {
void operator()(std::string* out, const tool::TypeInfo& t) const {
absl::StrAppend(out, MediaPipeTypeStringOrDemangled(t));
}
};
template <class Formatter>
class QuoteFormatter {
public:
explicit QuoteFormatter(Formatter&& f) : f_(std::forward<Formatter>(f)) {}
template <typename T>
void operator()(std::string* out, const T& t) const {
absl::StrAppend(out, "\"");
f_(out, t);
absl::StrAppend(out, "\"");
}
private:
Formatter f_;
};
template <class Formatter>
explicit QuoteFormatter(Formatter f) -> QuoteFormatter<Formatter>;
} // namespace internal
std::string PacketType::TypeNameForOneOf(TypeInfoSpan types) {
return absl::StrCat(
"OneOf<",
absl::StrJoin(types, ", ",
absl::DereferenceFormatter(internal::TypeInfoFormatter())),
">");
}
std::string PacketType::DebugTypeName() const {
if (auto* same_as = absl::get_if<SameAs>(&type_spec_)) {
// Construct a name based on the current chain of same_as_ links
// (which may change when the framework expands out Any-type).
return absl::StrCat("[Same Type As ", GetSameAs()->DebugTypeName(), "]");
return absl::StrCat("[Same Type As ",
same_as->other->GetSameAs()->DebugTypeName(), "]");
}
return type_name_;
if (auto* special = absl::get_if<SpecialType>(&type_spec_)) {
return special->name_;
}
if (auto* type_info = absl::get_if<const tool::TypeInfo*>(&type_spec_)) {
return MediaPipeTypeStringOrDemangled(**type_info);
}
if (auto* multi_type = absl::get_if<MultiType>(&type_spec_)) {
return TypeNameForOneOf(multi_type->types);
}
return "[Undefined Type]";
}
static bool HaveCommonType(absl::Span<const tool::TypeInfo* const> types1,
absl::Span<const tool::TypeInfo* const> types2) {
for (const auto& first : types1) {
for (const auto& second : types2) {
if (first->hash_code() == second->hash_code()) {
return true;
}
}
}
return false;
}
absl::Status PacketType::Validate(const Packet& packet) const {
if (!initialized_) {
if (!IsInitialized()) {
return absl::InvalidArgumentError(
"Uninitialized PacketType was used for validation.");
}
if (same_as_) {
if (SameAsPtr()) {
// Cycles are impossible at this stage due to being checked for
// in SetSameAs().
return GetSameAs()->Validate(packet);
}
if (no_packets_allowed_) {
return mediapipe::InvalidArgumentErrorBuilder(MEDIAPIPE_LOC)
<< "No packets are allowed for type: " << type_name_;
if (auto* type_info = absl::get_if<const tool::TypeInfo*>(&type_spec_)) {
return packet.ValidateAsType(**type_info);
}
if (validate_method_ != nullptr) {
return (packet.*validate_method_)();
}
// The PacketType is the Any Type.
if (packet.IsEmpty()) {
return mediapipe::InvalidArgumentErrorBuilder(MEDIAPIPE_LOC)
<< "Empty packets are not allowed for type: " << type_name_;
<< "Empty packets are not allowed for type: " << DebugTypeName();
}
if (auto* multi_type = absl::get_if<MultiType>(&type_spec_)) {
auto* packet_type = &packet.GetTypeInfo();
if (HaveCommonType(multi_type->types, absl::MakeSpan(&packet_type, 1))) {
return absl::OkStatus();
} else {
return absl::InvalidArgumentError(absl::StrCat(
"The Packet stores \"", packet.DebugTypeName(), "\", but one of ",
absl::StrJoin(multi_type->types, ", ",
absl::DereferenceFormatter(internal::QuoteFormatter(
internal::TypeInfoFormatter()))),
" was requested."));
}
}
if (auto* special = absl::get_if<SpecialType>(&type_spec_)) {
return special->accept_fn_(&packet.GetTypeInfo());
}
return absl::OkStatus();
}
PacketType::TypeInfoSpan PacketType::GetTypeSpan(const TypeSpec& type_spec) {
if (auto* type_info = absl::get_if<const tool::TypeInfo*>(&type_spec))
return absl::MakeSpan(type_info, 1);
if (auto* multi_type = absl::get_if<MultiType>(&type_spec))
return multi_type->types;
return {};
}
bool PacketType::IsConsistentWith(const PacketType& other) const {
const PacketType* type1 = GetSameAs();
const PacketType* type2 = other.GetSameAs();
if (type1->validate_method_ == nullptr ||
type2->validate_method_ == nullptr) {
// type1 or type2 either accepts anything or nothing.
if (type1->validate_method_ == nullptr && !type1->no_packets_allowed_) {
// type1 accepts anything.
return true;
}
if (type2->validate_method_ == nullptr && !type2->no_packets_allowed_) {
// type2 accepts anything.
return true;
}
if (type1->no_packets_allowed_ && type2->no_packets_allowed_) {
// type1 and type2 both accept nothing.
return true;
}
// The only special case left is that only one of "type1" or "type2"
// accepts nothing, which means there is no match.
return false;
TypeInfoSpan types1 = GetTypeSpan(type1->type_spec_);
TypeInfoSpan types2 = GetTypeSpan(type2->type_spec_);
if (!types1.empty() && !types2.empty()) {
return HaveCommonType(types1, types2);
}
return type1->validate_method_ == type2->validate_method_;
if (auto* special1 = absl::get_if<SpecialType>(&type1->type_spec_)) {
return special1->accept_fn_(type2->type_spec_).ok();
}
if (auto* special2 = absl::get_if<SpecialType>(&type2->type_spec_)) {
return special2->accept_fn_(type1->type_spec_).ok();
}
return false;
}
absl::Status ValidatePacketTypeSet(const PacketTypeSet& packet_type_set) {
+53 -25
View File
@@ -23,12 +23,16 @@
#include <vector>
#include "absl/base/macros.h"
#include "absl/status/status.h"
#include "absl/strings/str_split.h"
#include "absl/strings/string_view.h"
#include "absl/types/span.h"
#include "mediapipe/framework/collection.h"
#include "mediapipe/framework/deps/no_destructor.h"
#include "mediapipe/framework/packet.h"
#include "mediapipe/framework/packet_set.h"
#include "mediapipe/framework/port/status.h"
#include "mediapipe/framework/tool/type_util.h"
#include "mediapipe/framework/tool/validate_name.h"
#include "mediapipe/framework/type_map.h"
@@ -41,7 +45,7 @@ namespace mediapipe {
class PacketType {
public:
// Creates an uninitialized PacketType.
PacketType();
PacketType() = default;
// PacketType can be passed by value.
PacketType(const PacketType&) = default;
@@ -63,6 +67,9 @@ class PacketType {
// Specifically, using SetAny() still means that the stream has a type
// but this particular calculator just doesn't care what it is.
PacketType& SetAny();
// Sets the packet type to accept any of the provided types.
template <typename... T>
PacketType& SetOneOf();
// Sets the packet type to not accept any packets.
PacketType& SetNone();
// Sets the PacketType to be the same as type. This actually stores
@@ -80,6 +87,11 @@ class PacketType {
bool IsAny() const;
// Returns true if this PacketType allows nothing.
bool IsNone() const;
// Returns true if this PacketType allows a set of types.
bool IsOneOf() const;
// Returns true if this PacketType allows one specific type.
bool IsExactType() const;
// Returns true if this port has been marked as optional.
bool IsOptional() const { return optional_; }
// Returns true iff this and other are consistent, meaning they do
@@ -101,26 +113,38 @@ class PacketType {
const std::string* RegisteredTypeName() const;
// Returns the type name. Do not use this for validation, use
// Validate() instead.
const std::string DebugTypeName() const;
std::string DebugTypeName() const;
private:
// Typedef for the ValidateAsType() method in Packet that is used for
// type validation and identification.
typedef absl::Status (Packet::*ValidateMethodType)() const;
struct SameAs {
// This PacketType is the same as other.
// We don't do union-find optimizations in order to avoid a mutex.
const PacketType* other;
};
using TypeInfoSpan = absl::Span<const tool::TypeInfo* const>;
struct MultiType {
TypeInfoSpan types;
// TODO: refactor RegisteredTypeName, remove.
const std::string* registered_type_name;
};
struct SpecialType;
using TypeSpec = absl::variant<absl::monostate, const tool::TypeInfo*,
MultiType, SameAs, SpecialType>;
typedef absl::Status (*AcceptsTypeFn)(const TypeSpec& type);
struct SpecialType {
std::string name_;
AcceptsTypeFn accept_fn_;
};
static absl::Status AcceptAny(const TypeSpec& type);
static absl::Status AcceptNone(const TypeSpec& type);
const PacketType* SameAsPtr() const;
static TypeInfoSpan GetTypeSpan(const TypeSpec& type_spec);
static std::string TypeNameForOneOf(TypeInfoSpan types);
TypeSpec type_spec_;
// Records whether the packet type was set in any way.
bool initialized_;
// Don't allow any packets through.
bool no_packets_allowed_;
// Pointer to Packet::ValidateAsType<T>.
ValidateMethodType validate_method_;
// Type name as std::string.
std::string type_name_;
// The Registered type name or nullptr if the type isn't registered.
const std::string* registered_type_name_ptr_ = nullptr;
// If this is non-null then this PacketType is the same as same_as_.
// We don't do union-find optimizations in order to avoid a mutex.
const PacketType* same_as_;
// Whether the corresponding port is optional.
bool optional_ = false;
};
@@ -164,7 +188,7 @@ class PacketTypeSetErrorHandler {
for (const auto& entry : missing_->entries) {
// Optional entries that were missing are not considered errors.
if (!entry.second.IsOptional()) {
// Split them to keep the error std::string unchanged.
// Split them to keep the error string unchanged.
std::pair<std::string, std::string> tag_idx =
absl::StrSplit(entry.first, ':');
missing_->errors.push_back(absl::StrCat("Failed to get tag \"",
@@ -235,12 +259,16 @@ absl::Status ValidatePacketTypeSet(const PacketTypeSet& packet_type_set);
template <typename T>
PacketType& PacketType::Set() {
initialized_ = true;
no_packets_allowed_ = false;
validate_method_ = &Packet::ValidateAsType<T>;
type_name_ = MediaPipeTypeStringOrDemangled<T>();
registered_type_name_ptr_ = MediaPipeTypeString<T>();
same_as_ = nullptr;
type_spec_ = &tool::TypeId<T>();
return *this;
}
template <typename... T>
PacketType& PacketType::SetOneOf() {
static const NoDestructor<std::vector<const tool::TypeInfo*>> types{
{&tool::TypeId<T>()...}};
static const NoDestructor<std::string> name{TypeNameForOneOf(*types)};
type_spec_ = MultiType{*types, &*name};
return *this;
}
+6 -1
View File
@@ -60,18 +60,23 @@
#define MEDIAPIPE_OPENGL_ES_30 300
#define MEDIAPIPE_OPENGL_ES_31 310
// NOTE: MEDIAPIPE_OPENGL_ES_VERSION macro represents the maximum OpenGL ES
// version to build for. Runtime availability is _not_ guaranteed; in
// particular, uses of OpenGL ES 3.1 should be guarded by a runtime check.
// TODO: identify and fix code where macro is used incorrectly.
#if MEDIAPIPE_DISABLE_GPU
#define MEDIAPIPE_OPENGL_ES_VERSION 0
#define MEDIAPIPE_METAL_ENABLED 0
#else
#if defined(MEDIAPIPE_ANDROID)
#if defined(MEDIAPIPE_DISABLE_GL_COMPUTE)
#define MEDIAPIPE_OPENGL_ES_VERSION MEDIAPIPE_OPENGL_ES_20
#define MEDIAPIPE_OPENGL_ES_VERSION MEDIAPIPE_OPENGL_ES_30
#else
#define MEDIAPIPE_OPENGL_ES_VERSION MEDIAPIPE_OPENGL_ES_31
#endif
#define MEDIAPIPE_METAL_ENABLED 0
#elif defined(MEDIAPIPE_IOS)
// TODO: use MEDIAPIPE_OPENGL_ES_30 for iOS as max version.
#define MEDIAPIPE_OPENGL_ES_VERSION MEDIAPIPE_OPENGL_ES_20
#define MEDIAPIPE_METAL_ENABLED 1
#elif defined(MEDIAPIPE_OSX)
+28 -16
View File
@@ -89,9 +89,11 @@ cc_library(
cc_library(
name = "graph_profiler_real",
srcs = [
"gl_context_profiler.cc",
"graph_profiler.cc",
],
] + select({
"//conditions:default": ["gl_context_profiler.cc"],
"//mediapipe/gpu:disable_gpu": [],
}),
hdrs = [
"graph_profiler.h",
],
@@ -100,31 +102,37 @@ cc_library(
],
visibility = ["//visibility:private"],
deps = [
":graph_tracer",
":profiler_resource_util",
":sharded_map",
":graph_tracer",
":trace_buffer",
":sharded_map",
"//mediapipe/framework:calculator_cc_proto",
"//mediapipe/framework:calculator_context",
"//mediapipe/framework:calculator_profile_cc_proto",
"//mediapipe/framework/port:integral_types",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/types:optional",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/synchronization",
"@com_google_absl//absl/time",
"//mediapipe/framework/deps:clock",
"//mediapipe/framework:calculator_context",
"//mediapipe/framework:executor",
"//mediapipe/framework:validated_graph_config",
"//mediapipe/framework/deps:clock",
"//mediapipe/framework/port:advanced_proto_lite",
"//mediapipe/framework/port:integral_types",
"//mediapipe/framework/tool:tag_map",
"//mediapipe/framework/tool:validate_name",
"//mediapipe/framework/port:logging",
"//mediapipe/framework/port:re2",
"//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status",
"//mediapipe/framework/port:advanced_proto_lite",
"//mediapipe/framework/tool:name_util",
"//mediapipe/framework/tool:tag_map",
"//mediapipe/framework/tool:validate_name",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/synchronization",
"@com_google_absl//absl/time",
"@com_google_absl//absl/types:optional",
],
] + select({
"//conditions:default": [],
}) + select({
"//conditions:default": [
],
"//mediapipe/gpu:disable_gpu": [],
}),
)
cc_library(
@@ -270,6 +278,7 @@ cc_library(
name = "profiler_resource_util",
srcs = ["profiler_resource_util_common.cc"] + select({
"//conditions:default": ["profiler_resource_util.cc"],
"//mediapipe/framework:android_no_jni": ["profiler_resource_util_android_hal.cc"],
"//mediapipe:android": ["profiler_resource_util_android.cc"],
"//mediapipe:ios": ["profiler_resource_util_ios.cc"],
}),
@@ -295,6 +304,9 @@ cc_library(
"//conditions:default": [
"//mediapipe/framework/port:file_helpers",
],
"//mediapipe/framework:android_no_jni": [
"//mediapipe/framework/port:file_helpers",
],
"//mediapipe:android": [
"//mediapipe/java/com/google/mediapipe/framework/jni:jni_util",
"//mediapipe/framework/port:file_helpers",
+17 -7
View File
@@ -600,12 +600,17 @@ void AssignNodeNames(GraphProfile* profile) {
if (graph_trace) {
graph_trace->clear_calculator_name();
}
std::vector<std::string> canonical_names;
canonical_names.reserve(graph_config->node().size());
for (int i = 0; i < graph_config->node().size(); ++i) {
std::string node_name = CanonicalNodeName(*graph_config, i);
graph_config->mutable_node(i)->set_name(node_name);
if (graph_trace) {
graph_trace->add_calculator_name(node_name);
}
canonical_names.push_back(CanonicalNodeName(*graph_config, i));
}
for (int i = 0; i < graph_config->node().size(); ++i) {
graph_config->mutable_node(i)->set_name(canonical_names[i]);
}
if (graph_trace) {
graph_trace->mutable_calculator_name()->Assign(canonical_names.begin(),
canonical_names.end());
}
}
@@ -646,7 +651,8 @@ absl::StatusOr<std::string> GraphProfiler::GetTraceLogPath() {
}
}
absl::Status GraphProfiler::CaptureProfile(GraphProfile* result) {
absl::Status GraphProfiler::CaptureProfile(
GraphProfile* result, PopulateGraphConfig populate_config) {
// Record the GraphTrace events since the previous WriteProfile.
// The end_time is chosen to be trace_log_margin_usec in the past,
// providing time for events to be appended to the TraceBuffer.
@@ -674,6 +680,10 @@ absl::Status GraphProfiler::CaptureProfile(GraphProfile* result) {
}
this->Reset();
CleanCalculatorProfiles(result);
if (populate_config == PopulateGraphConfig::kFull) {
*result->mutable_config() = validated_graph_->Config();
AssignNodeNames(result);
}
return status;
}
@@ -686,7 +696,7 @@ absl::Status GraphProfiler::WriteProfile() {
int log_interval_count = GetLogIntervalCount(profiler_config_);
int log_file_count = GetLogFileCount(profiler_config_);
GraphProfile profile;
MP_RETURN_IF_ERROR(CaptureProfile(&profile));
MP_RETURN_IF_ERROR(CaptureProfile(&profile, PopulateGraphConfig::kNo));
// If there are no trace events, skip log writing.
const GraphTrace& trace = *profile.graph_trace().rbegin();
+92 -2
View File
@@ -71,6 +71,9 @@ struct PacketInfo {
// For testing
class GraphProfilerTestPeer;
// GraphProfiler::CaptureProfile option, see the method for details.
enum class PopulateGraphConfig { kNo, kFull };
// GraphProfiler keeps track of the following in microseconds based on the
// profiler clock, for each calculator
// - Open(), Process(), and Close() runtime.
@@ -145,7 +148,14 @@ class GraphProfiler : public std::enable_shared_from_this<ProfilingContext> {
// Records recent profiling and tracing data. Includes events since the
// previous call to CaptureProfile.
absl::Status CaptureProfile(GraphProfile* result);
//
// If `populate_config` is `kFull`, `config` field of the resulting profile
// will contain canonicalized config of the profiled graph, and
// `graph_trace.calculator_name` will contain node names referring to that
// config. Both fields are left empty if the option is set to `kNo`.
absl::Status CaptureProfile(
GraphProfile* result,
PopulateGraphConfig populate_config = PopulateGraphConfig::kNo);
// Writes recent profiling and tracing data to a file specified in the
// ProfilerConfig. Includes events since the previous call to WriteProfile.
@@ -356,6 +366,85 @@ class ProfilingContext : public GraphProfiler {
// For now, OSS always uses GlContextProfilerStub.
// TODO: Switch to GlContextProfiler when GlContext is moved to OSS.
#define MEDIAPIPE_DISABLE_GPU_PROFILER 1
// GlContextProfiler keeps track of all timestamp queries within a specific
// GlContext object. When created, the GlContextProfiler must be initialized
// before marking timestamps. Finally, when GlContext is no longer interested
// in marking timestamps or is about to be destroyed, Finish() must be called
// to complete all pending time queries and detach the timer from the GlContext.
// Note that the GlContextProfiler must be created and initialized within a
// valid GlContext object.
#if !MEDIAPIPE_DISABLE_GPU_PROFILER
class GlContextProfiler {
public:
explicit GlContextProfiler(
std::shared_ptr<ProfilingContext> profiling_context)
: profiling_context_(profiling_context) {}
// Not copyable or movable.
GlContextProfiler(const GlContextProfiler&) = delete;
GlContextProfiler& operator=(const GlContextProfiler&) = delete;
// Add a GlTimingInfo object to the collection of pending timestamp queries
// associated with a specific graph node_id, packet input_timestamp and mark
// if it is a start or stop event. When a stop event is marked, this function
// blocks on the corresponding start event to complete.
void MarkTimestamp(int node_id, Timestamp input_timestamp, bool is_finish);
// Complete all pending timing queries and detach the timer from the
// GlContext.
void LogAllTimestamps();
private:
// Store GlTimeQuery and the corresponding TraceEvent object that should be
// populated when the query completes together.
struct GlTimingInfo {
GlTimeQuery time_query;
TraceEvent trace_event;
};
// Setup the timer for marking GPU timestamps. If successful in setup, return
// true otherwise return false to indicate that timing measurment is not
// supported.
bool Initialize();
absl::Time TimeNow();
// Calibrate the GPU timer w.r.t. the CPU clock. If calibration is fails,
// timing_measurement_supported_ is set to false.
void CalibrateTimer(bool recalibrate);
// Log a TraceEvent object to represent if the GPU calibration period has
// started or just ended.
void LogCalibrationEvent(bool started, absl::Time time);
// Log TraceEvent objects for completed time queries. If the parameter wait is
// set to true, wait for all time queries to complete before returning.
void RetireReadyGlTimings(bool wait = false);
// Get the TraceEvent object containing the timestamp recorded by the GPU if
// the provided query was fulfilled. If it is still pending and wait is false,
// return absl::nullopt.
absl::optional<TraceEvent> GetTimeFromQuery(
std::unique_ptr<GlTimingInfo>& query, bool wait);
std::shared_ptr<ProfilingContext> profiling_context_;
GlSimpleTimer gl_timer_;
bool checked_timing_supported_ = false;
bool timing_measurement_supported_ = false;
std::deque<std::unique_ptr<GlTimingInfo>> pending_gl_times_;
std::unique_ptr<GlTimingInfo> gl_start_query_;
};
// The API class used to access the preferred GlContext profiler, such as
// GlContextProfiler or GlContextProfilerStub. GlProfilingHelper is defined as
// a class rather than a typedef in order to support clients that refer
// to it only as a forward declaration.
class GlProfilingHelper : public GlContextProfiler {
using GlContextProfiler::GlContextProfiler;
};
#else // MEDIAPIPE_DISABLE_GPU_PROFILER
class GlContextProfilerStub {
public:
explicit GlContextProfilerStub(
@@ -370,7 +459,8 @@ class GlContextProfilerStub {
class GlProfilingHelper : public GlContextProfilerStub {
using GlContextProfilerStub::GlContextProfilerStub;
};
#endif // !MEDIAPIPE_DISABLE_GPU_PROFILER
#undef MEDIAPIPE_DISABLE_GPU_PROFILER
} // namespace mediapipe
#endif // MEDIAPIPE_FRAMEWORK_PROFILER_GRAPH_PROFILER_H_
@@ -74,6 +74,9 @@ class TraceEvent {
inline TraceEvent& set_event_data(int64 data) { return *this; }
};
// GraphProfiler::CaptureProfile option, see the method for details.
enum class PopulateGraphConfig { kNo, kFull };
// Empty implementation of ProfilingContext to be used in place of the
// GraphProfiler when the main implementation is disabled.
class GraphProfilerStub {
@@ -85,6 +88,11 @@ class GraphProfilerStub {
std::vector<CalculatorProfile>*) const {
return absl::OkStatus();
}
absl::Status CaptureProfile(
GraphProfile* result,
PopulateGraphConfig populate_config = PopulateGraphConfig::kNo) {
return absl::OkStatus();
}
inline void Pause() {}
inline void Resume() {}
inline void Reset() {}
@@ -1267,5 +1267,49 @@ TEST(GraphProfilerTest, CalculatorProfileFilter) {
EXPECT_EQ(GetCalculatorNames(config), expected_names);
}
TEST(GraphProfilerTest, CaptureProfilePopulateConfig) {
CalculatorGraphConfig config;
QCHECK(proto2::TextFormat::ParseFromString(R"(
profiler_config {
enable_profiler: true
trace_enabled: true
}
input_stream: "input_stream"
node {
calculator: "DummyTestCalculator"
input_stream: "input_stream"
}
node {
calculator: "DummyTestCalculator"
input_stream: "input_stream"
}
)",
&config));
CalculatorGraph graph;
MP_ASSERT_OK(graph.Initialize(config));
GraphProfile profile;
MP_ASSERT_OK(
graph.profiler()->CaptureProfile(&profile, PopulateGraphConfig::kFull));
EXPECT_THAT(profile.config(), Partially(EqualsProto(R"pb(
input_stream: "input_stream"
node {
name: "DummyTestCalculator_1"
calculator: "DummyTestCalculator"
input_stream: "input_stream"
}
node {
name: "DummyTestCalculator_2"
calculator: "DummyTestCalculator"
input_stream: "input_stream"
}
)pb")));
EXPECT_THAT(profile.graph_trace(),
ElementsAre(Partially(EqualsProto(
R"pb(
calculator_name: "DummyTestCalculator_1"
calculator_name: "DummyTestCalculator_2"
)pb"))));
}
} // namespace
} // namespace mediapipe
@@ -1053,8 +1053,8 @@ TEST_F(GraphTracerE2ETest, DemuxGraphLogFiles) {
calculator_name: "LambdaCalculator_1"
calculator_name: "FlowLimiterCalculator"
calculator_name: "RoundRobinDemuxCalculator"
calculator_name: "LambdaCalculator_1"
calculator_name: "LambdaCalculator"
calculator_name: "LambdaCalculator_2"
calculator_name: "LambdaCalculator_3"
calculator_name: "ImmediateMuxCalculator"
stream_name: ""
stream_name: "input_packets_0"
@@ -1198,14 +1198,14 @@ TEST_F(GraphTracerE2ETest, DemuxGraphLogFiles) {
output_stream: "OUTPUT:1:input_1"
}
node {
name: "LambdaCalculator_1"
name: "LambdaCalculator_2"
calculator: "LambdaCalculator"
input_stream: "input_0"
output_stream: "output_0"
input_side_packet: "callback_0"
}
node {
name: "LambdaCalculator"
name: "LambdaCalculator_3"
calculator: "LambdaCalculator"
input_stream: "input_1"
output_stream: "output_1"
@@ -0,0 +1,9 @@
#include "mediapipe/framework/port/statusor.h"
namespace mediapipe {
StatusOr<std::string> GetDefaultTraceLogDirectory() {
return "/data/local/tmp";
}
} // namespace mediapipe
@@ -12,9 +12,9 @@
// 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.
// This program takes one input file and encodes its contents as a C++ string,
// which can be included in a C++ source file. It is similar to filewrapper
// (and borrows some of its code), but simpler.
#include <algorithm>
#include <fstream>
@@ -215,7 +215,7 @@ void CompleteCalculatorData(
}
void Reporter::Accumulate(const mediapipe::GraphProfile& profile) {
// Cache nodeID to its std::string name.
// Cache nodeID to its string name.
NameLookup name_lookup;
CacheNodeNameLookup(profile, &name_lookup);
@@ -363,8 +363,8 @@ class ReportImpl : public Report {
// Values for each calculator, corresponding to the label in headers().
std::vector<std::vector<std::string>> lines_impl;
// The longest std::string of any value in a given column (including the
// header for that column). Used for formatting the output.
// The longest string of any value in a given column (including the header
// for that column). Used for formatting the output.
std::vector<size_t> char_counts_impl;
bool compact_flag = false;
@@ -377,7 +377,7 @@ void ReportImpl::Print(std::ostream& output) {
// fill space up to char_counts[column] + 1. The strings in the output
// are mutable to support padding, hence no const in the for loops.
int column_number = 0;
// Make a copy of the column std::string because we might be adding spaces.
// Make a copy of the column string because we might be adding spaces.
for (auto column : headers_impl) {
int padding_needed = char_counts_impl[column_number] + 1 - column.length();
if (compact_flag) {
@@ -90,11 +90,11 @@ void BasicTraceEventTypes(TraceEventRegistry* result) {
}
}
// A map defining int32 identifiers for std::string object pointers.
// Lookup is fast when the same std::string object is used frequently.
// A map defining int32 identifiers for string object pointers.
// Lookup is fast when the same string object is used frequently.
class StringIdMap {
public:
// Returns the int32 identifier for a std::string object pointer.
// Returns the int32 identifier for a string object pointer.
int32 operator[](const std::string* id) {
if (id == nullptr) {
return 0;
@@ -47,8 +47,8 @@ std::tuple<std::string, Timestamp, std::vector<std::string>> CommandTuple(
return std::make_tuple(stream, timestamp, expected);
}
// Function to take the inputs and produce a diagnostic output std::string
// and output a packet with a diagnostic output std::string which includes
// Function to take the inputs and produce a diagnostic output string
// and output a packet with a diagnostic output string which includes
// the input timestamp and the ids of each input which is present.
absl::Status InputsToDebugString(const InputStreamShardSet& inputs,
OutputStreamShardSet* outputs) {
+2 -2
View File
@@ -279,7 +279,7 @@ class StdDevCalculator : public CalculatorBase {
REGISTER_CALCULATOR(StdDevCalculator);
// A calculator that receives some number of input streams carrying ints.
// Outputs, for each input timestamp, a space separated std::string containing
// Outputs, for each input timestamp, a space separated string containing
// the timestamp and all the inputs for that timestamp (Empty inputs
// will be denoted with "empty"). Sets the header to be a space-separated
// concatenation of the input stream headers.
@@ -368,7 +368,7 @@ REGISTER_CALCULATOR(SaverCalculator);
#ifndef MEDIAPIPE_MOBILE
// Source Calculator that produces matrices on the output stream with
// each coefficient from a normal gaussian. A std::string seed must be given
// each coefficient from a normal gaussian. A string seed must be given
// as an input side packet.
class RandomMatrixCalculator : public CalculatorBase {
public:
+1 -1
View File
@@ -86,7 +86,7 @@ class Timestamp {
// in microseconds, but this function should be preferred over Value() in case
// the underlying representation changes.
int64 Microseconds() const { return Value(); }
// This provides a human readable std::string for the special values.
// This provides a human readable string for the special values.
std::string DebugString() const;
// For use by framework. Clients or Calculator implementations should not call
+3 -2
View File
@@ -43,6 +43,7 @@ bzl_library(
"//mediapipe/framework:transitive_protos_bzl",
"//mediapipe/framework/deps:descriptor_set_bzl",
"//mediapipe/framework/deps:expand_template_bzl",
"@org_tensorflow//tensorflow/lite/core/shims:cc_library_with_tflite_bzl",
],
)
@@ -52,6 +53,7 @@ bzl_library(
"build_defs.bzl",
],
visibility = [
"//mediapipe/app/xeno/catalog:__subpackages__",
"//mediapipe/framework:__subpackages__",
],
)
@@ -286,6 +288,7 @@ cc_library(
mediapipe_cc_test(
name = "options_util_test",
size = "small",
timeout = "moderate",
srcs = ["options_util_test.cc"],
# A non-empty "data" param is needed to build the "_test_wasm" target.
data = [":node_chain_subgraph.proto"],
@@ -858,11 +861,9 @@ cc_library(
"//mediapipe/framework:calculator_cc_proto",
"//mediapipe/framework:calculator_framework",
"//mediapipe/framework:mediapipe_options_cc_proto",
"//mediapipe/framework:stream_handler_cc_proto",
"//mediapipe/framework:subgraph",
"//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status",
"//mediapipe/framework/stream_handler:sync_set_input_stream_handler_cc_proto",
"//mediapipe/framework/tool:switch_container_cc_proto",
],
alwayslink = 1,
@@ -12,9 +12,9 @@
// 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.
// This program takes one input file and encodes its contents as a C++ 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>
+36 -15
View File
@@ -20,6 +20,7 @@ load("//mediapipe/framework:transitive_protos.bzl", "transitive_protos")
load("//mediapipe/framework/deps:expand_template.bzl", "expand_template")
load("//mediapipe/framework/tool:build_defs.bzl", "clean_dep")
load("//mediapipe/framework/deps:descriptor_set.bzl", "direct_descriptor_set", "transitive_descriptor_set")
load("@org_tensorflow//tensorflow/lite/core/shims:cc_library_with_tflite.bzl", "cc_library_with_tflite")
def mediapipe_binary_graph(name, graph = None, output_name = None, deps = [], testonly = False, **kwargs):
"""Converts a graph from text format to binary format."""
@@ -98,6 +99,7 @@ def mediapipe_simple_subgraph(
register_as,
graph,
deps = [],
tflite_deps = None,
visibility = None,
testonly = None,
**kwargs):
@@ -109,6 +111,7 @@ def mediapipe_simple_subgraph(
CamelCase.
graph: the BUILD label of a text-format MediaPipe graph.
deps: any calculators or subgraphs used by this graph.
tflite_deps: any calculators or subgraphs used by this graph that may use different TFLite implementation.
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.
@@ -138,21 +141,39 @@ def mediapipe_simple_subgraph(
},
testonly = testonly,
)
native.cc_library(
name = name,
srcs = [
name + "_linked.cc",
graph_base_name + ".inc",
],
deps = [
clean_dep("//mediapipe/framework:calculator_framework"),
clean_dep("//mediapipe/framework:subgraph"),
] + deps,
alwayslink = 1,
visibility = visibility,
testonly = testonly,
**kwargs
)
if not tflite_deps:
native.cc_library(
name = name,
srcs = [
name + "_linked.cc",
graph_base_name + ".inc",
],
deps = [
clean_dep("//mediapipe/framework:calculator_framework"),
clean_dep("//mediapipe/framework:subgraph"),
] + deps,
alwayslink = 1,
visibility = visibility,
testonly = testonly,
**kwargs
)
else:
cc_library_with_tflite(
name = name,
srcs = [
name + "_linked.cc",
graph_base_name + ".inc",
],
tflite_deps = tflite_deps,
deps = [
clean_dep("//mediapipe/framework:calculator_framework"),
clean_dep("//mediapipe/framework:subgraph"),
] + deps,
alwayslink = 1,
visibility = visibility,
testonly = testonly,
**kwargs
)
def mediapipe_reexport_library(
name,
+1 -1
View File
@@ -85,7 +85,7 @@ std::pair<std::string, int> ParseTagIndexFromStream(const std::string& stream);
// Formats to "tag:index".
std::string CatTag(const std::string& tag, int index);
// Concatenates "tag:index:name" into a single std::string.
// Concatenates "tag:index:name" into a single string.
std::string CatStream(const std::pair<std::string, int>& tag_index,
const std::string& name);
@@ -34,7 +34,7 @@ class OptionsSyntaxUtil {
FieldPath OptionFieldPath(absl::string_view tag,
const Descriptor* descriptor);
// Splits a std::string into "tag" and "name" delimited by a single colon.
// Splits a string into "tag" and "name" delimited by a single colon.
std::vector<absl::string_view> StrSplitTags(absl::string_view tag_and_name);
private:
+1 -1
View File
@@ -228,7 +228,7 @@ absl::Status SyntaxStatus(bool ok, const std::string& text, T* result) {
" for type: ", MediaPipeTypeStringOrDemangled<T>(), "."));
}
// Templated parsing of a std::string value.
// Templated parsing of a string value.
template <typename T>
absl::Status ParseValue(const std::string& text, T* result) {
return SyntaxStatus(absl::SimpleAtoi(text, result), text, result);
@@ -31,7 +31,7 @@ class {{SUBGRAPH_CLASS_NAME}} : public Subgraph {
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.
// bytes. The trailing NUL added to the string literal should be excluded.
if (config.ParseFromArray(binary_graph, sizeof(binary_graph) - 1)) {
return config;
} else {
+1 -1
View File
@@ -40,7 +40,7 @@ absl::Status StatusInvalid(const std::string& error_message);
ABSL_DEPRECATED("Use absl::UnknownError(error_message) instead.")
absl::Status StatusFail(const std::string& error_message);
// Prefixes the given std::string to the error message in status.
// Prefixes the given string to the error message in status.
// This function should be considered internal to the framework.
// TODO Replace usage of AddStatusPrefix with util::Annotate().
absl::Status AddStatusPrefix(const std::string& prefix,
@@ -22,8 +22,6 @@
#include "mediapipe/framework/port/canonical_errors.h"
#include "mediapipe/framework/port/ret_check.h"
#include "mediapipe/framework/port/status.h"
#include "mediapipe/framework/stream_handler.pb.h"
#include "mediapipe/framework/stream_handler/sync_set_input_stream_handler.pb.h"
#include "mediapipe/framework/tool/container_util.h"
#include "mediapipe/framework/tool/name_util.h"
#include "mediapipe/framework/tool/subgraph_expansion.h"
@@ -88,12 +86,6 @@ CalculatorGraphConfig::Node* BuildDemuxNode(
CalculatorGraphConfig* config) {
CalculatorGraphConfig::Node* result = config->add_node();
*result->mutable_calculator() = "SwitchDemuxCalculator";
*result->mutable_input_stream_handler()->mutable_input_stream_handler() =
"ImmediateInputStreamHandler";
if (container_node.has_input_stream_handler()) {
*result->mutable_input_stream_handler() =
container_node.input_stream_handler();
}
return result;
}
@@ -103,8 +95,6 @@ CalculatorGraphConfig::Node* BuildMuxNode(
CalculatorGraphConfig* config) {
CalculatorGraphConfig::Node* result = config->add_node();
*result->mutable_calculator() = "SwitchMuxCalculator";
*result->mutable_input_stream_handler()->mutable_input_stream_handler() =
"ImmediateInputStreamHandler";
return result;
}
@@ -24,4 +24,7 @@ message SwitchContainerOptions {
// Activates channel 1 for enable = true, channel 0 otherwise.
optional bool enable = 4;
// Use DefaultInputStreamHandler for muxing & demuxing.
optional bool synchronize_io = 5;
}
@@ -66,8 +66,7 @@ REGISTER_CALCULATOR(TripleIntCalculator);
// A testing example of a SwitchContainer containing two subnodes.
// Note that the input and output tags supplied to the container node,
// must match the input and output tags required by the subnodes.
CalculatorGraphConfig SubnodeContainerExample(
const std::string& input_stream_handler = "") {
CalculatorGraphConfig SubnodeContainerExample(const std::string& options = "") {
std::string config = R"pb(
input_stream: "foo"
input_stream: "enable"
@@ -80,9 +79,9 @@ CalculatorGraphConfig SubnodeContainerExample(
options {
[mediapipe.SwitchContainerOptions.ext] {
contained_node: { calculator: "TripleIntCalculator" }
contained_node: { calculator: "PassThroughCalculator" }
contained_node: { calculator: "PassThroughCalculator" } $options
}
} $input_stream_handler
}
}
node {
calculator: "PassThroughCalculator"
@@ -94,8 +93,7 @@ CalculatorGraphConfig SubnodeContainerExample(
)pb";
return mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(
absl::StrReplaceAll(config,
{{"$input_stream_handler", input_stream_handler}}));
absl::StrReplaceAll(config, {{"$options", options}}));
}
// A testing example of a SwitchContainer containing two subnodes.
@@ -248,9 +246,6 @@ TEST(SwitchContainerTest, ApplyToSubnodes) {
options {
[mediapipe.SwitchContainerOptions.ext] {}
}
input_stream_handler {
input_stream_handler: "ImmediateInputStreamHandler"
}
}
node {
name: "switchcontainer__TripleIntCalculator"
@@ -274,9 +269,6 @@ TEST(SwitchContainerTest, ApplyToSubnodes) {
options {
[mediapipe.SwitchContainerOptions.ext] {}
}
input_stream_handler {
input_stream_handler: "ImmediateInputStreamHandler"
}
}
node {
calculator: "PassThroughCalculator"
@@ -322,9 +314,7 @@ TEST(SwitchContainerTest, ValidateInputStreamHandler) {
options {
[mediapipe.SwitchContainerOptions.ext] {}
}
input_stream_handler {
input_stream_handler: "ImmediateInputStreamHandler"
}
input_stream_handler { input_stream_handler: "DefaultInputStreamHandler" }
}
node {
name: "switchcontainer__TripleIntCalculator"
@@ -350,9 +340,7 @@ TEST(SwitchContainerTest, ValidateInputStreamHandler) {
options {
[mediapipe.SwitchContainerOptions.ext] {}
}
input_stream_handler {
input_stream_handler: "ImmediateInputStreamHandler"
}
input_stream_handler { input_stream_handler: "DefaultInputStreamHandler" }
}
node {
calculator: "PassThroughCalculator"
@@ -371,83 +359,12 @@ TEST(SwitchContainerTest, ValidateInputStreamHandler) {
EXPECT_THAT(graph.Config(), mediapipe::EqualsProto(expected_graph));
}
// Expands the SwitchContainer with a node-level input_stream_handler.
TEST(SwitchContainerTest, OverrideInputStreamHandler) {
EXPECT_TRUE(SubgraphRegistry::IsRegistered("SwitchContainer"));
CalculatorGraph graph;
CalculatorGraphConfig supergraph = SubnodeContainerExample(
R"pb(input_stream_handler {
input_stream_handler: "DefaultInputStreamHandler"
})pb");
*supergraph.mutable_node(0)
->mutable_input_stream_handler()
->mutable_input_stream_handler() = "DefaultInputStreamHandler";
MP_ASSERT_OK(graph.Initialize(supergraph, {}));
CalculatorGraphConfig expected_graph =
mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"pb(
node {
name: "switchcontainer__SwitchDemuxCalculator"
calculator: "SwitchDemuxCalculator"
input_stream: "ENABLE:enable"
input_stream: "foo"
output_stream: "C0__:switchcontainer__c0__foo"
output_stream: "C1__:switchcontainer__c1__foo"
options {
[mediapipe.SwitchContainerOptions.ext] {}
}
input_stream_handler {
input_stream_handler: "DefaultInputStreamHandler"
}
}
node {
name: "switchcontainer__TripleIntCalculator"
calculator: "TripleIntCalculator"
input_stream: "switchcontainer__c0__foo"
output_stream: "switchcontainer__c0__bar"
}
node {
name: "switchcontainer__PassThroughCalculator"
calculator: "PassThroughCalculator"
input_stream: "switchcontainer__c1__foo"
output_stream: "switchcontainer__c1__bar"
}
node {
name: "switchcontainer__SwitchMuxCalculator"
calculator: "SwitchMuxCalculator"
input_stream: "ENABLE:enable"
input_stream: "C0__:switchcontainer__c0__bar"
input_stream: "C1__:switchcontainer__c1__bar"
output_stream: "bar"
options {
[mediapipe.SwitchContainerOptions.ext] {}
}
input_stream_handler {
input_stream_handler: "ImmediateInputStreamHandler"
}
}
node {
calculator: "PassThroughCalculator"
input_stream: "foo"
input_stream: "bar"
output_stream: "output_foo"
output_stream: "output_bar"
}
input_stream: "foo"
input_stream: "enable"
executor {}
input_side_packet: "timezone"
)pb");
EXPECT_THAT(graph.Config(), mediapipe::EqualsProto(expected_graph));
}
// Runs the SwitchContainer with a node-level input_stream_handler.
TEST(SwitchContainerTest, RunsWithInputStreamHandler) {
EXPECT_TRUE(SubgraphRegistry::IsRegistered("SwitchContainer"));
CalculatorGraphConfig supergraph = SubnodeContainerExample(
R"pb(input_stream_handler {
input_stream_handler: "DefaultInputStreamHandler"
})pb");
CalculatorGraphConfig supergraph =
SubnodeContainerExample(R"pb(synchronize_io: true)pb");
MP_EXPECT_OK(tool::ExpandSubgraphs(&supergraph));
LOG(INFO) << supergraph.DebugString();
RunTestContainer(supergraph, true);
}
@@ -470,9 +387,6 @@ TEST(SwitchContainerTest, ApplyToSideSubnodes) {
options {
[mediapipe.SwitchContainerOptions.ext] {}
}
input_stream_handler {
input_stream_handler: "ImmediateInputStreamHandler"
}
}
node {
name: "switchcontainer__TripleIntCalculator"
@@ -496,9 +410,6 @@ TEST(SwitchContainerTest, ApplyToSideSubnodes) {
options {
[mediapipe.SwitchContainerOptions.ext] {}
}
input_stream_handler {
input_stream_handler: "ImmediateInputStreamHandler"
}
}
node {
calculator: "PassThroughCalculator"
@@ -26,6 +26,7 @@
#include "mediapipe/framework/port/status.h"
#include "mediapipe/framework/port/status_macros.h"
#include "mediapipe/framework/tool/container_util.h"
#include "mediapipe/framework/tool/switch_container.pb.h"
namespace mediapipe {
@@ -113,7 +114,10 @@ absl::Status SwitchDemuxCalculator::GetContract(CalculatorContract* cc) {
}
}
}
cc->SetInputStreamHandler("ImmediateInputStreamHandler");
auto& options = cc->Options<mediapipe::SwitchContainerOptions>();
if (!options.synchronize_io()) {
cc->SetInputStreamHandler("ImmediateInputStreamHandler");
}
cc->SetProcessTimestampBounds(true);
return absl::OkStatus();
}
@@ -28,6 +28,7 @@
#include "mediapipe/framework/port/status.h"
#include "mediapipe/framework/port/status_macros.h"
#include "mediapipe/framework/tool/container_util.h"
#include "mediapipe/framework/tool/switch_container.pb.h"
namespace mediapipe {
@@ -68,6 +69,17 @@ class SwitchMuxCalculator : public CalculatorBase {
private:
int channel_index_;
std::set<std::string> channel_tags_;
mediapipe::SwitchContainerOptions options_;
// This is used to keep around packets that we've received but not
// relayed yet (because we may not know which channel we should yet be using
// when synchronized_io flag is set).
std::map<Timestamp, std::map<CollectionItemId, Packet>> packet_history_;
// Historical channel index values for timestamps where we don't have all
// packets available yet (when synchronized_io flag is set).
std::map<Timestamp, int> channel_history_;
// Number of output steams that we already processed for the current output
// timestamp.
int current_processed_stream_count_ = 0;
};
REGISTER_CALCULATOR(SwitchMuxCalculator);
@@ -122,6 +134,7 @@ absl::Status SwitchMuxCalculator::GetContract(CalculatorContract* cc) {
}
absl::Status SwitchMuxCalculator::Open(CalculatorContext* cc) {
options_ = cc->Options<mediapipe::SwitchContainerOptions>();
channel_index_ = tool::GetChannelIndex(*cc, channel_index_);
channel_tags_ = ChannelTags(cc->Inputs().TagMap());
@@ -141,13 +154,79 @@ absl::Status SwitchMuxCalculator::Process(CalculatorContext* cc) {
// Update the input channel index if specified.
channel_index_ = tool::GetChannelIndex(*cc, channel_index_);
// Relay packets and timestamps only from channel_index_.
for (const std::string& tag : channel_tags_) {
for (int index = 0; index < cc->Outputs().NumEntries(tag); ++index) {
auto& output = cc->Outputs().Get(tag, index);
std::string input_tag = tool::ChannelTag(tag, channel_index_);
auto& input = cc->Inputs().Get(input_tag, index);
tool::Relay(input, &output);
if (options_.synchronize_io()) {
// Start with adding input signals into channel_history_ and packet_history_
if (cc->Inputs().HasTag("ENABLE") &&
!cc->Inputs().Tag("ENABLE").IsEmpty()) {
channel_history_[cc->Inputs().Tag("ENABLE").Value().Timestamp()] =
channel_index_;
}
if (cc->Inputs().HasTag("SELECT") &&
!cc->Inputs().Tag("SELECT").IsEmpty()) {
channel_history_[cc->Inputs().Tag("SELECT").Value().Timestamp()] =
channel_index_;
}
for (auto input_id = cc->Inputs().BeginId();
input_id < cc->Inputs().EndId(); ++input_id) {
auto& entry = cc->Inputs().Get(input_id);
if (entry.IsEmpty()) {
continue;
}
packet_history_[entry.Value().Timestamp()][input_id] = entry.Value();
}
// Now check if we have enough information to produce any outputs.
while (!channel_history_.empty()) {
// Look at the oldest unprocessed timestamp.
auto it = channel_history_.begin();
auto& packets = packet_history_[it->first];
int total_streams = 0;
// Loop over all outputs to see if we have anything new that we can relay.
for (const std::string& tag : channel_tags_) {
for (int index = 0; index < cc->Outputs().NumEntries(tag); ++index) {
++total_streams;
auto input_id =
cc->Inputs().GetId(tool::ChannelTag(tag, it->second), index);
auto packet_it = packets.find(input_id);
if (packet_it != packets.end()) {
cc->Outputs().Get(tag, index).AddPacket(packet_it->second);
++current_processed_stream_count_;
} else if (it->first <
cc->Inputs().Get(input_id).Value().Timestamp()) {
// Getting here means that input stream that corresponds to this
// output at the timestamp we're trying to process right now has
// already advanced beyond this timestamp. This means that we will
// shouldn't expect a packet for this timestamp anymore, and we can
// safely advance timestamp on the output.
cc->Outputs()
.Get(tag, index)
.SetNextTimestampBound(it->first.NextAllowedInStream());
++current_processed_stream_count_;
}
}
}
if (current_processed_stream_count_ == total_streams) {
// There's nothing else to wait for at the current timestamp, do the
// cleanup and move on to the next one.
packet_history_.erase(it->first);
channel_history_.erase(it);
current_processed_stream_count_ = 0;
} else {
// We're still missing some packets for the current timestamp. Clean up
// those that we just relayed and let the rest wait until the next
// Process() call.
packets.clear();
break;
}
}
} else {
// Relay packets and timestamps only from channel_index_.
for (const std::string& tag : channel_tags_) {
for (int index = 0; index < cc->Outputs().NumEntries(tag); ++index) {
auto& output = cc->Outputs().Get(tag, index);
std::string input_tag = tool::ChannelTag(tag, channel_index_);
auto& input = cc->Inputs().Get(input_tag, index);
tool::Relay(input, &output);
}
}
}
return absl::OkStatus();
+3 -3
View File
@@ -51,8 +51,8 @@ class TagMap {
int count;
};
// Create a TagMap from a repeated std::string proto field of
// TAG:<index>:name. This is the most common usage:
// Create a TagMap from a repeated string proto field of TAG:<index>:name.
// This is the most common usage:
// ASSIGN_OR_RETURN(std::shared_ptr<TagMap> tag_map,
// tool::TagMap::Create(node.input_streams()));
static absl::StatusOr<std::shared_ptr<TagMap>> Create(
@@ -87,7 +87,7 @@ class TagMap {
// Returns canonicalized strings describing the TagMap.
proto_ns::RepeatedPtrField<ProtoString> CanonicalEntries() const;
// Returns a std::string description for debug purposes.
// Returns a string description for debug purposes.
std::string DebugString() const;
// Returns a shorter description for debug purposes (doesn't include
// stream/side packet names).
+2 -2
View File
@@ -318,8 +318,8 @@ TEST(TagMapTest, SameAs) {
}
}
// A helper function to test that a TagMap's debug std::string and short
// debug std::string each satisfy a matcher.
// A helper function to test that a TagMap's debug string and short
// debug string each satisfy a matcher.
template <typename Matcher>
void TestDebugString(
const absl::StatusOr<std::shared_ptr<tool::TagMap>>& statusor_tag_map,
@@ -433,7 +433,7 @@ class TemplateExpanderImpl {
return result;
}
// Converts a TemplateArgument to std::string.
// Converts a TemplateArgument to string.
std::string AsString(const TemplateArgument& value) {
std::string result;
if (value.has_num()) {
+13 -13
View File
@@ -260,7 +260,7 @@ class TemplateParser::Parser::ParserImpl {
typedef proto_ns::TextFormat::ParseLocation ParseLocation;
// Determines if repeated values for non-repeated fields and
// oneofs are permitted, e.g., the std::string "foo: 1 foo: 2" for a
// oneofs are permitted, e.g., the string "foo: 1 foo: 2" for a
// required/optional field named "foo", or "baz: 1 qux: 2"
// where "baz" and "qux" are members of the same oneof.
enum SingularOverwritePolicy {
@@ -401,7 +401,7 @@ class TemplateParser::Parser::ParserImpl {
}
#ifndef PROTO2_OPENSOURCE
// Consumes a std::string value and parses it as a packed repeated field into
// Consumes a string value and parses it as a packed repeated field into
// the given field of the given message.
bool ConsumePackedFieldAsString(const std::string& field_name,
const FieldDescriptor* field,
@@ -409,7 +409,7 @@ class TemplateParser::Parser::ParserImpl {
std::string packed;
DO(ConsumeString(&packed));
// Prepend field tag and varint-encoded std::string length to turn into
// Prepend field tag and varint-encoded string length to turn into
// encoded message.
std::string tagged;
{
@@ -428,7 +428,7 @@ class TemplateParser::Parser::ParserImpl {
io::CodedInputStream coded_input(&array_input);
if (!message->MergePartialFromCodedStream(&coded_input)) {
ReportError("Could not parse packed field \"" + field_name +
"\" as wire-encoded std::string.");
"\" as wire-encoded string.");
return false;
}
@@ -607,7 +607,7 @@ class TemplateParser::Parser::ParserImpl {
bool consumed_semicolon = TryConsume(":");
if (consumed_semicolon && field->options().weak() &&
LookingAtType(io::Tokenizer::TYPE_STRING)) {
// we are getting a bytes std::string for a weak field.
// we are getting a bytes string for a weak field.
std::string tmp;
DO(ConsumeString(&tmp));
reflection->MutableMessage(message, field)->ParseFromString(tmp);
@@ -640,8 +640,8 @@ class TemplateParser::Parser::ParserImpl {
#ifndef PROTO2_OPENSOURCE
} else if (field->is_packable() &&
LookingAtType(io::Tokenizer::TYPE_STRING)) {
// Packable field printed as wire-formatted std::string: "foo: "abc\123"".
// Fields of type std::string cannot be packed themselves, so this is
// Packable field printed as wire-formatted string: "foo: "abc\123"".
// Fields of type string cannot be packed themselves, so this is
// unambiguous.
DO(ConsumePackedFieldAsString(field_name, field, message));
#endif // !PROTO2_OPENSOURCE
@@ -908,7 +908,7 @@ class TemplateParser::Parser::ParserImpl {
}
return true;
}
// Possible field values other than std::string:
// Possible field values other than string:
// 12345 => TYPE_INTEGER
// -12345 => TYPE_SYMBOL + TYPE_INTEGER
// 1.2345 => TYPE_FLOAT
@@ -992,7 +992,7 @@ class TemplateParser::Parser::ParserImpl {
return false;
}
// Consume a std::string of form "<id1>.<id2>....<idN>".
// Consume a string of form "<id1>.<id2>....<idN>".
bool ConsumeFullTypeName(std::string* name) {
DO(ConsumeIdentifier(name));
while (TryConsume(".")) {
@@ -1013,11 +1013,11 @@ class TemplateParser::Parser::ParserImpl {
return true;
}
// Consumes a std::string and saves its value in the text parameter.
// Consumes a string and saves its value in the text parameter.
// Returns false if the token is not of type STRING.
bool ConsumeString(std::string* text) {
if (!LookingAtType(io::Tokenizer::TYPE_STRING)) {
ReportError("Expected std::string, got: " + tokenizer_.current().text);
ReportError("Expected string, got: " + tokenizer_.current().text);
return false;
}
@@ -1391,7 +1391,7 @@ void StowFieldValue(Message* message, TemplateExpression* expression) {
}
}
// Strips first and last quotes from a std::string.
// Strips first and last quotes from a string.
static void StripQuotes(std::string* str) {
// Strip off the leading and trailing quotation marks from the value, if
// there are any.
@@ -1585,7 +1585,7 @@ class TemplateParser::Parser::MediaPipeParserImpl
return true;
}
// Parses a numeric or a std::string literal.
// Parses a numeric or a string literal.
bool ConsumeLiteral(TemplateExpression* result) {
std::string token = tokenizer_.current().text;
StripQuotes(&token);
+5
View File
@@ -215,6 +215,11 @@ std::string GetTestRootDir() {
std::string GetTestOutputsDir() {
const char* output_dir = getenv("TEST_UNDECLARED_OUTPUTS_DIR");
if (!output_dir) {
#ifdef __APPLE__
char path[PATH_MAX];
size_t n = confstr(_CS_DARWIN_USER_TEMP_DIR, path, sizeof(path));
if (n > 0 && n < sizeof(path)) return path;
#endif // __APPLE__
output_dir = "/tmp";
}
return output_dir;
+5 -5
View File
@@ -66,7 +66,7 @@ absl::Status SetFromTagAndNameInfo(
const TagAndNameInfo& info,
proto_ns::RepeatedPtrField<ProtoString>* tags_and_names);
// The std::string is a valid name for an input stream, output stream,
// The string is a valid name for an input stream, output stream,
// side packet, and input collection. Names use only lower case letters,
// numbers, and underscores.
//
@@ -77,18 +77,18 @@ absl::Status SetFromTagAndNameInfo(
// (3) Because input side packet names end up in model directory names,
// where lower case naming is the norm.
absl::Status ValidateName(const std::string& name);
// The std::string is a valid tag name. Tags use only upper case letters,
// The string is a valid tag name. Tags use only upper case letters,
// numbers, and underscores.
absl::Status ValidateTag(const std::string& tag);
// Parse a "Tag and Name" std::string into a tag and a name.
// Parse a "Tag and Name" string into a tag and a name.
// The format is an optional tag and colon, followed by a name.
// Example 1: "VIDEO:frames2" -> tag: "VIDEO", name: "frames2"
// Example 2: "video_frames_1" -> tag: "", name: "video_frames_1"
absl::Status ParseTagAndName(const std::string& tag_and_name, std::string* tag,
std::string* name);
// Parse a generic TAG:index:name std::string. The format is a tag, then an
// Parse a generic TAG:index:name string. The format is a tag, then an
// index, then a name. The tag and index are optional. If the index
// is included, then the tag must be included. If no tag is used then
// index is set to -1 (and should be assigned by argument position).
@@ -99,7 +99,7 @@ absl::Status ParseTagAndName(const std::string& tag_and_name, std::string* tag,
absl::Status ParseTagIndexName(const std::string& tag_and_name,
std::string* tag, int* index, std::string* name);
// Parse a generic TAG:index std::string. The format is a tag, then an index
// Parse a generic TAG:index string. The format is a tag, then an index
// with both being optional. If the tag is missing it is assumed to be
// "" and if the index is missing then it is assumed to be 0. If the
// index is provided then a colon (':') must be used.
+9 -9
View File
@@ -13,8 +13,8 @@
// limitations under the License.
// This header defines static maps to store the mappings from type hash id and
// name std::string to MediaPipeTypeData. It also provides code to inspect
// types of packets and access registered serialize and deserialize functions.
// name string to MediaPipeTypeData. It also provides code to inspect types of
// packets and access registered serialize and deserialize functions.
// Calculators can use this to infer types of packets and adjust accordingly.
//
// Register a type:
@@ -242,7 +242,7 @@ class StaticMap {
class MapName : public type_map_internal::StaticMap<MapName, KeyType> {};
// Defines a map from unique typeid number to MediaPipeTypeData.
DEFINE_MEDIAPIPE_TYPE_MAP(PacketTypeIdToMediaPipeTypeData, size_t);
// Defines a map from unique type std::string to MediaPipeTypeData.
// Defines a map from unique type string to MediaPipeTypeData.
DEFINE_MEDIAPIPE_TYPE_MAP(PacketTypeStringToMediaPipeTypeData, std::string);
// MEDIAPIPE_REGISTER_TYPE can be used to register a type.
@@ -267,7 +267,7 @@ DEFINE_MEDIAPIPE_TYPE_MAP(PacketTypeStringToMediaPipeTypeData, std::string);
// #undef MY_MAP_TYPE
//
// MEDIAPIPE_REGISTER_TYPE(
// std::string, "string", StringSerializeFn, StringDeserializeFn);
// std::string, "std::string", StringSerializeFn, StringDeserializeFn);
//
#define MEDIAPIPE_REGISTER_TYPE(type, type_name, serialize_fn, deserialize_fn) \
SET_MEDIAPIPE_TYPE_MAP_VALUE( \
@@ -293,7 +293,7 @@ DEFINE_MEDIAPIPE_TYPE_MAP(PacketTypeStringToMediaPipeTypeData, std::string);
// typedef is used, the name should be prefixed with the namespace(s),
// seperated by double colons.
//
// Example 1: register type with non-std::string proxy.
// Example 1: register type with non-string proxy.
// absl::Status ToProxyFn(
// const ClassType& obj, ProxyType* proxy)
// {
@@ -315,15 +315,15 @@ DEFINE_MEDIAPIPE_TYPE_MAP(PacketTypeStringToMediaPipeTypeData, std::string);
// ::mediapipe::DeserializeUsingGenericFn<ClassType WITH_MEDIAPIPE_PROXY
// ProxyType>, ToProxyFn, FromProxyFn);
//
// Example 2: register type with std::string proxy.
// absl::Status ToProxyFn(const ClassType& obj, std::string* encoding)
// Example 2: register type with string proxy.
// absl::Status ToProxyFn(const ClassType& obj, string* encoding)
// {
// ...
// return absl::OkStatus();
// }
//
// absl::Status FromProxyFn(
// const ProxyType& proxy, std::string* encoding) {
// const ProxyType& proxy, string* encoding) {
// ...
// return absl::OkStatus();
// }
@@ -367,7 +367,7 @@ inline const std::string* MediaPipeTypeStringFromTypeId(const size_t type_id) {
return (value) ? &value->type_string : nullptr;
}
// Returns std::string identifier of type or NULL if not registered.
// Returns string identifier of type or NULL if not registered.
template <typename T>
inline const std::string* MediaPipeTypeString() {
return MediaPipeTypeStringFromTypeId(tool::GetTypeHash<T>());
+27 -1
View File
@@ -49,7 +49,7 @@ namespace mediapipe {
namespace {
// Create a debug std::string name for a set of edge. An edge can be either
// Create a debug string name for a set of edge. An edge can be either
// a stream or a side packet.
std::string DebugEdgeNames(
const std::string& edge_type,
@@ -413,8 +413,11 @@ absl::Status ValidatedGraphConfig::Initialize(
// Set Any types based on what they connect to.
MP_RETURN_IF_ERROR(ResolveAnyTypes(&input_streams_, &output_streams_));
MP_RETURN_IF_ERROR(ResolveOneOfTypes(&input_streams_, &output_streams_));
MP_RETURN_IF_ERROR(
ResolveAnyTypes(&input_side_packets_, &output_side_packets_));
MP_RETURN_IF_ERROR(
ResolveOneOfTypes(&input_side_packets_, &output_side_packets_));
// Validate consistency of side packets and streams.
MP_RETURN_IF_ERROR(ValidateSidePacketTypes());
@@ -908,6 +911,29 @@ absl::Status ValidatedGraphConfig::ResolveAnyTypes(
return absl::OkStatus();
}
absl::Status ValidatedGraphConfig::ResolveOneOfTypes(
std::vector<EdgeInfo>* input_edges, std::vector<EdgeInfo>* output_edges) {
for (EdgeInfo& input_edge : *input_edges) {
if (input_edge.upstream == -1) {
continue;
}
EdgeInfo& output_edge = (*output_edges)[input_edge.upstream];
PacketType* input_root = input_edge.packet_type->GetSameAs();
PacketType* output_root = output_edge.packet_type->GetSameAs();
if (!input_root->IsConsistentWith(*output_root)) continue;
// We narrow down OneOf types here if the other side is a single type.
// We do not currently intersect multiple OneOf types.
// Note that this is sensitive to the order edges are examined.
// TODO: we should be more thorough.
if (input_root->IsOneOf() && output_root->IsExactType()) {
input_root->SetSameAs(output_edge.packet_type);
} else if (output_root->IsOneOf() && input_root->IsExactType()) {
output_root->SetSameAs(input_edge.packet_type);
}
}
return absl::OkStatus();
}
absl::Status ValidatedGraphConfig::ValidateStreamTypes() {
for (const EdgeInfo& stream : input_streams_) {
RET_CHECK_NE(stream.upstream, -1);
+6 -4
View File
@@ -133,12 +133,11 @@ class NodeTypeInfo {
// This function is only valid for a NodeTypeInfo of NodeType CALCULATOR.
bool AddSource(int index) { return ancestor_sources_.insert(index).second; }
// Convert the NodeType enum into a std::string (generally for error
// messaging).
// Convert the NodeType enum into a string (generally for error messaging).
static std::string NodeTypeToString(NodeType node_type);
// Returns the name of the specified InputStreamHandler, or empty std::string
// if none set.
// Returns the name of the specified InputStreamHandler, or empty string if
// none set.
std::string GetInputStreamHandler() const {
return contract_.GetInputStreamHandler();
}
@@ -383,6 +382,9 @@ class ValidatedGraphConfig {
// Infer the type of types set to "Any" by what they are connected to.
absl::Status ResolveAnyTypes(std::vector<EdgeInfo>* input_edges,
std::vector<EdgeInfo>* output_edges);
// Narrow down OneOf types if they other end is a single type.
absl::Status ResolveOneOfTypes(std::vector<EdgeInfo>* input_edges,
std::vector<EdgeInfo>* output_edges);
// Returns an error if the generator graph does not have consistent
// type specifications for side packets.