// 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_STATUS_HANDLER_H_ #define MEDIAPIPE_FRAMEWORK_STATUS_HANDLER_H_ #include #include #include "absl/memory/memory.h" #include "mediapipe/framework/deps/registration.h" #include "mediapipe/framework/mediapipe_options.pb.h" #include "mediapipe/framework/packet_set.h" #include "mediapipe/framework/packet_type.h" #include "mediapipe/framework/port.h" #include "mediapipe/framework/port/status.h" namespace mediapipe { // Pure virtual base class for status handlers. // // These classes take any number of input side packet packets and process the // status resulting from a calculator graph run. The status may be OK (if the // graph run was successful), or may indicate the failure of a PacketGenerator // or Calculator. // // IMPORTANT: If a failure of a PacketGenerator results in missing external // inputs that were requested (i.e., input side packets that should have been // generated by a failing PacketGenerator or by a PacketGenerator that had not // yet executed), the affected StatusHandler will be skipped. class StatusHandler { public: StatusHandler(const StatusHandler&) = delete; StatusHandler& operator=(const StatusHandler&) = delete; virtual ~StatusHandler() = 0; // All subclasses of StatusHandler must implement these static functions with // the following signatures: // // static absl::Status FillExpectations( // const MediaPipeOptions& extendable_options, // PacketTypeSet* input_side_packets); // // static absl::Status HandlePreRunStatus( // const MediaPipeOptions& extendable_options, // const PacketSet& input_side_packets, // const absl::Status& pre_run_status); // // static absl::Status HandleStatus( // const MediaPipeOptions& extendable_options, // const PacketSet& input_side_packets, // const absl::Status& run_status); // // FillExpectations() is used to validate the graph and it is analogous to the // function in calculator.h, packet_generator.h, and packet_factory.h. // // HandlePreRunStatus() is executed after CalculatorGraph runs the packet // factories and generators to produce the input side packets, and before it // runs // the calculator graph. Calling HandlePreRunStatus at this point is useful so // that the handlers can record (at the earliest time possible) that we // started a graph run on a specific input. Note that HandlePreRunStatus() // is not run if the graph fails in initialization (even if it fails // due to a PacketGenerator or PacketFactory returning an error). // // HandleStatus() is called after the graph run, so the handler can store the // run result of it. It is not called when the PRE-RUN status is not ok (when // the generation of input side packets fails). // // Subclasses must be registered with // REGISTER_STATUS_HANDLER(MyStatusHandler); }; // Details for the registration of a StatusHandler follow. A user of // StatusHandler does not need to know about the following code; its purpose is // to provide functionality akin to virtual static functions. namespace internal { class StaticAccessToStatusHandler { public: virtual ~StaticAccessToStatusHandler() {} virtual absl::Status FillExpectations( const MediaPipeOptions& extendable_options, PacketTypeSet* input_side_packets) = 0; virtual absl::Status HandlePreRunStatus( const MediaPipeOptions& extendable_options, const PacketSet& input_side_packets, const absl::Status& pre_run_status) = 0; virtual absl::Status HandleStatus(const MediaPipeOptions& extendable_options, const PacketSet& input_side_packets, // const absl::Status& run_status) = 0; }; using StaticAccessToStatusHandlerRegistry = GlobalFactoryRegistry>; // Functions for checking that the StatusHandler has the proper functions // defined. template constexpr bool StatusHandlerHasFillExpectations( decltype(&T::FillExpectations) /* unused */) { typedef absl::Status (*FillExpectationsType)( const MediaPipeOptions& extendable_options, PacketTypeSet* input_side_packets); return std::is_same::value; } template constexpr bool StatusHandlerHasFillExpectations(...) { return false; } template constexpr bool StatusHandlerHasHandlePreRunStatus( decltype(&T::HandlePreRunStatus) /* unused */) { typedef absl::Status (*HandlePreRunStatusType)( const MediaPipeOptions& extendable_options, const PacketSet& input_side_packets, const absl::Status& pre_run_status); return std::is_same::value; } template constexpr bool StatusHandlerHasHandleStatus( decltype(&T::HandleStatus) /* unused */) { typedef absl::Status (*HandleStatusType)( const MediaPipeOptions& extendable_options, const PacketSet& input_side_packets, const absl::Status& run_status); return std::is_same::value; } template constexpr bool StatusHandlerHasHandleStatus(...) { return false; } // Provides access to the static functions within a specific sublcass of // StatusHandler. See the same mechanism in calculator.h for a more detailed // explanation. template class StaticAccessToStatusHandlerTyped : public StaticAccessToStatusHandler { public: static_assert( std::is_base_of::value, "Classes registered with REGISTER_STATUS_HANDLER must be subclasses of " "mediapipe::StatusHandler."); static_assert( StatusHandlerHasFillExpectations(nullptr), "FillExpectations() must be defined with the correct signature in every " "StatusHandler."); static_assert( StatusHandlerHasHandlePreRunStatus(nullptr), "HandlePreRunStatus() must be defined with the correct signature in " "every StatusHandler."); static_assert(StatusHandlerHasHandleStatus(nullptr), "HandleStatus() must be defined with the correct signature in " "every StatusHandler."); absl::Status FillExpectations(const MediaPipeOptions& extendable_options, PacketTypeSet* input_side_packets) final { return StatusHandlerSubclass::FillExpectations(extendable_options, input_side_packets); } absl::Status HandlePreRunStatus(const MediaPipeOptions& extendable_options, const PacketSet& input_side_packets, const absl::Status& pre_run_status) final { return StatusHandlerSubclass::HandlePreRunStatus( extendable_options, input_side_packets, pre_run_status); } absl::Status HandleStatus(const MediaPipeOptions& extendable_options, const PacketSet& input_side_packets, const absl::Status& run_status) final { return StatusHandlerSubclass::HandleStatus(extendable_options, input_side_packets, run_status); } }; } // namespace internal // Macro for registering StatusHandlers. It actually just registers the // StaticAccessToStatusHandlerTyped class. #define REGISTER_STATUS_HANDLER(name) \ REGISTER_FACTORY_FUNCTION_QUALIFIED( \ mediapipe::internal::StaticAccessToStatusHandlerRegistry, \ status_handler_registration, name, \ absl::make_unique< \ mediapipe::internal::StaticAccessToStatusHandlerTyped>) } // namespace mediapipe #endif // MEDIAPIPE_FRAMEWORK_STATUS_HANDLER_H_