mediapipe/mediapipe/framework/input_stream_handler.h
MediaPipe Team 7fb37c80e8 Project import generated by Copybara.
GitOrigin-RevId: 19a829ffd755edb43e54d20c0e7b9348512d5108
2022-05-05 19:57:20 +00:00

328 lines
14 KiB
C++

// Copyright 2019 The MediaPipe Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef MEDIAPIPE_FRAMEWORK_INPUT_STREAM_HANDLER_H_
#define MEDIAPIPE_FRAMEWORK_INPUT_STREAM_HANDLER_H_
#include <atomic>
#include <functional>
#include <list>
#include <memory>
#include <string>
#include <utility>
#include <vector>
// TODO: Move protos in another CL after the C++ code migration.
#include "mediapipe/framework/calculator_context.h"
#include "mediapipe/framework/calculator_context_manager.h"
#include "mediapipe/framework/collection.h"
#include "mediapipe/framework/collection_item_id.h"
#include "mediapipe/framework/deps/registration.h"
#include "mediapipe/framework/input_stream_manager.h"
#include "mediapipe/framework/input_stream_shard.h"
#include "mediapipe/framework/mediapipe_options.pb.h"
#include "mediapipe/framework/packet.h"
#include "mediapipe/framework/packet_set.h"
#include "mediapipe/framework/packet_type.h"
#include "mediapipe/framework/port/status.h"
#include "mediapipe/framework/tool/tag_map.h"
namespace mediapipe {
// Indicates the operation the node is ready for.
enum class NodeReadiness {
// The node is not ready.
kNotReady,
// The node is ready and we should run Process().
kReadyForProcess,
// The node is ready and we should run Close().
kReadyForClose,
};
// Abstract base class for input stream handlers.
//
// The input stream handler is invoked every time a Packet is enqueued or the
// next timestamp bound is set in any of the input streams and actually decides
// whether a calculator node's Process() should be called. The input stream
// handler owns and manages the InputStreamManager objects. The operations
// performed by OutputStreamHandler on an InputStreamManager object need to go
// through its input stream handler.
//
// Derived classes are required to implement the following member functions:
//
// NodeReadiness GetNodeReadiness(Timestamp* min_stream_timestamp);
// void FillInputSet(Timestamp input_timestamp,
// InputStreamShardSet* input_set);
//
class InputStreamHandler {
public:
InputStreamHandler(std::shared_ptr<tool::TagMap> tag_map,
CalculatorContextManager* calculator_context_manager,
const MediaPipeOptions& options,
bool calculator_run_in_parallel)
: input_stream_managers_(std::move(tag_map)),
calculator_context_manager_(calculator_context_manager),
options_(options),
calculator_run_in_parallel_(calculator_run_in_parallel) {}
virtual ~InputStreamHandler() = default;
// Initializes the InputStreamManagerSet object.
// flat_input_stream_managers is expected to point to a contiguous
// flat array with InputStreamManagers corresponding to the id's in
// InputStreamHandler::input_stream_managers_ (meaning it should point
// to somewhere in the middle of the main flat array of all input
// stream managers).
absl::Status InitializeInputStreamManagers(
InputStreamManager* flat_input_stream_managers);
InputStreamManager* GetInputStreamManager(CollectionItemId id);
// Sets up the InputStreamShardSet by propagating data from the managers.
absl::Status SetupInputShards(InputStreamShardSet* input_shards);
// Returns a vector of pairs of stream name and queue size for monitoring
// purpose.
std::vector<std::tuple<std::string, int, int, Timestamp>> GetMonitoringInfo();
// Resets the input stream handler and its underlying input streams for
// another run of the graph.
// InputStreamHandler subclass can override this function to meet some special
// needs while preparing the calculator node for run.
// TODO: Makes PrepareForRun() non-virtual and makes
// InitializeInputStreamManagers() virtual instead.
virtual void PrepareForRun(
std::function<void()> headers_ready_callback,
std::function<void()> notification_callback,
std::function<void(CalculatorContext*)> schedule_callback,
std::function<void(absl::Status)> error_callback);
int NumInputStreams() const { return input_stream_managers_.NumEntries(); }
// Returns the tag map of the input streams.
const std::shared_ptr<tool::TagMap>& InputTagMap() const {
return input_stream_managers_.TagMap();
}
// Sets header into a particular stream.
void SetHeader(CollectionItemId id, const Packet& header);
// Updates the header packets in the input shards.
void UpdateInputShardHeaders(InputStreamShardSet* input_shards);
// Sets max queue size of every stream.
void SetMaxQueueSize(int max_queue_size);
// Sets max queue size of a particular stream.
void SetMaxQueueSize(CollectionItemId id, int max_queue_size);
void SetQueueSizeCallbacks(
InputStreamManager::QueueSizeCallback becomes_full_callback,
InputStreamManager::QueueSizeCallback becomes_not_full_callback);
// Add packets into a particular stream.
virtual void AddPackets(CollectionItemId id,
const std::list<Packet>& packets);
// Moves packets into a particular stream.
virtual void MovePackets(CollectionItemId id, std::list<Packet>* packets);
// Sets next timestamp bound in a particular stream.
void SetNextTimestampBound(CollectionItemId id, Timestamp bound);
// Clears the current packet of every stream shard and removes the current
// timestamp from the calculator context.
void ClearCurrentInputs(CalculatorContext* calculator_context);
void Close();
// 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
// max number of invocations that are allowed to be scheduled is reached.
// Returns true if at least one invocation has been scheduled.
// The latest minimum timestamp bound of the input streams is returned in
// *input_bound if the latest readiness of the node is kNotReady when the
// function returns. During batching, this value will be equal to the
// timestamp of the first set of inputs in the batch. In other cases,
// Timestamp::Unset() is returned.
// This method can only be invoked in the schedule phase.
bool ScheduleInvocations(int max_allowance, Timestamp* input_bound);
// Finalizes the input set before the calculator node's Process() is
// called at the given input timestamp.
void FinalizeInputSet(Timestamp timestamp, InputStreamShardSet* input_set);
// Returns the number of input stream headers (excluding headers of back
// edges) that are not set.
int UnsetHeaderCount() const {
return unset_header_count_.load(std::memory_order_relaxed);
}
// When true, Calculator::Process is called for any increase in the
// timestamp bound, whether or not any packets are available.
// Calculator::Process is called when the minimum timestamp bound
// increases for any synchronized set of input streams.
// DefaultInputStreamHandler groups all input streams into a single set.
// ImmediateInputStreamHandler treats each input stream as a separate set.
void SetProcessTimestampBounds(bool process_ts) {
process_timestamps_ = process_ts;
}
// When true, Calculator::Process is called for every input timestamp bound.
bool ProcessTimestampBounds() { return process_timestamps_; }
// Returns the number of sync-sets populated by this input stream handler.
virtual int SyncSetCount() { return 1; }
// A helper class to build input packet sets for a certain set of streams.
//
// ReadyForProcess requires all of the streams to be fully determined
// at the same input-timestamp.
// This is the readiness policy for all streams in DefaultInputStreamHandler.
// It is also the policy for each sync-set in SyncSetInputStreamHandler.
// It is also the policy for each input-stream in ImmediateInputStreamHandler.
//
// If ProcessTimestampBounds() is set, then a fully determined input timestamp
// with only empty input packets will qualify as ReadyForProcess.
class SyncSet {
public:
// Creates a SyncSet for a certain set of streams, |stream_ids|.
SyncSet(InputStreamHandler* input_stream_handler,
std::vector<CollectionItemId> stream_ids);
// Reinitializes this SyncSet before each CalculatorGraph run.
void PrepareForRun();
// Answers whether this stream is ready for Process or Close.
NodeReadiness GetReadiness(Timestamp* min_stream_timestamp);
// Returns the latest timestamp returned for processing.
Timestamp LastProcessed() const;
// The earliest available packet timestamp, or Timestamp::Done.
Timestamp MinPacketTimestamp() const;
// Moves packets from all input streams to the input_set.
void FillInputSet(Timestamp input_timestamp,
InputStreamShardSet* input_set);
// Copies timestamp bounds from all input streams to the input_set.
void FillInputBounds(InputStreamShardSet* input_set);
private:
InputStreamHandler* input_stream_handler_;
std::vector<CollectionItemId> stream_ids_;
Timestamp last_processed_ts_ = Timestamp::Unset();
};
protected:
typedef internal::Collection<InputStreamManager*> InputStreamManagerSet;
const MediaPipeOptions& options() const { return options_; }
// Subclasses must set batch size to greater than 1 to enable batching.
// Batching cannot be combined with late_preparation_ behavior.
void SetBatchSize(int batch_size);
// Subclasses can enable late preparation; however it cannot be used along
// with batching.
void SetLatePreparation(bool late_preparation);
// Accesses InputStreamShard's private method to add packets. All
// InputStreamHandler subclasses are only able to add packets to shards
// through this method.
// TODO: Renames this method to "SetStreamContents" when
// InputStreamShard is renamed.
void AddPacketToShard(InputStreamShard* shard, Packet&& value, bool is_done) {
shard->AddPacket(std::move(value), is_done);
}
// Returns the operation the calculator node is ready for.
// Specifically:
// - NodeReadiness::kNotReady if the node's Process() or Close() cannot be
// called yet. The minimum timestamp bound of the input streams is
// returned in *min_stream_timestamp.
// - NodeReadiness::kReadyForProcess if the node is not waiting for a packet
// on any input stream and is thus "ready" for its Process() to be
// called. For a source node, Timestamp::Done() is returned in
// *min_stream_timestamp. For a non-source node, the input timestamp for
// the Process() call is returned in *min_stream_timestamp.
// - NodeReadiness::kReadyForClose if the node's Close() can be called.
// Timestamp::Done() is returned in *min_stream_timestamp.
virtual NodeReadiness GetNodeReadiness(Timestamp* min_stream_timestamp) = 0;
// Moves input packets from the input streams into the input set for the given
// input timestamp.
virtual void FillInputSet(Timestamp input_timestamp,
InputStreamShardSet* input_set) = 0;
// Collection of InputStreamManager objects.
InputStreamManagerSet input_stream_managers_;
// A pointer to the calculator context manager of the calculator node.
CalculatorContextManager* const calculator_context_manager_;
MediaPipeOptions options_;
const bool calculator_run_in_parallel_;
// Indicates if a calculator context has been prepared for Close().
bool prepared_context_for_close_;
// Note: You must not hold any locks while invoking any of these callbacks.
//
// A callback to notify the observer of the changes on the packet queue or
// the timestamp bound.
std::function<void()> notification_;
// A callback to schedule the node with the prepared calculator context.
std::function<void(CalculatorContext*)> schedule_callback_;
std::function<void(absl::Status)> error_callback_;
private:
// Indicates when to fill the input set. If true, every input set will be
// prepared in FinalizeInputSet(). Otherwise, the input sets will be filled
// in ScheduleInvocations() in the scheduling phase.
// The variable is set to false by default. A subclass should set it to true
// with SetLatePreparation(true) in the constructor if the input sets need to
// be filled in ProcessNode().
bool late_preparation_ = false;
// Determines how many sets of input packets are collected before a
// CalculatorNode is scheduled.
int batch_size_ = 1;
// When true, any increase in timestamp bound invokes Calculator::Process.
bool process_timestamps_ = false;
// A callback to notify the observer when all the input stream headers
// (excluding headers of back edges) become available.
std::function<void()> headers_ready_callback_;
std::atomic<int> unset_header_count_{0};
};
using InputStreamHandlerRegistry = GlobalFactoryRegistry<
std::unique_ptr<InputStreamHandler>, std::shared_ptr<tool::TagMap>,
CalculatorContextManager*, const MediaPipeOptions&, bool>;
} // namespace mediapipe
// Macro for registering the input stream handler.
#define REGISTER_INPUT_STREAM_HANDLER(name) \
REGISTER_FACTORY_FUNCTION_QUALIFIED( \
mediapipe::InputStreamHandlerRegistry, input_handler_registration, name, \
absl::make_unique<name, std::shared_ptr<tool::TagMap>, \
CalculatorContextManager*, const MediaPipeOptions&, \
bool>)
#endif // MEDIAPIPE_FRAMEWORK_INPUT_STREAM_HANDLER_H_