// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <vector>
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/port/ret_check.h"
#include "mediapipe/framework/port/status.h"
#include "mediapipe/graphs/instant_motion_tracking/calculators/sticker_buffer.pb.h"
#include "mediapipe/graphs/instant_motion_tracking/calculators/transformations.h"
namespace mediapipe {
constexpr char kProtoDataString[] = "PROTO";
constexpr char kAnchorsTag[] = "ANCHORS";
constexpr char kUserRotationsTag[] = "USER_ROTATIONS";
constexpr char kUserScalingsTag[] = "USER_SCALINGS";
constexpr char kRenderDescriptorsTag[] = "RENDER_DATA";
// This calculator takes in the sticker protobuffer data and parses each
// individual sticker object into anchors, user rotations and scalings, in
// addition to basic render data represented in integer form.
//
// Input:
// PROTO - String of sticker data in appropriate protobuf format [REQUIRED]
// Output:
// ANCHORS - Anchors with initial normalized X,Y coordinates [REQUIRED]
// USER_ROTATIONS - UserRotations with radians of rotation from user [REQUIRED]
// USER_SCALINGS - UserScalings with increment of scaling from user [REQUIRED]
// RENDER_DATA - Descriptors of which objects/animations to render for stickers
// [REQUIRED]
//
// Example config:
// node {
// calculator: "StickerManagerCalculator"
// input_stream: "PROTO:sticker_proto_string"
// output_stream: "ANCHORS:initial_anchor_data"
// output_stream: "USER_ROTATIONS:user_rotation_data"
// output_stream: "USER_SCALINGS:user_scaling_data"
// output_stream: "RENDER_DATA:sticker_render_data"
// }
class StickerManagerCalculator : public CalculatorBase {
public:
static absl::Status GetContract(CalculatorContract* cc) {
RET_CHECK(cc->Inputs().HasTag(kProtoDataString));
RET_CHECK(cc->Outputs().HasTag(kAnchorsTag) &&
cc->Outputs().HasTag(kUserRotationsTag) &&
cc->Outputs().HasTag(kUserScalingsTag) &&
cc->Outputs().HasTag(kRenderDescriptorsTag));
cc->Inputs().Tag(kProtoDataString).Set<std::string>();
cc->Outputs().Tag(kAnchorsTag).Set<std::vector<Anchor>>();
cc->Outputs().Tag(kUserRotationsTag).Set<std::vector<UserRotation>>();
cc->Outputs().Tag(kUserScalingsTag).Set<std::vector<UserScaling>>();
cc->Outputs().Tag(kRenderDescriptorsTag).Set<std::vector<int>>();
return absl::OkStatus();
}
absl::Status Open(CalculatorContext* cc) override {
cc->SetOffset(TimestampDiff(0));
return absl::OkStatus();
}
absl::Status Process(CalculatorContext* cc) override {
std::string sticker_proto_string =
cc->Inputs().Tag(kProtoDataString).Get<std::string>();
std::vector<Anchor> initial_anchor_data;
std::vector<UserRotation> user_rotation_data;
std::vector<UserScaling> user_scaling_data;
std::vector<int> render_data;
::mediapipe::StickerRoll sticker_roll;
bool parse_success = sticker_roll.ParseFromString(sticker_proto_string);
// Ensure parsing was a success
RET_CHECK(parse_success) << "Error parsing sticker protobuf data";
for (int i = 0; i < sticker_roll.sticker().size(); ++i) {
// Declare empty structures for sticker data
Anchor initial_anchor;
UserRotation user_rotation;
UserScaling user_scaling;
// Get individual Sticker object as defined by Protobuffer
::mediapipe::Sticker sticker = sticker_roll.sticker(i);
// Set individual data structure ids to associate with this sticker
initial_anchor.sticker_id = sticker.id();
user_rotation.sticker_id = sticker.id();
user_scaling.sticker_id = sticker.id();
initial_anchor.x = sticker.x();
initial_anchor.y = sticker.y();
initial_anchor.z = 1.0f; // default to 1.0 in normalized 3d space
user_rotation.rotation_radians = sticker.rotation();
user_scaling.scale_factor = sticker.scale();
const int render_id = sticker.render_id();
// Set all vector data with sticker attributes
initial_anchor_data.emplace_back(initial_anchor);
user_rotation_data.emplace_back(user_rotation);
user_scaling_data.emplace_back(user_scaling);
render_data.emplace_back(render_id);
}
if (cc->Outputs().HasTag(kAnchorsTag)) {
cc->Outputs()
.Tag(kAnchorsTag)
.AddPacket(MakePacket<std::vector<Anchor>>(initial_anchor_data)
.At(cc->InputTimestamp()));
}
if (cc->Outputs().HasTag(kUserRotationsTag)) {
cc->Outputs()
.Tag(kUserRotationsTag)
.AddPacket(MakePacket<std::vector<UserRotation>>(user_rotation_data)
.At(cc->InputTimestamp()));
}
if (cc->Outputs().HasTag(kUserScalingsTag)) {
cc->Outputs()
.Tag(kUserScalingsTag)
.AddPacket(MakePacket<std::vector<UserScaling>>(user_scaling_data)
.At(cc->InputTimestamp()));
}
if (cc->Outputs().HasTag(kRenderDescriptorsTag)) {
cc->Outputs()
.Tag(kRenderDescriptorsTag)
.AddPacket(MakePacket<std::vector<int>>(render_data)
.At(cc->InputTimestamp()));
}
return absl::OkStatus();
}
absl::Status Close(CalculatorContext* cc) override {
return absl::OkStatus();
}
};
REGISTER_CALCULATOR(StickerManagerCalculator);
} // namespace mediapipe