Project import generated by Copybara.

GitOrigin-RevId: 53a42bf7ad836321123cb7b6c80b0f2e13fbf83e
This commit is contained in:
MediaPipe Team 2020-04-06 19:10:12 -07:00 committed by jqtang
parent 1722d4b8a2
commit a3d36eee32
127 changed files with 3910 additions and 4783 deletions

View File

@ -12,9 +12,9 @@ build --copt='-Wno-comment'
build --copt='-Wno-return-type' build --copt='-Wno-return-type'
build --copt='-Wno-unused-local-typedefs' build --copt='-Wno-unused-local-typedefs'
build --copt='-Wno-ignored-attributes' build --copt='-Wno-ignored-attributes'
# Temporarily set the incompatibility flag for Bazel 0.27.0 and above
build --incompatible_disable_deprecated_attr_params=false # Tensorflow needs remote repo
build --incompatible_depset_is_not_iterable=false build --experimental_repo_remote_exec
# Sets the default Apple platform to macOS. # Sets the default Apple platform to macOS.
build --apple_platform_type=macos build --apple_platform_type=macos
@ -23,6 +23,10 @@ build --apple_platform_type=macos
build --apple_generate_dsym build --apple_generate_dsym
# Android configs. # Android configs.
# Note: the documentation tells us to use @androidndk//:default_crosstool, but
# the automatic configuration transition uses //external:android/crosstool.
# Using it here works and spares us from having two different config_settings
# for Android.
build:android --crosstool_top=//external:android/crosstool build:android --crosstool_top=//external:android/crosstool
build:android --host_crosstool_top=@bazel_tools//tools/cpp:toolchain build:android --host_crosstool_top=@bazel_tools//tools/cpp:toolchain
build:android --linkopt=-landroid build:android --linkopt=-landroid

View File

@ -48,7 +48,7 @@ RUN pip install future
RUN pip3 install six RUN pip3 install six
# Install bazel # Install bazel
ARG BAZEL_VERSION=1.1.0 ARG BAZEL_VERSION=2.0.0
RUN mkdir /bazel && \ RUN mkdir /bazel && \
wget --no-check-certificate -O /bazel/installer.sh "https://github.com/bazelbuild/bazel/releases/download/${BAZEL_VERSION}/b\ wget --no-check-certificate -O /bazel/installer.sh "https://github.com/bazelbuild/bazel/releases/download/${BAZEL_VERSION}/b\
azel-${BAZEL_VERSION}-installer-linux-x86_64.sh" && \ azel-${BAZEL_VERSION}-installer-linux-x86_64.sh" && \

168
WORKSPACE
View File

@ -2,16 +2,15 @@ workspace(name = "mediapipe")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
skylib_version = "0.8.0" skylib_version = "0.9.0"
http_archive( http_archive(
name = "bazel_skylib", name = "bazel_skylib",
type = "tar.gz", type = "tar.gz",
url = "https://github.com/bazelbuild/bazel-skylib/releases/download/{}/bazel-skylib.{}.tar.gz".format (skylib_version, skylib_version), url = "https://github.com/bazelbuild/bazel-skylib/releases/download/{}/bazel_skylib-{}.tar.gz".format (skylib_version, skylib_version),
sha256 = "2ef429f5d7ce7111263289644d233707dba35e39696377ebab8b0bc701f7818e", sha256 = "1dde365491125a3db70731e25658dfdd3bc5dbdfd11b840b3e987ecf043c7ca0",
) )
load("@bazel_skylib//lib:versions.bzl", "versions") load("@bazel_skylib//lib:versions.bzl", "versions")
versions.check(minimum_bazel_version = "1.0.0", versions.check(minimum_bazel_version = "2.0.0")
maximum_bazel_version = "1.2.1")
# ABSL cpp library lts_2020_02_25 # ABSL cpp library lts_2020_02_25
@ -93,11 +92,13 @@ http_archive(
build_file = "@//third_party:libyuv.BUILD", build_file = "@//third_party:libyuv.BUILD",
) )
# Note: protobuf-javalite is no longer released as a separate download, it's included in the main Java download.
# ...but the Java download is currently broken, so we use the "source" download.
http_archive( http_archive(
name = "com_google_protobuf_javalite", name = "com_google_protobuf_javalite",
sha256 = "79d102c61e2a479a0b7e5fc167bcfaa4832a0c6aad4a75fa7da0480564931bcc", sha256 = "a79d19dcdf9139fa4b81206e318e33d245c4c9da1ffed21c87288ed4380426f9",
strip_prefix = "protobuf-384989534b2246d413dbcd750744faab2607b516", strip_prefix = "protobuf-3.11.4",
urls = ["https://github.com/google/protobuf/archive/384989534b2246d413dbcd750744faab2607b516.zip"], urls = ["https://github.com/protocolbuffers/protobuf/archive/v3.11.4.tar.gz"],
) )
http_archive( http_archive(
@ -117,23 +118,18 @@ http_archive(
], ],
) )
# 2020-02-12 # 2020-04-01
# The last commit before TensorFlow switched to Bazel 2.0 _TENSORFLOW_GIT_COMMIT = "805e47cea96c7e8c6fccf494d40a2392dc99fdd8"
_TENSORFLOW_GIT_COMMIT = "77e9ffb9b2bfb1a4f7056e62d84039626923e328" _TENSORFLOW_SHA256= "9ee3ae604c2e1345ac60345becee6d659364721513f9cb8652eb2e7138320ca5"
_TENSORFLOW_SHA256= "176ccd82f7dd17c5e117b50d353603b129c7a6ccbfebd522ca47cc2a40f33f13"
http_archive( http_archive(
name = "org_tensorflow", name = "org_tensorflow",
urls = [ urls = [
"https://mirror.bazel.build/github.com/tensorflow/tensorflow/archive/%s.tar.gz" % _TENSORFLOW_GIT_COMMIT, "https://mirror.bazel.build/github.com/tensorflow/tensorflow/archive/%s.tar.gz" % _TENSORFLOW_GIT_COMMIT,
"https://github.com/tensorflow/tensorflow/archive/%s.tar.gz" % _TENSORFLOW_GIT_COMMIT, "https://github.com/tensorflow/tensorflow/archive/%s.tar.gz" % _TENSORFLOW_GIT_COMMIT,
], ],
# A compatibility patch
patches = [ patches = [
"@//third_party:org_tensorflow_528e22eae8bf3206189a066032c66e9e5c9b4a61.diff", "@//third_party:org_tensorflow_compatibility_fixes.diff",
# Updates for XNNPACK: https://github.com/tensorflow/tensorflow/commit/cfc31e324c8de6b52f752a39cb161d99d853ca99 "@//third_party:org_tensorflow_protobuf_updates.diff",
"@//third_party:org_tensorflow_cfc31e324c8de6b52f752a39cb161d99d853ca99.diff",
# CpuInfo's build rule fixes.
"@//third_party:org_tensorflow_9696366bcadab23a25c773b3ed405bac8ded4d0d.diff",
], ],
patch_args = [ patch_args = [
"-p1", "-p1",
@ -158,10 +154,6 @@ http_archive(
sha256 = "5ba6d0db4e784621fda44a50c58bb23b0892684692f0c623e2063f9c19f192f1" sha256 = "5ba6d0db4e784621fda44a50c58bb23b0892684692f0c623e2063f9c19f192f1"
) )
# Please run
# $ sudo apt-get install libopencv-core-dev libopencv-highgui-dev \
# libopencv-calib3d-dev libopencv-features2d-dev \
# libopencv-imgproc-dev libopencv-video-dev
new_local_repository( new_local_repository(
name = "linux_opencv", name = "linux_opencv",
build_file = "@//third_party:opencv_linux.BUILD", build_file = "@//third_party:opencv_linux.BUILD",
@ -174,7 +166,6 @@ new_local_repository(
path = "/usr" path = "/usr"
) )
# Please run $ brew install opencv@3
new_local_repository( new_local_repository(
name = "macos_opencv", name = "macos_opencv",
build_file = "@//third_party:opencv_macos.BUILD", build_file = "@//third_party:opencv_macos.BUILD",
@ -207,79 +198,6 @@ http_archive(
url = "https://github.com/opencv/opencv/releases/download/3.2.0/opencv-3.2.0-ios-framework.zip", url = "https://github.com/opencv/opencv/releases/download/3.2.0/opencv-3.2.0-ios-framework.zip",
) )
RULES_JVM_EXTERNAL_TAG = "2.2"
RULES_JVM_EXTERNAL_SHA = "f1203ce04e232ab6fdd81897cf0ff76f2c04c0741424d192f28e65ae752ce2d6"
http_archive(
name = "rules_jvm_external",
strip_prefix = "rules_jvm_external-%s" % RULES_JVM_EXTERNAL_TAG,
sha256 = RULES_JVM_EXTERNAL_SHA,
url = "https://github.com/bazelbuild/rules_jvm_external/archive/%s.zip" % RULES_JVM_EXTERNAL_TAG,
)
load("@rules_jvm_external//:defs.bzl", "maven_install")
maven_install(
artifacts = [
"androidx.annotation:annotation:aar:1.1.0",
"androidx.appcompat:appcompat:aar:1.1.0-rc01",
"androidx.camera:camera-core:aar:1.0.0-alpha06",
"androidx.camera:camera-camera2:aar:1.0.0-alpha06",
"androidx.constraintlayout:constraintlayout:aar:1.1.3",
"androidx.core:core:aar:1.1.0-rc03",
"androidx.legacy:legacy-support-v4:aar:1.0.0",
"androidx.recyclerview:recyclerview:aar:1.1.0-beta02",
"com.google.android.material:material:aar:1.0.0-rc01",
],
repositories = [
"https://dl.google.com/dl/android/maven2",
"https://repo1.maven.org/maven2",
],
)
maven_server(
name = "google_server",
url = "https://dl.google.com/dl/android/maven2",
)
maven_jar(
name = "androidx_lifecycle",
artifact = "androidx.lifecycle:lifecycle-common:2.0.0",
sha1 = "e070ffae07452331bc5684734fce6831d531785c",
server = "google_server",
)
maven_jar(
name = "androidx_concurrent_futures",
artifact = "androidx.concurrent:concurrent-futures:1.0.0-alpha03",
sha1 = "b528df95c7e2fefa2210c0c742bf3e491c1818ae",
server = "google_server",
)
maven_jar(
name = "com_google_guava_android",
artifact = "com.google.guava:guava:27.0.1-android",
sha1 = "b7e1c37f66ef193796ccd7ea6e80c2b05426182d",
)
maven_jar(
name = "com_google_common_flogger",
artifact = "com.google.flogger:flogger:0.3.1",
sha1 = "585030fe1ec709760cbef997a459729fb965df0e",
)
maven_jar(
name = "com_google_common_flogger_system_backend",
artifact = "com.google.flogger:flogger-system-backend:0.3.1",
sha1 = "287b569d76abcd82f9de87fe41829fbc7ebd8ac9",
)
maven_jar(
name = "com_google_code_findbugs",
artifact = "com.google.code.findbugs:jsr305:3.0.2",
sha1 = "25ea2e8b0c338a877313bd4672d3fe056ea78f0d",
)
# You may run setup_android.sh to install Android SDK and NDK. # You may run setup_android.sh to install Android SDK and NDK.
android_ndk_repository( android_ndk_repository(
name = "androidndk", name = "androidndk",
@ -293,9 +211,15 @@ android_sdk_repository(
http_archive( http_archive(
name = "build_bazel_rules_apple", name = "build_bazel_rules_apple",
sha256 = "bdc8e66e70b8a75da23b79f1f8c6207356df07d041d96d2189add7ee0780cf4e", sha256 = "7a7afdd4869bb201c9352eed2daf37294d42b093579b70423490c1b4d4f6ce42",
strip_prefix = "rules_apple-b869b0d3868d78a1d4ffd866ccb304fb68aa12c3", url = "https://github.com/bazelbuild/rules_apple/releases/download/0.19.0/rules_apple.0.19.0.tar.gz",
url = "https://github.com/bazelbuild/rules_apple/archive/b869b0d3868d78a1d4ffd866ccb304fb68aa12c3.tar.gz", patches = [
# Bypass checking ios unit test runner when building MP ios applications.
"@//third_party:build_bazel_rules_apple_bypass_test_runner_check.diff"
],
patch_args = [
"-p1",
],
) )
load( load(
@ -329,3 +253,49 @@ http_archive(
build_file = "@//third_party:google_toolbox_for_mac.BUILD", build_file = "@//third_party:google_toolbox_for_mac.BUILD",
) )
# Maven dependencies.
RULES_JVM_EXTERNAL_TAG = "3.2"
RULES_JVM_EXTERNAL_SHA = "82262ff4223c5fda6fb7ff8bd63db8131b51b413d26eb49e3131037e79e324af"
http_archive(
name = "rules_jvm_external",
strip_prefix = "rules_jvm_external-%s" % RULES_JVM_EXTERNAL_TAG,
sha256 = RULES_JVM_EXTERNAL_SHA,
url = "https://github.com/bazelbuild/rules_jvm_external/archive/%s.zip" % RULES_JVM_EXTERNAL_TAG,
)
load("@rules_jvm_external//:defs.bzl", "maven_install")
# Important: there can only be one maven_install rule. Add new maven deps here.
maven_install(
name = "maven",
artifacts = [
"junit:junit:4.12",
"androidx.test.espresso:espresso-core:3.1.1",
"org.hamcrest:hamcrest-library:1.3",
"androidx.concurrent:concurrent-futures:1.0.0-alpha03",
"androidx.lifecycle:lifecycle-common:2.0.0",
"androidx.annotation:annotation:aar:1.1.0",
"androidx.appcompat:appcompat:aar:1.1.0-rc01",
"androidx.camera:camera-core:aar:1.0.0-alpha06",
"androidx.camera:camera-camera2:aar:1.0.0-alpha06",
"androidx.constraintlayout:constraintlayout:aar:1.1.3",
"androidx.core:core:aar:1.1.0-rc03",
"androidx.legacy:legacy-support-v4:aar:1.0.0",
"androidx.recyclerview:recyclerview:aar:1.1.0-beta02",
"com.google.android.material:material:aar:1.0.0-rc01",
"com.google.code.findbugs:jsr305:3.0.2",
"com.google.flogger:flogger-system-backend:0.3.1",
"com.google.flogger:flogger:0.3.1",
"com.google.guava:guava:27.0.1-android",
],
repositories = [
"https://jcenter.bintray.com",
"https://maven.google.com",
"https://dl.google.com/dl/android/maven2",
"https://repo1.maven.org/maven2",
],
fetch_sources = True,
version_conflict_policy = "pinned",
)

View File

@ -14,6 +14,9 @@
licenses(["notice"]) # Apache 2.0 licenses(["notice"]) # Apache 2.0
# Note: yes, these need to use "//external:android/crosstool", not
# @androidndk//:default_crosstool.
config_setting( config_setting(
name = "android", name = "android",
values = {"crosstool_top": "//external:android/crosstool"}, values = {"crosstool_top": "//external:android/crosstool"},

View File

@ -230,6 +230,7 @@ cc_library(
"//mediapipe/framework:packet", "//mediapipe/framework:packet",
"//mediapipe/framework/formats:detection_cc_proto", "//mediapipe/framework/formats:detection_cc_proto",
"//mediapipe/framework/formats:landmark_cc_proto", "//mediapipe/framework/formats:landmark_cc_proto",
"//mediapipe/framework/formats:matrix",
"//mediapipe/framework/formats:rect_cc_proto", "//mediapipe/framework/formats:rect_cc_proto",
"//mediapipe/framework/port:integral_types", "//mediapipe/framework/port:integral_types",
"//mediapipe/framework/port:ret_check", "//mediapipe/framework/port:ret_check",
@ -257,6 +258,7 @@ cc_library(
"//mediapipe/framework/port:ret_check", "//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"//mediapipe/util:render_data_cc_proto", "//mediapipe/util:render_data_cc_proto",
"@org_tensorflow//tensorflow/lite:framework",
], ],
alwayslink = 1, alwayslink = 1,
) )
@ -779,6 +781,7 @@ cc_library(
"//mediapipe/framework:calculator_framework", "//mediapipe/framework:calculator_framework",
"//mediapipe/framework/formats:landmark_cc_proto", "//mediapipe/framework/formats:landmark_cc_proto",
"//mediapipe/framework/formats:rect_cc_proto", "//mediapipe/framework/formats:rect_cc_proto",
"//mediapipe/framework/formats:matrix",
"//mediapipe/framework/port:ret_check", "//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"//mediapipe/util:resource_util", "//mediapipe/util:resource_util",

View File

@ -18,6 +18,7 @@
#include "mediapipe/framework/formats/detection.pb.h" #include "mediapipe/framework/formats/detection.pb.h"
#include "mediapipe/framework/formats/landmark.pb.h" #include "mediapipe/framework/formats/landmark.pb.h"
#include "mediapipe/framework/formats/matrix.h"
#include "mediapipe/framework/formats/rect.pb.h" #include "mediapipe/framework/formats/rect.pb.h"
namespace mediapipe { namespace mediapipe {
@ -37,4 +38,8 @@ typedef BeginLoopCalculator<std::vector<::mediapipe::Detection>>
BeginLoopDetectionCalculator; BeginLoopDetectionCalculator;
REGISTER_CALCULATOR(BeginLoopDetectionCalculator); REGISTER_CALCULATOR(BeginLoopDetectionCalculator);
// A calculator to process std::vector<Matrix>.
typedef BeginLoopCalculator<std::vector<Matrix>> BeginLoopMatrixCalculator;
REGISTER_CALCULATOR(BeginLoopMatrixCalculator);
} // namespace mediapipe } // namespace mediapipe

View File

@ -20,6 +20,7 @@
#include "mediapipe/framework/formats/landmark.pb.h" #include "mediapipe/framework/formats/landmark.pb.h"
#include "mediapipe/framework/formats/rect.pb.h" #include "mediapipe/framework/formats/rect.pb.h"
#include "mediapipe/util/render_data.pb.h" #include "mediapipe/util/render_data.pb.h"
#include "tensorflow/lite/interpreter.h"
namespace mediapipe { namespace mediapipe {
@ -42,4 +43,7 @@ typedef EndLoopCalculator<std::vector<::mediapipe::ClassificationList>>
EndLoopClassificationListCalculator; EndLoopClassificationListCalculator;
REGISTER_CALCULATOR(EndLoopClassificationListCalculator); REGISTER_CALCULATOR(EndLoopClassificationListCalculator);
typedef EndLoopCalculator<std::vector<TfLiteTensor>> EndLoopTensorCalculator;
REGISTER_CALCULATOR(EndLoopTensorCalculator);
} // namespace mediapipe } // namespace mediapipe

View File

@ -18,6 +18,7 @@
#include "mediapipe/framework/formats/detection.pb.h" #include "mediapipe/framework/formats/detection.pb.h"
#include "mediapipe/framework/formats/landmark.pb.h" #include "mediapipe/framework/formats/landmark.pb.h"
#include "mediapipe/framework/formats/matrix.h"
#include "mediapipe/framework/formats/rect.pb.h" #include "mediapipe/framework/formats/rect.pb.h"
#include "tensorflow/lite/interpreter.h" #include "tensorflow/lite/interpreter.h"
@ -57,6 +58,9 @@ typedef SplitVectorCalculator<::mediapipe::NormalizedRect, false>
SplitNormalizedRectVectorCalculator; SplitNormalizedRectVectorCalculator;
REGISTER_CALCULATOR(SplitNormalizedRectVectorCalculator); REGISTER_CALCULATOR(SplitNormalizedRectVectorCalculator);
typedef SplitVectorCalculator<Matrix, false> SplitMatrixVectorCalculator;
REGISTER_CALCULATOR(SplitMatrixVectorCalculator);
#if !defined(MEDIAPIPE_DISABLE_GL_COMPUTE) #if !defined(MEDIAPIPE_DISABLE_GL_COMPUTE)
typedef SplitVectorCalculator<::tflite::gpu::gl::GlBuffer, true> typedef SplitVectorCalculator<::tflite::gpu::gl::GlBuffer, true>
MovableSplitGlBufferVectorCalculator; MovableSplitGlBufferVectorCalculator;

View File

@ -86,6 +86,14 @@ mediapipe_cc_proto_library(
deps = [":opencv_image_encoder_calculator_proto"], deps = [":opencv_image_encoder_calculator_proto"],
) )
mediapipe_cc_proto_library(
name = "opencv_encoded_image_to_image_frame_calculator_cc_proto",
srcs = ["opencv_encoded_image_to_image_frame_calculator.proto"],
cc_deps = ["//mediapipe/framework:calculator_cc_proto"],
visibility = ["//visibility:public"],
deps = [":opencv_encoded_image_to_image_frame_calculator_proto"],
)
mediapipe_cc_proto_library( mediapipe_cc_proto_library(
name = "mask_overlay_calculator_cc_proto", name = "mask_overlay_calculator_cc_proto",
srcs = ["mask_overlay_calculator.proto"], srcs = ["mask_overlay_calculator.proto"],
@ -172,6 +180,7 @@ cc_library(
srcs = ["opencv_encoded_image_to_image_frame_calculator.cc"], srcs = ["opencv_encoded_image_to_image_frame_calculator.cc"],
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = [ deps = [
":opencv_encoded_image_to_image_frame_calculator_cc_proto",
"//mediapipe/framework:calculator_framework", "//mediapipe/framework:calculator_framework",
"//mediapipe/framework/formats:image_frame_opencv", "//mediapipe/framework/formats:image_frame_opencv",
"//mediapipe/framework/port:opencv_imgcodecs", "//mediapipe/framework/port:opencv_imgcodecs",
@ -557,6 +566,27 @@ proto_library(
deps = ["//mediapipe/framework:calculator_proto"], deps = ["//mediapipe/framework:calculator_proto"],
) )
proto_library(
name = "opencv_encoded_image_to_image_frame_calculator_proto",
srcs = ["opencv_encoded_image_to_image_frame_calculator.proto"],
visibility = ["//visibility:public"],
deps = ["//mediapipe/framework:calculator_proto"],
)
proto_library(
name = "feature_detector_calculator_proto",
srcs = ["feature_detector_calculator.proto"],
deps = ["//mediapipe/framework:calculator_proto"],
)
mediapipe_cc_proto_library(
name = "feature_detector_calculator_cc_proto",
srcs = ["feature_detector_calculator.proto"],
cc_deps = ["//mediapipe/framework:calculator_cc_proto"],
visibility = ["//visibility:public"],
deps = [":feature_detector_calculator_proto"],
)
cc_library( cc_library(
name = "mask_overlay_calculator", name = "mask_overlay_calculator",
srcs = ["mask_overlay_calculator.cc"], srcs = ["mask_overlay_calculator.cc"],
@ -572,3 +602,30 @@ cc_library(
], ],
alwayslink = 1, alwayslink = 1,
) )
cc_library(
name = "feature_detector_calculator",
srcs = ["feature_detector_calculator.cc"],
visibility = ["//mediapipe:__subpackages__"],
deps = [
":feature_detector_calculator_cc_proto",
"//mediapipe/framework:calculator_framework",
"//mediapipe/framework/formats:image_frame",
"//mediapipe/framework/formats:image_frame_opencv",
"//mediapipe/framework/formats:landmark_cc_proto",
"//mediapipe/framework/formats:video_stream_header",
"//mediapipe/framework/port:integral_types",
"//mediapipe/framework/port:logging",
"//mediapipe/framework/port:opencv_core",
"//mediapipe/framework/port:opencv_features2d",
"//mediapipe/framework/port:opencv_imgproc",
"//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status",
"//mediapipe/framework/port:threadpool",
"//mediapipe/framework/tool:options_util",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/synchronization",
"@org_tensorflow//tensorflow/lite:framework",
],
alwayslink = 1,
)

View File

@ -0,0 +1,210 @@
// Copyright 2020 The MediaPipe Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <memory>
#include <vector>
#include "absl/memory/memory.h"
#include "absl/synchronization/blocking_counter.h"
#include "mediapipe/calculators/image/feature_detector_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/formats/image_frame.h"
#include "mediapipe/framework/formats/image_frame_opencv.h"
#include "mediapipe/framework/formats/landmark.pb.h"
#include "mediapipe/framework/formats/video_stream_header.h"
#include "mediapipe/framework/port/integral_types.h"
#include "mediapipe/framework/port/logging.h"
#include "mediapipe/framework/port/opencv_core_inc.h"
#include "mediapipe/framework/port/opencv_features2d_inc.h"
#include "mediapipe/framework/port/opencv_imgproc_inc.h"
#include "mediapipe/framework/port/ret_check.h"
#include "mediapipe/framework/port/status.h"
#include "mediapipe/framework/port/threadpool.h"
#include "mediapipe/framework/tool/options_util.h"
#include "tensorflow/lite/interpreter.h"
namespace mediapipe {
const char kOptionsTag[] = "OPTIONS";
const int kPatchSize = 32;
const int kNumThreads = 16;
// A calculator to apply local feature detection.
// Input stream:
// IMAGE: Input image frame of type ImageFrame from video stream.
// Output streams:
// FEATURES: The detected keypoints from input image as vector<cv::KeyPoint>.
// PATCHES: Optional output the extracted patches as vector<cv::Mat>
class FeatureDetectorCalculator : public CalculatorBase {
public:
~FeatureDetectorCalculator() override = default;
static ::mediapipe::Status GetContract(CalculatorContract* cc);
::mediapipe::Status Open(CalculatorContext* cc) override;
::mediapipe::Status Process(CalculatorContext* cc) override;
private:
FeatureDetectorCalculatorOptions options_;
cv::Ptr<cv::Feature2D> feature_detector_;
std::unique_ptr<::mediapipe::ThreadPool> pool_;
// Create image pyramid based on input image.
void ComputeImagePyramid(const cv::Mat& input_image,
std::vector<cv::Mat>* image_pyramid);
// Extract the patch for single feature with image pyramid.
cv::Mat ExtractPatch(const cv::KeyPoint& feature,
const std::vector<cv::Mat>& image_pyramid);
};
REGISTER_CALCULATOR(FeatureDetectorCalculator);
::mediapipe::Status FeatureDetectorCalculator::GetContract(
CalculatorContract* cc) {
if (cc->Inputs().HasTag("IMAGE")) {
cc->Inputs().Tag("IMAGE").Set<ImageFrame>();
}
if (cc->Outputs().HasTag("FEATURES")) {
cc->Outputs().Tag("FEATURES").Set<std::vector<cv::KeyPoint>>();
}
if (cc->Outputs().HasTag("LANDMARKS")) {
cc->Outputs().Tag("LANDMARKS").Set<NormalizedLandmarkList>();
}
if (cc->Outputs().HasTag("PATCHES")) {
cc->Outputs().Tag("PATCHES").Set<std::vector<TfLiteTensor>>();
}
return ::mediapipe::OkStatus();
}
::mediapipe::Status FeatureDetectorCalculator::Open(CalculatorContext* cc) {
options_ =
tool::RetrieveOptions(cc->Options(), cc->InputSidePackets(), kOptionsTag)
.GetExtension(FeatureDetectorCalculatorOptions::ext);
feature_detector_ = cv::ORB::create(
options_.max_features(), options_.scale_factor(),
options_.pyramid_level(), kPatchSize - 1, 0, 2, cv::ORB::FAST_SCORE);
pool_ = absl::make_unique<::mediapipe::ThreadPool>("ThreadPool", kNumThreads);
pool_->StartWorkers();
return ::mediapipe::OkStatus();
}
::mediapipe::Status FeatureDetectorCalculator::Process(CalculatorContext* cc) {
const Timestamp& timestamp = cc->InputTimestamp();
if (timestamp == Timestamp::PreStream()) {
// Indicator packet.
return ::mediapipe::OkStatus();
}
InputStream* input_frame = &(cc->Inputs().Tag("IMAGE"));
cv::Mat input_view = formats::MatView(&input_frame->Get<ImageFrame>());
cv::Mat grayscale_view;
cv::cvtColor(input_view, grayscale_view, cv::COLOR_RGB2GRAY);
std::vector<cv::KeyPoint> keypoints;
feature_detector_->detect(grayscale_view, keypoints);
if (keypoints.size() > options_.max_features()) {
keypoints.resize(options_.max_features());
}
if (cc->Outputs().HasTag("FEATURES")) {
auto features_ptr = absl::make_unique<std::vector<cv::KeyPoint>>(keypoints);
cc->Outputs().Tag("FEATURES").Add(features_ptr.release(), timestamp);
}
if (cc->Outputs().HasTag("LANDMARKS")) {
auto landmarks_ptr = absl::make_unique<NormalizedLandmarkList>();
for (int j = 0; j < keypoints.size(); ++j) {
auto feature_landmark = landmarks_ptr->add_landmark();
feature_landmark->set_x(keypoints[j].pt.x / grayscale_view.cols);
feature_landmark->set_y(keypoints[j].pt.y / grayscale_view.rows);
}
cc->Outputs().Tag("LANDMARKS").Add(landmarks_ptr.release(), timestamp);
}
if (cc->Outputs().HasTag("PATCHES")) {
std::vector<cv::Mat> image_pyramid;
ComputeImagePyramid(grayscale_view, &image_pyramid);
std::vector<cv::Mat> patch_mat;
patch_mat.resize(keypoints.size());
absl::BlockingCounter counter(keypoints.size());
for (int i = 0; i < keypoints.size(); i++) {
pool_->Schedule(
[this, &image_pyramid, &keypoints, &patch_mat, i, &counter] {
patch_mat[i] = ExtractPatch(keypoints[i], image_pyramid);
counter.DecrementCount();
});
}
counter.Wait();
const int batch_size = options_.max_features();
auto patches = absl::make_unique<std::vector<TfLiteTensor>>();
TfLiteTensor tensor;
tensor.type = kTfLiteFloat32;
tensor.dims = TfLiteIntArrayCreate(4);
tensor.dims->data[0] = batch_size;
tensor.dims->data[1] = kPatchSize;
tensor.dims->data[2] = kPatchSize;
tensor.dims->data[3] = 1;
int num_bytes = batch_size * kPatchSize * kPatchSize * sizeof(float);
tensor.data.data = malloc(num_bytes);
tensor.bytes = num_bytes;
tensor.allocation_type = kTfLiteArenaRw;
float* tensor_buffer = tensor.data.f;
for (int i = 0; i < keypoints.size(); i++) {
for (int j = 0; j < patch_mat[i].rows; ++j) {
for (int k = 0; k < patch_mat[i].cols; ++k) {
*tensor_buffer++ = patch_mat[i].at<uchar>(j, k) / 128.0f - 1.0f;
}
}
}
for (int i = keypoints.size() * kPatchSize * kPatchSize; i < num_bytes / 4;
i++) {
*tensor_buffer++ = 0;
}
patches->emplace_back(tensor);
cc->Outputs().Tag("PATCHES").Add(patches.release(), timestamp);
}
return ::mediapipe::OkStatus();
}
void FeatureDetectorCalculator::ComputeImagePyramid(
const cv::Mat& input_image, std::vector<cv::Mat>* image_pyramid) {
cv::Mat tmp_image = input_image;
cv::Mat src_image = input_image;
for (int i = 0; i < options_.pyramid_level(); ++i) {
image_pyramid->push_back(src_image);
cv::resize(src_image, tmp_image, cv::Size(), 1.0f / options_.scale_factor(),
1.0f / options_.scale_factor());
src_image = tmp_image;
}
}
cv::Mat FeatureDetectorCalculator::ExtractPatch(
const cv::KeyPoint& feature, const std::vector<cv::Mat>& image_pyramid) {
cv::Mat img = image_pyramid[feature.octave];
float scale_factor = 1 / pow(options_.scale_factor(), feature.octave);
cv::Point2f center =
cv::Point2f(feature.pt.x * scale_factor, feature.pt.y * scale_factor);
cv::Mat rot = cv::getRotationMatrix2D(center, feature.angle, 1.0);
rot.at<double>(0, 2) += kPatchSize / 2 - center.x;
rot.at<double>(1, 2) += kPatchSize / 2 - center.y;
cv::Mat cropped_img;
// perform the affine transformation
cv::warpAffine(img, cropped_img, rot, cv::Size(kPatchSize, kPatchSize),
cv::INTER_LINEAR);
return cropped_img;
}
} // namespace mediapipe

View File

@ -0,0 +1,24 @@
// Options for FeatureDetectorCalculator
syntax = "proto2";
package mediapipe;
import "mediapipe/framework/calculator.proto";
message FeatureDetectorCalculatorOptions {
extend CalculatorOptions {
optional FeatureDetectorCalculatorOptions ext = 278741680;
}
// Set to true if output patches, otherwise only output cv::KeyPoint
optional bool output_patch = 1;
// The max number of detected features.
optional int32 max_features = 2 [default = 200];
// The number of pyramid levels.
optional int32 pyramid_level = 3 [default = 4];
// Pyramid decimation ratio.
optional float scale_factor = 4 [default = 1.2];
}

View File

@ -219,8 +219,10 @@ REGISTER_CALCULATOR(ImageCroppingCalculator);
const auto& input_img = cc->Inputs().Tag(kImageTag).Get<ImageFrame>(); const auto& input_img = cc->Inputs().Tag(kImageTag).Get<ImageFrame>();
cv::Mat input_mat = formats::MatView(&input_img); cv::Mat input_mat = formats::MatView(&input_img);
auto [target_width, target_height, rect_center_x, rect_center_y, rotation] = RectSpec specs = GetCropSpecs(cc, input_img.Width(), input_img.Height());
GetCropSpecs(cc, input_img.Width(), input_img.Height()); int target_width = specs.width, target_height = specs.height,
rect_center_x = specs.center_x, rect_center_y = specs.center_y;
float rotation = specs.rotation;
// Get border mode and value for OpenCV. // Get border mode and value for OpenCV.
int border_mode; int border_mode;
@ -403,8 +405,10 @@ void ImageCroppingCalculator::GetOutputDimensions(CalculatorContext* cc,
int src_width, int src_height, int src_width, int src_height,
int* dst_width, int* dst_width,
int* dst_height) { int* dst_height) {
auto [crop_width, crop_height, x_center, y_center, rotation] = RectSpec specs = GetCropSpecs(cc, src_width, src_height);
GetCropSpecs(cc, src_width, src_height); int crop_width = specs.width, crop_height = specs.height,
x_center = specs.center_x, y_center = specs.center_y;
float rotation = specs.rotation;
const float half_width = crop_width / 2.0f; const float half_width = crop_width / 2.0f;
const float half_height = crop_height / 2.0f; const float half_height = crop_height / 2.0f;

View File

@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "mediapipe/calculators/image/opencv_encoded_image_to_image_frame_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h" #include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/formats/image_frame_opencv.h" #include "mediapipe/framework/formats/image_frame_opencv.h"
#include "mediapipe/framework/port/opencv_imgcodecs_inc.h" #include "mediapipe/framework/port/opencv_imgcodecs_inc.h"
@ -34,7 +35,11 @@ namespace mediapipe {
class OpenCvEncodedImageToImageFrameCalculator : public CalculatorBase { class OpenCvEncodedImageToImageFrameCalculator : public CalculatorBase {
public: public:
static ::mediapipe::Status GetContract(CalculatorContract* cc); static ::mediapipe::Status GetContract(CalculatorContract* cc);
::mediapipe::Status Open(CalculatorContext* cc) override;
::mediapipe::Status Process(CalculatorContext* cc) override; ::mediapipe::Status Process(CalculatorContext* cc) override;
private:
mediapipe::OpenCvEncodedImageToImageFrameCalculatorOptions options_;
}; };
::mediapipe::Status OpenCvEncodedImageToImageFrameCalculator::GetContract( ::mediapipe::Status OpenCvEncodedImageToImageFrameCalculator::GetContract(
@ -44,13 +49,29 @@ class OpenCvEncodedImageToImageFrameCalculator : public CalculatorBase {
return ::mediapipe::OkStatus(); return ::mediapipe::OkStatus();
} }
::mediapipe::Status OpenCvEncodedImageToImageFrameCalculator::Open(
CalculatorContext* cc) {
options_ =
cc->Options<mediapipe::OpenCvEncodedImageToImageFrameCalculatorOptions>();
return ::mediapipe::OkStatus();
}
::mediapipe::Status OpenCvEncodedImageToImageFrameCalculator::Process( ::mediapipe::Status OpenCvEncodedImageToImageFrameCalculator::Process(
CalculatorContext* cc) { CalculatorContext* cc) {
const std::string& contents = cc->Inputs().Index(0).Get<std::string>(); const std::string& contents = cc->Inputs().Index(0).Get<std::string>();
const std::vector<char> contents_vector(contents.begin(), contents.end()); const std::vector<char> contents_vector(contents.begin(), contents.end());
cv::Mat decoded_mat = cv::Mat decoded_mat;
cv::imdecode(contents_vector, -1 /* return the loaded image as-is */); if (options_.apply_orientation_from_exif_data()) {
// We want to respect the orientation from the EXIF data, which
// IMREAD_UNCHANGED ignores, but otherwise we want to be as permissive as
// possible with our reading flags. Therefore, we use IMREAD_ANYCOLOR and
// IMREAD_ANYDEPTH.
decoded_mat = cv::imdecode(contents_vector,
cv::IMREAD_ANYCOLOR | cv::IMREAD_ANYDEPTH);
} else {
// Return the loaded image as-is
decoded_mat = cv::imdecode(contents_vector, cv::IMREAD_UNCHANGED);
}
ImageFormat::Format image_format = ImageFormat::UNKNOWN; ImageFormat::Format image_format = ImageFormat::UNKNOWN;
cv::Mat output_mat; cv::Mat output_mat;
switch (decoded_mat.channels()) { switch (decoded_mat.channels()) {
@ -70,7 +91,8 @@ class OpenCvEncodedImageToImageFrameCalculator : public CalculatorBase {
<< "Unsupported number of channels: " << decoded_mat.channels(); << "Unsupported number of channels: " << decoded_mat.channels();
} }
std::unique_ptr<ImageFrame> output_frame = absl::make_unique<ImageFrame>( std::unique_ptr<ImageFrame> output_frame = absl::make_unique<ImageFrame>(
image_format, decoded_mat.size().width, decoded_mat.size().height); image_format, decoded_mat.size().width, decoded_mat.size().height,
ImageFrame::kGlDefaultAlignmentBoundary);
output_mat.copyTo(formats::MatView(output_frame.get())); output_mat.copyTo(formats::MatView(output_frame.get()));
cc->Outputs().Index(0).Add(output_frame.release(), cc->InputTimestamp()); cc->Outputs().Index(0).Add(output_frame.release(), cc->InputTimestamp());
return ::mediapipe::OkStatus(); return ::mediapipe::OkStatus();

View File

@ -0,0 +1,30 @@
// Copyright 2020 The MediaPipe Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
syntax = "proto2";
package mediapipe;
import "mediapipe/framework/calculator.proto";
message OpenCvEncodedImageToImageFrameCalculatorOptions {
extend CalculatorOptions {
optional OpenCvEncodedImageToImageFrameCalculatorOptions ext = 303447308;
}
// If set, we will attempt to automatically apply the orientation specified by
// the image's EXIF data when loading the image. Otherwise, the image data
// will be loaded as-is.
optional bool apply_orientation_from_exif_data = 1 [default = false];
}

View File

@ -51,10 +51,11 @@ static constexpr char kStringSavedModelPath[] = "STRING_SAVED_MODEL_PATH";
#endif #endif
} }
// If options.convert_signature_to_tags() will convert letters to uppercase // If options.convert_signature_to_tags() is set, will convert letters to
// and replace /'s with _'s. If set, this enables the standard SavedModel // uppercase and replace /'s and -'s with _'s. This enables the standard
// classification, regression, and prediction signatures to be used as // SavedModel classification, regression, and prediction signatures to be used
// uppercase INPUTS and OUTPUTS tags for streams. // as uppercase INPUTS and OUTPUTS tags for streams and supports other common
// patterns.
const std::string MaybeConvertSignatureToTag( const std::string MaybeConvertSignatureToTag(
const std::string& name, const std::string& name,
const TensorFlowSessionFromSavedModelCalculatorOptions& options) { const TensorFlowSessionFromSavedModelCalculatorOptions& options) {
@ -64,6 +65,7 @@ const std::string MaybeConvertSignatureToTag(
std::transform(name.begin(), name.end(), output.begin(), std::transform(name.begin(), name.end(), output.begin(),
[](unsigned char c) { return std::toupper(c); }); [](unsigned char c) { return std::toupper(c); });
output = absl::StrReplaceAll(output, {{"/", "_"}}); output = absl::StrReplaceAll(output, {{"/", "_"}});
output = absl::StrReplaceAll(output, {{"-", "_"}});
return output; return output;
} else { } else {
return name; return name;

View File

@ -32,8 +32,8 @@ message TensorFlowSessionFromSavedModelCalculatorOptions {
// The name of the generic signature to load into the mapping from tags to // The name of the generic signature to load into the mapping from tags to
// tensor names. // tensor names.
optional string signature_name = 2 [default = "serving_default"]; optional string signature_name = 2 [default = "serving_default"];
// Whether to convert the signature keys to uppercase and switch /'s to // Whether to convert the signature keys to uppercase as well as switch /'s
// _'s, which enables standard signatures to be used as Tags. // and -'s to _'s, which enables common signatures to be used as Tags.
optional bool convert_signature_to_tags = 3 [default = true]; optional bool convert_signature_to_tags = 3 [default = true];
// If true, saved_model_path can have multiple exported models in // If true, saved_model_path can have multiple exported models in
// subdirectories saved_model_path/%08d and the alphabetically last (i.e., // subdirectories saved_model_path/%08d and the alphabetically last (i.e.,

View File

@ -53,10 +53,11 @@ static constexpr char kStringSavedModelPath[] = "STRING_SAVED_MODEL_PATH";
#endif #endif
} }
// If options.convert_signature_to_tags() will convert letters to uppercase // If options.convert_signature_to_tags() is set, will convert letters to
// and replace /'s with _'s. If set, this enables the standard SavedModel // uppercase and replace /'s and -'s with _'s. This enables the standard
// classification, regression, and prediction signatures to be used as // SavedModel classification, regression, and prediction signatures to be used
// uppercase INPUTS and OUTPUTS tags for streams. // as uppercase INPUTS and OUTPUTS tags for streams and supports other common
// patterns.
const std::string MaybeConvertSignatureToTag( const std::string MaybeConvertSignatureToTag(
const std::string& name, const std::string& name,
const TensorFlowSessionFromSavedModelGeneratorOptions& options) { const TensorFlowSessionFromSavedModelGeneratorOptions& options) {
@ -66,6 +67,7 @@ const std::string MaybeConvertSignatureToTag(
std::transform(name.begin(), name.end(), output.begin(), std::transform(name.begin(), name.end(), output.begin(),
[](unsigned char c) { return std::toupper(c); }); [](unsigned char c) { return std::toupper(c); });
output = absl::StrReplaceAll(output, {{"/", "_"}}); output = absl::StrReplaceAll(output, {{"/", "_"}});
output = absl::StrReplaceAll(output, {{"-", "_"}});
return output; return output;
} else { } else {
return name; return name;

View File

@ -32,8 +32,8 @@ message TensorFlowSessionFromSavedModelGeneratorOptions {
// The name of the generic signature to load into the mapping from tags to // The name of the generic signature to load into the mapping from tags to
// tensor names. // tensor names.
optional string signature_name = 2 [default = "serving_default"]; optional string signature_name = 2 [default = "serving_default"];
// Whether to convert the signature keys to uppercase and switch /'s to // Whether to convert the signature keys to uppercase as well as switch /'s
// _'s, which enables standard signatures to be used as Tags. // and -'s to _'s, which enables common signatures to be used as Tags.
optional bool convert_signature_to_tags = 3 [default = true]; optional bool convert_signature_to_tags = 3 [default = true];
// If true, saved_model_path can have multiple exported models in // If true, saved_model_path can have multiple exported models in
// subdirectories saved_model_path/%08d and the alphabetically last (i.e., // subdirectories saved_model_path/%08d and the alphabetically last (i.e.,

View File

@ -451,7 +451,7 @@ cc_library(
"//mediapipe:android": [ "//mediapipe:android": [
"//mediapipe/util/android/file/base", "//mediapipe/util/android/file/base",
], ],
"//mediapipe:apple": [ "//mediapipe:ios": [
"//mediapipe/util/android/file/base", "//mediapipe/util/android/file/base",
], ],
"//mediapipe:macos": [ "//mediapipe:macos": [

View File

@ -673,7 +673,7 @@ REGISTER_CALCULATOR(TfLiteInferenceCalculator);
const auto& input_indices = interpreter_->inputs(); const auto& input_indices = interpreter_->inputs();
gpu_data_in_.resize(input_indices.size()); gpu_data_in_.resize(input_indices.size());
for (int i = 0; i < input_indices.size(); ++i) { for (int i = 0; i < input_indices.size(); ++i) {
const TfLiteTensor* tensor = interpreter_->tensor(input_indices[0]); const TfLiteTensor* tensor = interpreter_->tensor(input_indices[i]);
gpu_data_in_[i] = absl::make_unique<GPUData>(); gpu_data_in_[i] = absl::make_unique<GPUData>();
gpu_data_in_[i]->elements = 1; gpu_data_in_[i]->elements = 1;
for (int d = 0; d < tensor->dims->size; ++d) { for (int d = 0; d < tensor->dims->size; ++d) {

View File

@ -145,7 +145,7 @@ REGISTER_CALCULATOR(TfLiteTensorsToLandmarksCalculator);
? cc->InputSidePackets().Tag("FLIP_HORIZONTALLY").Get<bool>() ? cc->InputSidePackets().Tag("FLIP_HORIZONTALLY").Get<bool>()
: options_.flip_horizontally(); : options_.flip_horizontally();
flip_horizontally_ = flip_vertically_ =
cc->InputSidePackets().HasTag("FLIP_VERTICALLY") cc->InputSidePackets().HasTag("FLIP_VERTICALLY")
? cc->InputSidePackets().Tag("FLIP_VERTICALLY").Get<bool>() ? cc->InputSidePackets().Tag("FLIP_VERTICALLY").Get<bool>()
: options_.flip_vertically(); : options_.flip_vertically();

View File

@ -15,11 +15,11 @@
#ifndef MEDIAPIPE_CALCULATORS_TFLITE_UTIL_H_ #ifndef MEDIAPIPE_CALCULATORS_TFLITE_UTIL_H_
#define MEDIAPIPE_CALCULATORS_TFLITE_UTIL_H_ #define MEDIAPIPE_CALCULATORS_TFLITE_UTIL_H_
#define RET_CHECK_CALL(call) \ #define RET_CHECK_CALL(call) \
do { \ do { \
const auto status = (call); \ const auto status = (call); \
if (ABSL_PREDICT_FALSE(!status.ok())) \ if (ABSL_PREDICT_FALSE(!status.ok())) \
return ::mediapipe::InternalError(status.error_message()); \ return ::mediapipe::InternalError(status.message()); \
} while (0); } while (0);
#endif // MEDIAPIPE_CALCULATORS_TFLITE_UTIL_H_ #endif // MEDIAPIPE_CALCULATORS_TFLITE_UTIL_H_

View File

@ -321,7 +321,7 @@ cc_library(
"//mediapipe:android": [ "//mediapipe:android": [
"//mediapipe/util/android/file/base", "//mediapipe/util/android/file/base",
], ],
"//mediapipe:apple": [ "//mediapipe:ios": [
"//mediapipe/util/android/file/base", "//mediapipe/util/android/file/base",
], ],
"//mediapipe:macos": [ "//mediapipe:macos": [
@ -349,7 +349,7 @@ cc_library(
"//mediapipe:android": [ "//mediapipe:android": [
"//mediapipe/util/android/file/base", "//mediapipe/util/android/file/base",
], ],
"//mediapipe:apple": [ "//mediapipe:ios": [
"//mediapipe/util/android/file/base", "//mediapipe/util/android/file/base",
], ],
"//mediapipe:macos": [ "//mediapipe:macos": [
@ -926,7 +926,7 @@ cc_library(
"//mediapipe:android": [ "//mediapipe:android": [
"//mediapipe/util/android/file/base", "//mediapipe/util/android/file/base",
], ],
"//mediapipe:apple": [ "//mediapipe:ios": [
"//mediapipe/util/android/file/base", "//mediapipe/util/android/file/base",
], ],
"//mediapipe:macos": [ "//mediapipe:macos": [
@ -971,9 +971,9 @@ cc_library(
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = [ deps = [
"//mediapipe/framework:calculator_framework", "//mediapipe/framework:calculator_framework",
"//mediapipe/framework/port:file_helpers",
"//mediapipe/framework/port:ret_check", "//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"//mediapipe/util:resource_util",
], ],
alwayslink = 1, alwayslink = 1,
) )

View File

@ -55,7 +55,7 @@ size_t RoundUp(size_t n, size_t m) { return ((n + m - 1) / m) * m; } // NOLINT
// When using GPU, this color will become transparent when the calculator // When using GPU, this color will become transparent when the calculator
// merges the annotation overlay with the image frame. As a result, drawing in // merges the annotation overlay with the image frame. As a result, drawing in
// this color is not supported and it should be set to something unlikely used. // this color is not supported and it should be set to something unlikely used.
constexpr int kAnnotationBackgroundColor[] = {100, 101, 102}; constexpr uchar kAnnotationBackgroundColor = 2; // Grayscale value.
} // namespace } // namespace
// A calculator for rendering data on images. // A calculator for rendering data on images.
@ -491,11 +491,9 @@ REGISTER_CALCULATOR(AnnotationOverlayCalculator);
if (format != mediapipe::ImageFormat::SRGBA && if (format != mediapipe::ImageFormat::SRGBA &&
format != mediapipe::ImageFormat::SRGB) format != mediapipe::ImageFormat::SRGB)
RET_CHECK_FAIL() << "Unsupported GPU input format: " << format; RET_CHECK_FAIL() << "Unsupported GPU input format: " << format;
image_mat = absl::make_unique<cv::Mat>(height_, width_, CV_8UC3);
image_mat = absl::make_unique<cv::Mat>( memset(image_mat->data, kAnnotationBackgroundColor,
height_, width_, CV_8UC3, height_ * width_ * image_mat->elemSize());
cv::Scalar(kAnnotationBackgroundColor[0], kAnnotationBackgroundColor[1],
kAnnotationBackgroundColor[2]));
} else { } else {
image_mat = absl::make_unique<cv::Mat>( image_mat = absl::make_unique<cv::Mat>(
options_.canvas_height_px(), options_.canvas_width_px(), CV_8UC3, options_.canvas_height_px(), options_.canvas_width_px(), CV_8UC3,
@ -617,9 +615,9 @@ REGISTER_CALCULATOR(AnnotationOverlayCalculator);
glUniform1i(glGetUniformLocation(program_, "input_frame"), 1); glUniform1i(glGetUniformLocation(program_, "input_frame"), 1);
glUniform1i(glGetUniformLocation(program_, "overlay"), 2); glUniform1i(glGetUniformLocation(program_, "overlay"), 2);
glUniform3f(glGetUniformLocation(program_, "transparent_color"), glUniform3f(glGetUniformLocation(program_, "transparent_color"),
kAnnotationBackgroundColor[0] / 255.0, kAnnotationBackgroundColor / 255.0,
kAnnotationBackgroundColor[1] / 255.0, kAnnotationBackgroundColor / 255.0,
kAnnotationBackgroundColor[2] / 255.0); kAnnotationBackgroundColor / 255.0);
// Init texture for opencv rendered frame. // Init texture for opencv rendered frame.
const auto& input_frame = const auto& input_frame =

View File

@ -128,16 +128,19 @@ REGISTER_CALCULATOR(LabelsToRenderDataCalculator);
} else { } else {
const std::vector<std::string>& label_vector = const std::vector<std::string>& label_vector =
cc->Inputs().Tag("LABELS").Get<std::vector<std::string>>(); cc->Inputs().Tag("LABELS").Get<std::vector<std::string>>();
std::vector<float> score_vector;
if (cc->Inputs().HasTag("SCORES")) {
score_vector = cc->Inputs().Tag("SCORES").Get<std::vector<float>>();
}
CHECK_EQ(label_vector.size(), score_vector.size());
labels.resize(label_vector.size()); labels.resize(label_vector.size());
scores.resize(label_vector.size());
for (int i = 0; i < label_vector.size(); ++i) { for (int i = 0; i < label_vector.size(); ++i) {
labels[i] = label_vector[i]; labels[i] = label_vector[i];
scores[i] = score_vector[i]; }
if (cc->Inputs().HasTag("SCORES")) {
std::vector<float> score_vector =
cc->Inputs().Tag("SCORES").Get<std::vector<float>>();
CHECK_EQ(label_vector.size(), score_vector.size());
scores.resize(label_vector.size());
for (int i = 0; i < label_vector.size(); ++i) {
scores[i] = score_vector[i];
}
} }
} }

View File

@ -16,34 +16,80 @@
#include <string> #include <string>
#include "mediapipe/framework/calculator_framework.h" #include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/port/file_helpers.h"
#include "mediapipe/framework/port/status.h" #include "mediapipe/framework/port/status.h"
#include "mediapipe/util/resource_util.h"
namespace mediapipe { namespace mediapipe {
namespace {
constexpr char kFilePathTag[] = "FILE_PATH";
constexpr char kContentsTag[] = "CONTENTS";
} // namespace
// The calculator takes the path to the local file as an input side packet and // The calculator takes the path to the local file as an input side packet and
// outputs the contents of that file. // outputs the contents of that file.
// //
// NOTE: file loading can be batched by providing multiple input/output side
// packets.
//
// Example config: // Example config:
// node { // node {
// calculator: "LocalFileContentsCalculator" // calculator: "LocalFileContentsCalculator"
// input_side_packet: "FILE_PATH:file_path" // input_side_packet: "FILE_PATH:file_path"
// output_side_packet: "CONTENTS:contents" // output_side_packet: "CONTENTS:contents"
// } // }
//
// node {
// calculator: "LocalFileContentsCalculator"
// input_side_packet: "FILE_PATH:0:file_path1"
// input_side_packet: "FILE_PATH:1:file_path2"
// ...
// output_side_packet: "CONTENTS:0:contents1"
// output_side_packet: "CONTENTS:1:contents2"
// ...
// }
class LocalFileContentsCalculator : public CalculatorBase { class LocalFileContentsCalculator : public CalculatorBase {
public: public:
static ::mediapipe::Status GetContract(CalculatorContract* cc) { static ::mediapipe::Status GetContract(CalculatorContract* cc) {
cc->InputSidePackets().Tag("FILE_PATH").Set<std::string>(); RET_CHECK(cc->InputSidePackets().HasTag(kFilePathTag))
cc->OutputSidePackets().Tag("CONTENTS").Set<std::string>(); << "Missing PATH input side packet(s)";
RET_CHECK(cc->OutputSidePackets().HasTag(kContentsTag))
<< "Missing CONTENTS output side packet(s)";
RET_CHECK_EQ(cc->InputSidePackets().NumEntries(kFilePathTag),
cc->OutputSidePackets().NumEntries(kContentsTag))
<< "Same number of input streams and output streams is required.";
for (CollectionItemId id = cc->InputSidePackets().BeginId(kFilePathTag);
id != cc->InputSidePackets().EndId(kFilePathTag); ++id) {
cc->InputSidePackets().Get(id).Set<std::string>();
}
for (CollectionItemId id = cc->OutputSidePackets().BeginId(kContentsTag);
id != cc->OutputSidePackets().EndId(kContentsTag); ++id) {
cc->OutputSidePackets().Get(id).Set<std::string>();
}
return ::mediapipe::OkStatus(); return ::mediapipe::OkStatus();
} }
::mediapipe::Status Open(CalculatorContext* cc) override { ::mediapipe::Status Open(CalculatorContext* cc) override {
std::string contents; CollectionItemId input_id = cc->InputSidePackets().BeginId(kFilePathTag);
MP_RETURN_IF_ERROR(mediapipe::file::GetContents( CollectionItemId output_id = cc->OutputSidePackets().BeginId(kContentsTag);
cc->InputSidePackets().Tag("FILE_PATH").Get<std::string>(), &contents)); // Number of inputs and outpus is the same according to the contract.
cc->OutputSidePackets() for (; input_id != cc->InputSidePackets().EndId(kFilePathTag);
.Tag("CONTENTS") ++input_id, ++output_id) {
.Set(MakePacket<std::string>(std::move(contents))); std::string file_path =
cc->InputSidePackets().Get(input_id).Get<std::string>();
ASSIGN_OR_RETURN(file_path, PathToResourceAsFile(file_path));
std::string contents;
MP_RETURN_IF_ERROR(GetResourceContents(file_path, &contents));
cc->OutputSidePackets().Get(output_id).Set(
MakePacket<std::string>(std::move(contents)));
}
return ::mediapipe::OkStatus(); return ::mediapipe::OkStatus();
} }

View File

@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include <algorithm>
#include "absl/memory/memory.h" #include "absl/memory/memory.h"
#include "absl/strings/str_cat.h" #include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h" #include "absl/strings/str_join.h"
@ -76,14 +78,16 @@ void AddTimedBoxProtoToRenderData(
RenderAnnotation::Text* text = label_annotation->mutable_text(); RenderAnnotation::Text* text = label_annotation->mutable_text();
text->set_display_text(box_proto.label()); text->set_display_text(box_proto.label());
text->set_normalized(true); text->set_normalized(true);
constexpr float text_left_start = 0.3f; constexpr float text_left_start = 0.2f;
text->set_left((1.0f - text_left_start) * box_proto.left() + text->set_left((1.0f - text_left_start) * box_proto.left() +
text_left_start * box_proto.right()); text_left_start * box_proto.right());
constexpr float text_baseline = 0.6f; constexpr float text_baseline = 0.6f;
text->set_baseline(text_baseline * box_proto.bottom() + text->set_baseline(text_baseline * box_proto.bottom() +
(1.0f - text_baseline) * box_proto.top()); (1.0f - text_baseline) * box_proto.top());
constexpr float text_height = 0.2f; constexpr float text_height = 0.1f;
text->set_font_height((box_proto.bottom() - box_proto.top()) * text_height); text->set_font_height(std::min(box_proto.bottom() - box_proto.top(),
box_proto.right() - box_proto.left()) *
text_height);
} }
} }

View File

@ -65,6 +65,26 @@ proto_library(
], ],
) )
proto_library(
name = "tracked_detection_manager_calculator_proto",
srcs = ["tracked_detection_manager_calculator.proto"],
visibility = ["//visibility:public"],
deps = [
"//mediapipe/framework:calculator_proto",
"//mediapipe/util/tracking:tracked_detection_manager_config_proto",
],
)
proto_library(
name = "box_detector_calculator_proto",
srcs = ["box_detector_calculator.proto"],
visibility = ["//visibility:public"],
deps = [
"//mediapipe/framework:calculator_proto",
"//mediapipe/util/tracking:box_detector_proto",
],
)
proto_library( proto_library(
name = "video_pre_stream_calculator_proto", name = "video_pre_stream_calculator_proto",
srcs = ["video_pre_stream_calculator.proto"], srcs = ["video_pre_stream_calculator.proto"],
@ -107,6 +127,28 @@ mediapipe_cc_proto_library(
deps = [":box_tracker_calculator_proto"], deps = [":box_tracker_calculator_proto"],
) )
mediapipe_cc_proto_library(
name = "tracked_detection_manager_calculator_cc_proto",
srcs = ["tracked_detection_manager_calculator.proto"],
cc_deps = [
"//mediapipe/framework:calculator_cc_proto",
"//mediapipe/util/tracking:tracked_detection_manager_config_cc_proto",
],
visibility = ["//visibility:public"],
deps = [":tracked_detection_manager_calculator_proto"],
)
mediapipe_cc_proto_library(
name = "box_detector_calculator_cc_proto",
srcs = ["box_detector_calculator.proto"],
cc_deps = [
"//mediapipe/framework:calculator_cc_proto",
"//mediapipe/util/tracking:box_detector_cc_proto",
],
visibility = ["//visibility:public"],
deps = [":box_detector_calculator_proto"],
)
mediapipe_cc_proto_library( mediapipe_cc_proto_library(
name = "video_pre_stream_calculator_cc_proto", name = "video_pre_stream_calculator_cc_proto",
srcs = ["video_pre_stream_calculator.proto"], srcs = ["video_pre_stream_calculator.proto"],
@ -279,11 +321,54 @@ cc_library(
alwayslink = 1, alwayslink = 1,
) )
cc_library(
name = "box_detector_calculator",
srcs = ["box_detector_calculator.cc"],
visibility = ["//visibility:public"],
deps = [
":box_detector_calculator_cc_proto",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/strings",
"//mediapipe/framework:calculator_framework",
"//mediapipe/framework/formats:image_frame",
"//mediapipe/framework/formats:image_frame_opencv",
"//mediapipe/framework/formats:video_stream_header", # fixdeps: keep -- required for exobazel build.
"//mediapipe/framework/port:integral_types",
"//mediapipe/framework/port:logging",
"//mediapipe/framework/port:opencv_core",
"//mediapipe/framework/port:opencv_features2d",
"//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:status",
"//mediapipe/util:resource_util",
"//mediapipe/util/tracking",
"//mediapipe/util/tracking:box_detector",
"//mediapipe/util/tracking:box_tracker",
"//mediapipe/util/tracking:box_tracker_cc_proto",
"//mediapipe/util/tracking:flow_packager_cc_proto",
"//mediapipe/util/tracking:tracking_visualization_utilities",
] + select({
"//mediapipe:android": [
"//mediapipe/util/android/file/base",
],
"//mediapipe:ios": [
"//mediapipe/util/android/file/base",
],
"//mediapipe:macos": [
"//mediapipe/framework/port:file_helpers",
],
"//conditions:default": [
"//mediapipe/framework/port:file_helpers",
],
}),
alwayslink = 1,
)
cc_library( cc_library(
name = "tracked_detection_manager_calculator", name = "tracked_detection_manager_calculator",
srcs = ["tracked_detection_manager_calculator.cc"], srcs = ["tracked_detection_manager_calculator.cc"],
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = [ deps = [
":tracked_detection_manager_calculator_cc_proto",
"//mediapipe/framework:calculator_framework", "//mediapipe/framework:calculator_framework",
"//mediapipe/framework/formats:detection_cc_proto", "//mediapipe/framework/formats:detection_cc_proto",
"//mediapipe/framework/formats:location_data_cc_proto", "//mediapipe/framework/formats:location_data_cc_proto",

View File

@ -0,0 +1,393 @@
// Copyright 2019 The MediaPipe Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdio.h>
#include <memory>
#include <unordered_set>
#include "absl/memory/memory.h"
#include "absl/strings/numbers.h"
#include "mediapipe/calculators/video/box_detector_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/formats/image_frame.h"
#include "mediapipe/framework/formats/image_frame_opencv.h"
#include "mediapipe/framework/formats/video_stream_header.h"
#include "mediapipe/framework/port/integral_types.h"
#include "mediapipe/framework/port/logging.h"
#include "mediapipe/framework/port/opencv_core_inc.h"
#include "mediapipe/framework/port/opencv_features2d_inc.h"
#include "mediapipe/framework/port/ret_check.h"
#include "mediapipe/framework/port/status.h"
#include "mediapipe/util/resource_util.h"
#include "mediapipe/util/tracking/box_detector.h"
#include "mediapipe/util/tracking/box_tracker.h"
#include "mediapipe/util/tracking/box_tracker.pb.h"
#include "mediapipe/util/tracking/flow_packager.pb.h"
#include "mediapipe/util/tracking/tracking.h"
#include "mediapipe/util/tracking/tracking_visualization_utilities.h"
#if defined(MEDIAPIPE_MOBILE)
#include "mediapipe/util/android/file/base/file.h"
#include "mediapipe/util/android/file/base/helpers.h"
#else
#include "mediapipe/framework/port/file_helpers.h"
#endif
namespace mediapipe {
// A calculator to detect reappeared box positions from single frame.
//
// Input stream:
// TRACKING: Input tracking data (proto TrackingData) containing features and
// descriptors.
// VIDEO: Optional input video stream tracked boxes are rendered over
// (Required if VIZ is specified).
// FEATURES: Input feature points (std::vector<cv::KeyPoint>) in the original
// pixel space.
// DESCRIPTORS: Input feature descriptors (std::vector<float>). Actual feature
// dimension needs to be specified in detector_options.
// IMAGE_SIZE: Input image dimension.
// TRACKED_BOXES : input box tracking result (proto TimedBoxProtoList) from
// BoxTrackerCalculator.
// ADD_INDEX: Optional std::string containing binary format proto of type
// BoxDetectorIndex. Used for adding target index to the detector
// search index during runtime.
// CANCEL_OBJECT_ID: Optional id of box to be removed. This is recommended
// to be used with SyncSetInputStreamHandler.
// REACQ_SWITCH: Optional bool for swithcing on and off reacquisition
// functionality. User should initialize a graph with box detector
// calculator and be able to switch it on and off in runtime.
//
// Output streams:
// VIZ: Optional output video stream with rendered box positions
// (requires VIDEO to be present)
// BOXES: Optional output stream of type TimedBoxProtoList for each lost box.
//
// Imput side packets:
// INDEX_PROTO_STRING: Optional std::string containing binary format proto of
// type
// BoxDetectorIndex. Used for initializing box_detector
// with predefined template images.
// FRAME_ALIGNMENT: Optional integer to indicate alignment_boundary for
// outputing ImageFrame in "VIZ" stream.
// Set to ImageFrame::kDefaultAlignmentBoundary for
// offline pipeline to be compatible with FFmpeg.
// Set to ImageFrame::kGlDefaultAlignmentBoundary for Apps
// to be compatible with GL renderer.
// OUTPUT_INDEX_FILENAME: File path to the output index file.
class BoxDetectorCalculator : public CalculatorBase {
public:
~BoxDetectorCalculator() override = default;
static ::mediapipe::Status GetContract(CalculatorContract* cc);
::mediapipe::Status Open(CalculatorContext* cc) override;
::mediapipe::Status Process(CalculatorContext* cc) override;
::mediapipe::Status Close(CalculatorContext* cc) override;
private:
BoxDetectorCalculatorOptions options_;
std::unique_ptr<BoxDetectorInterface> box_detector_;
bool detector_switch_ = true;
uint32 frame_alignment_ = ImageFrame::kDefaultAlignmentBoundary;
bool write_index_ = false;
int box_id_ = 0;
};
REGISTER_CALCULATOR(BoxDetectorCalculator);
::mediapipe::Status BoxDetectorCalculator::GetContract(CalculatorContract* cc) {
if (cc->Inputs().HasTag("TRACKING")) {
cc->Inputs().Tag("TRACKING").Set<TrackingData>();
}
if (cc->Inputs().HasTag("TRACKED_BOXES")) {
cc->Inputs().Tag("TRACKED_BOXES").Set<TimedBoxProtoList>();
}
if (cc->Inputs().HasTag("VIDEO")) {
cc->Inputs().Tag("VIDEO").Set<ImageFrame>();
}
if (cc->Inputs().HasTag("FEATURES")) {
RET_CHECK(cc->Inputs().HasTag("DESCRIPTORS"))
<< "FEATURES and DESCRIPTORS need to be specified together.";
cc->Inputs().Tag("FEATURES").Set<std::vector<cv::KeyPoint>>();
}
if (cc->Inputs().HasTag("DESCRIPTORS")) {
RET_CHECK(cc->Inputs().HasTag("FEATURES"))
<< "FEATURES and DESCRIPTORS need to be specified together.";
cc->Inputs().Tag("DESCRIPTORS").Set<std::vector<float>>();
}
if (cc->Inputs().HasTag("IMAGE_SIZE")) {
cc->Inputs().Tag("IMAGE_SIZE").Set<std::pair<int, int>>();
}
if (cc->Inputs().HasTag("ADD_INDEX")) {
cc->Inputs().Tag("ADD_INDEX").Set<std::string>();
}
if (cc->Inputs().HasTag("CANCEL_OBJECT_ID")) {
cc->Inputs().Tag("CANCEL_OBJECT_ID").Set<int>();
}
if (cc->Inputs().HasTag("REACQ_SWITCH")) {
cc->Inputs().Tag("REACQ_SWITCH").Set<bool>();
}
if (cc->Outputs().HasTag("BOXES")) {
cc->Outputs().Tag("BOXES").Set<TimedBoxProtoList>();
}
if (cc->Outputs().HasTag("VIZ")) {
RET_CHECK(cc->Inputs().HasTag("VIDEO"))
<< "Output stream VIZ requires VIDEO to be present.";
cc->Outputs().Tag("VIZ").Set<ImageFrame>();
}
if (cc->InputSidePackets().HasTag("INDEX_PROTO_STRING")) {
cc->InputSidePackets().Tag("INDEX_PROTO_STRING").Set<std::string>();
}
if (cc->InputSidePackets().HasTag("OUTPUT_INDEX_FILENAME")) {
cc->InputSidePackets().Tag("OUTPUT_INDEX_FILENAME").Set<std::string>();
}
if (cc->InputSidePackets().HasTag("FRAME_ALIGNMENT")) {
cc->InputSidePackets().Tag("FRAME_ALIGNMENT").Set<int>();
}
return ::mediapipe::OkStatus();
}
::mediapipe::Status BoxDetectorCalculator::Open(CalculatorContext* cc) {
options_ = cc->Options<BoxDetectorCalculatorOptions>();
box_detector_ = BoxDetectorInterface::Create(options_.detector_options());
if (cc->InputSidePackets().HasTag("INDEX_PROTO_STRING")) {
BoxDetectorIndex predefined_index;
if (!predefined_index.ParseFromString(cc->InputSidePackets()
.Tag("INDEX_PROTO_STRING")
.Get<std::string>())) {
LOG(FATAL) << "failed to parse BoxDetectorIndex from INDEX_PROTO_STRING";
}
box_detector_->AddBoxDetectorIndex(predefined_index);
}
for (const auto& filename : options_.index_proto_filename()) {
std::string string_path;
ASSIGN_OR_RETURN(string_path, PathToResourceAsFile(filename));
std::string index_string;
MP_RETURN_IF_ERROR(file::GetContents(string_path, &index_string));
BoxDetectorIndex predefined_index;
if (!predefined_index.ParseFromString(index_string)) {
LOG(FATAL)
<< "failed to parse BoxDetectorIndex from index_proto_filename";
}
box_detector_->AddBoxDetectorIndex(predefined_index);
}
if (cc->InputSidePackets().HasTag("OUTPUT_INDEX_FILENAME")) {
write_index_ = true;
}
if (cc->InputSidePackets().HasTag("FRAME_ALIGNMENT")) {
frame_alignment_ = cc->InputSidePackets().Tag("FRAME_ALIGNMENT").Get<int>();
}
return ::mediapipe::OkStatus();
}
::mediapipe::Status BoxDetectorCalculator::Process(CalculatorContext* cc) {
const Timestamp timestamp = cc->InputTimestamp();
const int64 timestamp_msec = timestamp.Value() / 1000;
InputStream* cancel_object_id_stream =
cc->Inputs().HasTag("CANCEL_OBJECT_ID")
? &(cc->Inputs().Tag("CANCEL_OBJECT_ID"))
: nullptr;
if (cancel_object_id_stream && !cancel_object_id_stream->IsEmpty()) {
const int cancel_object_id = cancel_object_id_stream->Get<int>();
box_detector_->CancelBoxDetection(cancel_object_id);
}
InputStream* add_index_stream = cc->Inputs().HasTag("ADD_INDEX")
? &(cc->Inputs().Tag("ADD_INDEX"))
: nullptr;
if (add_index_stream && !add_index_stream->IsEmpty()) {
BoxDetectorIndex predefined_index;
if (!predefined_index.ParseFromString(
add_index_stream->Get<std::string>())) {
LOG(FATAL) << "failed to parse BoxDetectorIndex from ADD_INDEX";
}
box_detector_->AddBoxDetectorIndex(predefined_index);
}
InputStream* reacq_switch_stream = cc->Inputs().HasTag("REACQ_SWITCH")
? &(cc->Inputs().Tag("REACQ_SWITCH"))
: nullptr;
if (reacq_switch_stream && !reacq_switch_stream->IsEmpty()) {
detector_switch_ = reacq_switch_stream->Get<bool>();
}
if (!detector_switch_) {
return ::mediapipe::OkStatus();
}
InputStream* track_stream = cc->Inputs().HasTag("TRACKING")
? &(cc->Inputs().Tag("TRACKING"))
: nullptr;
InputStream* video_stream =
cc->Inputs().HasTag("VIDEO") ? &(cc->Inputs().Tag("VIDEO")) : nullptr;
InputStream* feature_stream = cc->Inputs().HasTag("FEATURES")
? &(cc->Inputs().Tag("FEATURES"))
: nullptr;
InputStream* descriptor_stream = cc->Inputs().HasTag("DESCRIPTORS")
? &(cc->Inputs().Tag("DESCRIPTORS"))
: nullptr;
CHECK(track_stream != nullptr || video_stream != nullptr ||
(feature_stream != nullptr && descriptor_stream != nullptr))
<< "One and only one of {tracking_data, input image frame, "
"feature/descriptor} need to be valid.";
InputStream* tracked_boxes_stream = cc->Inputs().HasTag("TRACKED_BOXES")
? &(cc->Inputs().Tag("TRACKED_BOXES"))
: nullptr;
std::unique_ptr<TimedBoxProtoList> detected_boxes(new TimedBoxProtoList());
if (track_stream != nullptr) {
// Detect from tracking data
if (track_stream->IsEmpty()) {
return ::mediapipe::OkStatus();
}
const TrackingData& tracking_data = track_stream->Get<TrackingData>();
CHECK(tracked_boxes_stream != nullptr) << "tracked_boxes needed.";
const TimedBoxProtoList tracked_boxes =
tracked_boxes_stream->Get<TimedBoxProtoList>();
box_detector_->DetectAndAddBox(tracking_data, tracked_boxes, timestamp_msec,
detected_boxes.get());
} else if (video_stream != nullptr) {
// Detect from input frame
if (video_stream->IsEmpty()) {
return ::mediapipe::OkStatus();
}
TimedBoxProtoList tracked_boxes;
if (tracked_boxes_stream != nullptr && !tracked_boxes_stream->IsEmpty()) {
tracked_boxes = tracked_boxes_stream->Get<TimedBoxProtoList>();
}
// Just directly pass along the image frame data as-is for detection; we
// don't need to worry about conforming to a specific alignment here.
const cv::Mat input_view =
formats::MatView(&video_stream->Get<ImageFrame>());
box_detector_->DetectAndAddBox(input_view, tracked_boxes, timestamp_msec,
detected_boxes.get());
} else {
if (feature_stream->IsEmpty() || descriptor_stream->IsEmpty()) {
return ::mediapipe::OkStatus();
}
const auto& image_size =
cc->Inputs().Tag("IMAGE_SIZE").Get<std::pair<int, int>>();
float inv_scale = 1.0f / std::max(image_size.first, image_size.second);
TimedBoxProtoList tracked_boxes;
if (tracked_boxes_stream != nullptr && !tracked_boxes_stream->IsEmpty()) {
tracked_boxes = tracked_boxes_stream->Get<TimedBoxProtoList>();
} else if (write_index_) {
auto* box_ptr = tracked_boxes.add_box();
box_ptr->set_id(box_id_);
box_ptr->set_reacquisition(true);
box_ptr->set_aspect_ratio((float)image_size.first /
(float)image_size.second);
box_ptr->mutable_quad()->add_vertices(0);
box_ptr->mutable_quad()->add_vertices(0);
box_ptr->mutable_quad()->add_vertices(0);
box_ptr->mutable_quad()->add_vertices(1);
box_ptr->mutable_quad()->add_vertices(1);
box_ptr->mutable_quad()->add_vertices(1);
box_ptr->mutable_quad()->add_vertices(1);
box_ptr->mutable_quad()->add_vertices(0);
++box_id_;
}
const auto& features = feature_stream->Get<std::vector<cv::KeyPoint>>();
const int feature_size = features.size();
std::vector<Vector2_f> features_vec(feature_size);
const auto& descriptors = descriptor_stream->Get<std::vector<float>>();
const int dims = options_.detector_options().descriptor_dims();
CHECK_GE(descriptors.size(), feature_size * dims);
cv::Mat descriptors_mat(feature_size, dims, CV_32F);
for (int j = 0; j < feature_size; ++j) {
features_vec[j].Set(features[j].pt.x * inv_scale,
features[j].pt.y * inv_scale);
for (int i = 0; i < dims; ++i) {
descriptors_mat.at<float>(j, i) = descriptors[j * dims + i];
}
}
box_detector_->DetectAndAddBoxFromFeatures(
features_vec, descriptors_mat, tracked_boxes, timestamp_msec,
image_size.first * inv_scale, image_size.second * inv_scale,
detected_boxes.get());
}
if (cc->Outputs().HasTag("VIZ")) {
cv::Mat viz_view;
std::unique_ptr<ImageFrame> viz_frame;
if (video_stream != nullptr && !video_stream->IsEmpty()) {
viz_frame = absl::make_unique<ImageFrame>();
viz_frame->CopyFrom(video_stream->Get<ImageFrame>(), frame_alignment_);
viz_view = formats::MatView(viz_frame.get());
}
for (const auto& box : detected_boxes->box()) {
RenderBox(box, &viz_view);
}
cc->Outputs().Tag("VIZ").Add(viz_frame.release(), timestamp);
}
if (cc->Outputs().HasTag("BOXES")) {
cc->Outputs().Tag("BOXES").Add(detected_boxes.release(), timestamp);
}
return ::mediapipe::OkStatus();
}
::mediapipe::Status BoxDetectorCalculator::Close(CalculatorContext* cc) {
if (write_index_) {
BoxDetectorIndex index = box_detector_->ObtainBoxDetectorIndex();
MEDIAPIPE_CHECK_OK(mediapipe::file::SetContents(
cc->InputSidePackets().Tag("OUTPUT_INDEX_FILENAME").Get<std::string>(),
index.SerializeAsString()));
}
return ::mediapipe::OkStatus();
}
} // namespace mediapipe

View File

@ -0,0 +1,31 @@
// Copyright 2019 The MediaPipe Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
syntax = "proto2";
package mediapipe;
import "mediapipe/framework/calculator.proto";
import "mediapipe/util/tracking/box_detector.proto";
message BoxDetectorCalculatorOptions {
extend CalculatorOptions {
optional BoxDetectorCalculatorOptions ext = 289746530;
}
optional BoxDetectorOptions detector_options = 1;
// File path to the template index files.
repeated string index_proto_filename = 2;
}

View File

@ -18,6 +18,7 @@
#include <vector> #include <vector>
#include "absl/container/node_hash_map.h" #include "absl/container/node_hash_map.h"
#include "mediapipe/calculators/video/tracked_detection_manager_calculator.pb.h"
#include "mediapipe/framework/calculator_framework.h" #include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/formats/detection.pb.h" #include "mediapipe/framework/formats/detection.pb.h"
#include "mediapipe/framework/formats/location_data.pb.h" #include "mediapipe/framework/formats/location_data.pb.h"
@ -139,6 +140,7 @@ Detection GetAxisAlignedDetectionFromTrackedDetection(
class TrackedDetectionManagerCalculator : public CalculatorBase { class TrackedDetectionManagerCalculator : public CalculatorBase {
public: public:
static ::mediapipe::Status GetContract(CalculatorContract* cc); static ::mediapipe::Status GetContract(CalculatorContract* cc);
::mediapipe::Status Open(CalculatorContext* cc) override;
::mediapipe::Status Process(CalculatorContext* cc) override; ::mediapipe::Status Process(CalculatorContext* cc) override;
@ -184,6 +186,15 @@ REGISTER_CALCULATOR(TrackedDetectionManagerCalculator);
return ::mediapipe::OkStatus(); return ::mediapipe::OkStatus();
} }
::mediapipe::Status TrackedDetectionManagerCalculator::Open(
CalculatorContext* cc) {
mediapipe::TrackedDetectionManagerCalculatorOptions options =
cc->Options<mediapipe::TrackedDetectionManagerCalculatorOptions>();
tracked_detection_manager_.SetConfig(
options.tracked_detection_manager_options());
return ::mediapipe::OkStatus();
}
::mediapipe::Status TrackedDetectionManagerCalculator::Process( ::mediapipe::Status TrackedDetectionManagerCalculator::Process(
CalculatorContext* cc) { CalculatorContext* cc) {
if (cc->Inputs().HasTag("TRACKING_BOXES")) { if (cc->Inputs().HasTag("TRACKING_BOXES")) {

View File

@ -0,0 +1,28 @@
// Copyright 2020 The MediaPipe Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
syntax = "proto2";
package mediapipe;
import "mediapipe/framework/calculator.proto";
import "mediapipe/util/tracking/tracked_detection_manager_config.proto";
message TrackedDetectionManagerCalculatorOptions {
extend CalculatorOptions {
optional TrackedDetectionManagerCalculatorOptions ext = 301970230;
}
optional TrackedDetectionManagerConfig tracked_detection_manager_options = 1;
}

View File

@ -51,7 +51,7 @@ To build and run the TensorFlow Lite example on desktop (GPU) with Webcam, run:
```bash ```bash
# Video from webcam running on desktop GPU # Video from webcam running on desktop GPU
# This works only for linux currently # This works only for linux currently
$ bazel build -c opt --copt -DMESA_EGL_NO_X11_HEADERS \ $ bazel build -c opt --copt -DMESA_EGL_NO_X11_HEADERS --copt -DEGL_NO_X11 \
mediapipe/examples/desktop/face_detection:face_detection_gpu mediapipe/examples/desktop/face_detection:face_detection_gpu
# It should print: # It should print:

View File

@ -190,10 +190,10 @@ within the MediaPipe framework:
bazel build --define MEDIAPIPE_DISABLE_GPU=1 <my-target> bazel build --define MEDIAPIPE_DISABLE_GPU=1 <my-target>
# to enable full GPU support (OpenGL ES 3.1+ & Metal) # to enable full GPU support (OpenGL ES 3.1+ & Metal)
bazel build --copt -DMESA_EGL_NO_X11_HEADERS <my-target> bazel build --copt -DMESA_EGL_NO_X11_HEADERS --copt -DEGL_NO_X11 <my-target>
# to enable only OpenGL ES 3.0 and below (no GLES 3.1+ features) # to enable only OpenGL ES 3.0 and below (no GLES 3.1+ features)
bazel build --copt -DMESA_EGL_NO_X11_HEADERS --copt -DMEDIAPIPE_DISABLE_GL_COMPUTE <my-target> bazel build --copt -DMESA_EGL_NO_X11_HEADERS --copt -DEGL_NO_X11 --copt -DMEDIAPIPE_DISABLE_GL_COMPUTE <my-target>
``` ```
Note *MEDIAPIPE_DISABLE_GL_COMPUTE* is automatically defined on all Apple Note *MEDIAPIPE_DISABLE_GL_COMPUTE* is automatically defined on all Apple

View File

@ -26,7 +26,7 @@ To build and run the TensorFlow Lite example on desktop (GPU) with Webcam, run:
```bash ```bash
# Video from webcam running on desktop GPU # Video from webcam running on desktop GPU
# This works only for linux currently # This works only for linux currently
$ bazel build -c opt --copt -DMESA_EGL_NO_X11_HEADERS \ $ bazel build -c opt --copt -DMESA_EGL_NO_X11_HEADERS --copt -DEGL_NO_X11 \
mediapipe/examples/desktop/hair_segmentation:hair_segmentation_gpu mediapipe/examples/desktop/hair_segmentation:hair_segmentation_gpu
# It should print: # It should print:

View File

@ -48,7 +48,7 @@ To build and run the TensorFlow Lite example on desktop (GPU) with Webcam, run:
```bash ```bash
# Video from webcam running on desktop GPU # Video from webcam running on desktop GPU
# This works only for linux currently # This works only for linux currently
$ bazel build -c opt --copt -DMESA_EGL_NO_X11_HEADERS \ $ bazel build -c opt --copt -DMESA_EGL_NO_X11_HEADERS --copt -DEGL_NO_X11 \
mediapipe/examples/desktop/hand_tracking:hand_tracking_gpu mediapipe/examples/desktop/hand_tracking:hand_tracking_gpu
# It should print: # It should print:

View File

@ -40,12 +40,11 @@ To build and run iOS apps:
$ cd mediapipe $ cd mediapipe
``` ```
2. Install Bazel (version between 1.0.0 and 1.2.1). 2. Install Bazel.
Follow the official Follow the official
[Bazel documentation](https://docs.bazel.build/versions/master/install-ubuntu.html) [Bazel documentation](https://docs.bazel.build/versions/master/install-ubuntu.html)
to install Bazel manually. Note that MediaPipe doesn't support Bazel 2.0.0+ to install Bazel 2.0 or higher.
yet.
3. Install OpenCV and FFmpeg. 3. Install OpenCV and FFmpeg.
@ -111,7 +110,7 @@ To build and run iOS apps:
# To compile with GPU support, replace # To compile with GPU support, replace
--define MEDIAPIPE_DISABLE_GPU=1 --define MEDIAPIPE_DISABLE_GPU=1
# with # with
--copt -DMESA_EGL_NO_X11_HEADERS --copt -DMESA_EGL_NO_X11_HEADERS --copt -DEGL_NO_X11
# when building GPU examples. # when building GPU examples.
``` ```
@ -125,7 +124,7 @@ To build and run iOS apps:
mediapipe/examples/desktop/hello_world:hello_world mediapipe/examples/desktop/hello_world:hello_world
# If you are running on Linux desktop with GPU support enabled (via mesa drivers) # If you are running on Linux desktop with GPU support enabled (via mesa drivers)
$ bazel run --copt -DMESA_EGL_NO_X11_HEADERS \ $ bazel run --copt -DMESA_EGL_NO_X11_HEADERS --copt -DEGL_NO_X11 \
mediapipe/examples/desktop/hello_world:hello_world mediapipe/examples/desktop/hello_world:hello_world
# Should print: # Should print:
@ -152,12 +151,11 @@ To build and run iOS apps:
$ cd mediapipe $ cd mediapipe
``` ```
2. Install Bazel (version between 1.0.0 and 1.2.1). 2. Install Bazel.
Follow the official Follow the official
[Bazel documentation](https://docs.bazel.build/versions/master/install-redhat.html) [Bazel documentation](https://docs.bazel.build/versions/master/install-redhat.html)
to install Bazel manually. Note that MediaPipe doesn't support Bazel 2.0.0+ to install Bazel 2.0 or higher.
yet.
3. Install OpenCV. 3. Install OpenCV.
@ -241,23 +239,18 @@ To build and run iOS apps:
$ cd mediapipe $ cd mediapipe
``` ```
3. Install Bazel (version between 1.0.0 and 1.1.0). 3. Install Bazel.
Option 1. Use package manager tool to install Bazel 1.1.0 Option 1. Use package manager tool to install Bazel
```bash ```bash
# If Bazel 1.1.0+ was installed. $ brew install bazel
$ brew uninstall bazel
# Install Bazel 1.1.0
$ brew install https://raw.githubusercontent.com/bazelbuild/homebrew-tap/f8a0fa981bcb1784a0d0823e14867b844e94fb3d/Formula/bazel.rb
$ brew link bazel
# Run 'bazel version' to check version of bazel # Run 'bazel version' to check version of bazel
``` ```
Option 2. Follow the official Option 2. Follow the official
[Bazel documentation](https://docs.bazel.build/versions/master/install-os-x.html#install-with-installer-mac-os-x) [Bazel documentation](https://docs.bazel.build/versions/master/install-os-x.html#install-with-installer-mac-os-x)
to install any version of Bazel manually. Note that MediaPipe doesn't to install Bazel 2.0 or higher.
support Bazel 1.1.0+ on macOS yet.
4. Install OpenCV and FFmpeg. 4. Install OpenCV and FFmpeg.
@ -391,18 +384,18 @@ cameras. Alternatively, you use a video file as input.
username@DESKTOP-TMVLBJ1:~$ sudo apt-get update && sudo apt-get install -y build-essential git python zip adb openjdk-8-jdk username@DESKTOP-TMVLBJ1:~$ sudo apt-get update && sudo apt-get install -y build-essential git python zip adb openjdk-8-jdk
``` ```
5. Install Bazel (version between 1.0.0 and 1.2.1). 5. Install Bazel.
```bash ```bash
username@DESKTOP-TMVLBJ1:~$ curl -sLO --retry 5 --retry-max-time 10 \ username@DESKTOP-TMVLBJ1:~$ curl -sLO --retry 5 --retry-max-time 10 \
https://storage.googleapis.com/bazel/1.0.0/release/bazel-1.0.0-installer-linux-x86_64.sh && \ https://storage.googleapis.com/bazel/2.0.0/release/bazel-2.0.0-installer-linux-x86_64.sh && \
sudo mkdir -p /usr/local/bazel/1.0.0 && \ sudo mkdir -p /usr/local/bazel/2.0.0 && \
chmod 755 bazel-1.0.0-installer-linux-x86_64.sh && \ chmod 755 bazel-2.0.0-installer-linux-x86_64.sh && \
sudo ./bazel-1.0.0-installer-linux-x86_64.sh --prefix=/usr/local/bazel/1.0.0 && \ sudo ./bazel-2.0.0-installer-linux-x86_64.sh --prefix=/usr/local/bazel/2.0.0 && \
source /usr/local/bazel/1.0.0/lib/bazel/bin/bazel-complete.bash source /usr/local/bazel/2.0.0/lib/bazel/bin/bazel-complete.bash
username@DESKTOP-TMVLBJ1:~$ /usr/local/bazel/1.0.0/lib/bazel/bin/bazel version && \ username@DESKTOP-TMVLBJ1:~$ /usr/local/bazel/2.0.0/lib/bazel/bin/bazel version && \
alias bazel='/usr/local/bazel/1.0.0/lib/bazel/bin/bazel' alias bazel='/usr/local/bazel/2.0.0/lib/bazel/bin/bazel'
``` ```
6. Checkout MediaPipe repository. 6. Checkout MediaPipe repository.

View File

@ -89,11 +89,11 @@ process new data sets, in the documentation of
dataset = d.as_dataset('test') dataset = d.as_dataset('test')
# implement additional processing and batching here # implement additional processing and batching here
dataset_output = dataset.make_one_shot_iterator().get_next() dataset_output = dataset.make_one_shot_iterator().get_next()
images = dataset_output=['images'] images = dataset_output['images']
labels = dataset_output=['labels'] labels = dataset_output['labels']
with tf.Session() as sess: with tf.Session() as sess:
images_, labels_ = sess.run(images, labels) images_, labels_ = sess.run([images, labels])
print('The shape of images_ is %s' % str(images_.shape)) print('The shape of images_ is %s' % str(images_.shape))
print('The shape of labels_ is %s' % str(labels_.shape)) print('The shape of labels_ is %s' % str(labels_.shape))
``` ```

View File

@ -76,6 +76,10 @@ in the next section.
2. Open `mediapipe/Mediapipe.tulsiproj` using the Tulsi app. 2. Open `mediapipe/Mediapipe.tulsiproj` using the Tulsi app.
Important: If Tulsi displays an error saying "Bazel could not be found",
press the "Bazel..." button in the Packages tab and select the `bazel`
executable in your homebrew `/bin/` directory.
3. Select the MediaPipe config in the Configs tab, then press the Generate 3. Select the MediaPipe config in the Configs tab, then press the Generate
button below. You will be asked for a location to save the Xcode project. button below. You will be asked for a location to save the Xcode project.
Once the project is generated, it will be opened in Xcode. Once the project is generated, it will be opened in Xcode.

View File

@ -48,7 +48,7 @@ To build and run the TensorFlow Lite example on desktop (GPU) with Webcam, run:
```bash ```bash
# Video from webcam running on desktop GPU # Video from webcam running on desktop GPU
# This works only for linux currently # This works only for linux currently
$ bazel build -c opt --copt -DMESA_EGL_NO_X11_HEADERS \ $ bazel build -c opt --copt -DMESA_EGL_NO_X11_HEADERS --copt -DEGL_NO_X11 \
mediapipe/examples/desktop/multi_hand_tracking:multi_hand_tracking_gpu mediapipe/examples/desktop/multi_hand_tracking:multi_hand_tracking_gpu
# It should print: # It should print:

View File

@ -60,8 +60,8 @@ android_library(
"//third_party:androidx_appcompat", "//third_party:androidx_appcompat",
"//third_party:androidx_constraint_layout", "//third_party:androidx_constraint_layout",
"//third_party:opencv", "//third_party:opencv",
"@androidx_concurrent_futures//jar", "@maven//:androidx_concurrent_concurrent_futures",
"@com_google_guava_android//jar", "@maven//:com_google_guava_guava",
], ],
) )

View File

@ -64,10 +64,10 @@ android_library(
"//third_party:androidx_legacy_support_v4", "//third_party:androidx_legacy_support_v4",
"//third_party:androidx_recyclerview", "//third_party:androidx_recyclerview",
"//third_party:opencv", "//third_party:opencv",
"@androidx_concurrent_futures//jar", "@maven//:androidx_concurrent_concurrent_futures",
"@androidx_lifecycle//jar", "@maven//:androidx_lifecycle_lifecycle_common",
"@com_google_code_findbugs//jar", "@maven//:com_google_code_findbugs_jsr305",
"@com_google_guava_android//jar", "@maven//:com_google_guava_guava",
], ],
) )

View File

@ -64,10 +64,10 @@ android_library(
"//third_party:androidx_legacy_support_v4", "//third_party:androidx_legacy_support_v4",
"//third_party:androidx_recyclerview", "//third_party:androidx_recyclerview",
"//third_party:opencv", "//third_party:opencv",
"@androidx_concurrent_futures//jar", "@maven//:androidx_concurrent_concurrent_futures",
"@androidx_lifecycle//jar", "@maven//:androidx_lifecycle_lifecycle_common",
"@com_google_code_findbugs//jar", "@maven//:com_google_code_findbugs_jsr305",
"@com_google_guava_android//jar", "@maven//:com_google_guava_guava",
], ],
) )

View File

@ -63,10 +63,10 @@ android_library(
"//third_party:androidx_legacy_support_v4", "//third_party:androidx_legacy_support_v4",
"//third_party:androidx_recyclerview", "//third_party:androidx_recyclerview",
"//third_party:opencv", "//third_party:opencv",
"@androidx_concurrent_futures//jar", "@maven//:androidx_concurrent_concurrent_futures",
"@androidx_lifecycle//jar", "@maven//:androidx_lifecycle_lifecycle_common",
"@com_google_code_findbugs//jar", "@maven//:com_google_code_findbugs_jsr305",
"@com_google_guava_android//jar", "@maven//:com_google_guava_guava",
], ],
) )

View File

@ -64,10 +64,10 @@ android_library(
"//third_party:androidx_legacy_support_v4", "//third_party:androidx_legacy_support_v4",
"//third_party:androidx_recyclerview", "//third_party:androidx_recyclerview",
"//third_party:opencv", "//third_party:opencv",
"@androidx_concurrent_futures//jar", "@maven//:androidx_concurrent_concurrent_futures",
"@androidx_lifecycle//jar", "@maven//:androidx_lifecycle_lifecycle_common",
"@com_google_code_findbugs//jar", "@maven//:com_google_code_findbugs_jsr305",
"@com_google_guava_android//jar", "@maven//:com_google_guava_guava",
], ],
) )

View File

@ -85,10 +85,10 @@ android_library(
"//third_party:androidx_legacy_support_v4", "//third_party:androidx_legacy_support_v4",
"//third_party:androidx_recyclerview", "//third_party:androidx_recyclerview",
"//third_party:opencv", "//third_party:opencv",
"@androidx_concurrent_futures//jar", "@maven//:androidx_concurrent_concurrent_futures",
"@androidx_lifecycle//jar", "@maven//:androidx_lifecycle_lifecycle_common",
"@com_google_code_findbugs//jar", "@maven//:com_google_code_findbugs_jsr305",
"@com_google_guava_android//jar", "@maven//:com_google_guava_guava",
], ],
) )

View File

@ -85,10 +85,10 @@ android_library(
"//third_party:androidx_legacy_support_v4", "//third_party:androidx_legacy_support_v4",
"//third_party:androidx_recyclerview", "//third_party:androidx_recyclerview",
"//third_party:opencv", "//third_party:opencv",
"@androidx_concurrent_futures//jar", "@maven//:androidx_concurrent_concurrent_futures",
"@androidx_lifecycle//jar", "@maven//:androidx_lifecycle_lifecycle_common",
"@com_google_code_findbugs//jar", "@maven//:com_google_code_findbugs_jsr305",
"@com_google_guava_android//jar", "@maven//:com_google_guava_guava",
], ],
) )

View File

@ -97,10 +97,10 @@ android_library(
"//third_party:androidx_legacy_support_v4", "//third_party:androidx_legacy_support_v4",
"//third_party:androidx_recyclerview", "//third_party:androidx_recyclerview",
"//third_party:opencv", "//third_party:opencv",
"@androidx_concurrent_futures//jar", "@maven//:androidx_concurrent_concurrent_futures",
"@androidx_lifecycle//jar", "@maven//:androidx_lifecycle_lifecycle_common",
"@com_google_code_findbugs//jar", "@maven//:com_google_code_findbugs_jsr305",
"@com_google_guava_android//jar", "@maven//:com_google_guava_guava",
], ],
) )

View File

@ -64,10 +64,10 @@ android_library(
"//third_party:androidx_legacy_support_v4", "//third_party:androidx_legacy_support_v4",
"//third_party:androidx_recyclerview", "//third_party:androidx_recyclerview",
"//third_party:opencv", "//third_party:opencv",
"@androidx_concurrent_futures//jar", "@maven//:androidx_concurrent_concurrent_futures",
"@androidx_lifecycle//jar", "@maven//:androidx_lifecycle_lifecycle_common",
"@com_google_code_findbugs//jar", "@maven//:com_google_code_findbugs_jsr305",
"@com_google_guava_android//jar", "@maven//:com_google_guava_guava",
], ],
) )

View File

@ -65,10 +65,10 @@ android_library(
"//third_party:androidx_legacy_support_v4", "//third_party:androidx_legacy_support_v4",
"//third_party:androidx_recyclerview", "//third_party:androidx_recyclerview",
"//third_party:opencv", "//third_party:opencv",
"@androidx_concurrent_futures//jar", "@maven//:androidx_concurrent_concurrent_futures",
"@androidx_lifecycle//jar", "@maven//:androidx_lifecycle_lifecycle_common",
"@com_google_code_findbugs//jar", "@maven//:com_google_code_findbugs_jsr305",
"@com_google_guava_android//jar", "@maven//:com_google_guava_guava",
], ],
) )

View File

@ -64,9 +64,9 @@ android_library(
"//third_party:androidx_legacy_support_v4", "//third_party:androidx_legacy_support_v4",
"//third_party:androidx_recyclerview", "//third_party:androidx_recyclerview",
"//third_party:opencv", "//third_party:opencv",
"@androidx_concurrent_futures//jar", "@maven//:androidx_concurrent_concurrent_futures",
"@androidx_lifecycle//jar", "@maven//:androidx_lifecycle_lifecycle_common",
"@com_google_guava_android//jar", "@maven//:com_google_guava_guava",
], ],
) )

View File

@ -35,10 +35,8 @@ RUN dpkg --add-architecture arm64
RUN apt-get update && apt-get install -y \ RUN apt-get update && apt-get install -y \
build-essential \ build-essential \
crossbuild-essential-arm64 \ crossbuild-essential-arm64 \
libusb-1.0-0-dev \
libusb-1.0-0-dev:arm64 \ libusb-1.0-0-dev:arm64 \
zlib1g-dev \ zlibc:arm64 \
zlib1g-dev:arm64 \
pkg-config \ pkg-config \
zip \ zip \
unzip \ unzip \
@ -62,8 +60,8 @@ RUN pip3 install six
COPY . /mediapipe/ COPY . /mediapipe/
# Install bazel # Install bazel
# Please match the current MediaPipe Bazel requirements according to docs.
ARG BAZEL_VERSION=1.1.0 ARG BAZEL_VERSION=2.0.0
RUN mkdir /bazel && \ RUN mkdir /bazel && \
wget --no-check-certificate -O /bazel/installer.sh "https://github.com/bazelbuild/bazel/releases/download/${BAZEL_VERSION}/bazel-${BAZEL_VERSION}-installer-linux-x86_64.sh" && \ wget --no-check-certificate -O /bazel/installer.sh "https://github.com/bazelbuild/bazel/releases/download/${BAZEL_VERSION}/bazel-${BAZEL_VERSION}-installer-linux-x86_64.sh" && \
wget --no-check-certificate -O /bazel/LICENSE.txt "https://raw.githubusercontent.com/bazelbuild/bazel/master/LICENSE" && \ wget --no-check-certificate -O /bazel/LICENSE.txt "https://raw.githubusercontent.com/bazelbuild/bazel/master/LICENSE" && \

View File

@ -1,356 +0,0 @@
workspace(name = "mediapipe")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
skylib_version = "0.8.0"
http_archive(
name = "bazel_skylib",
type = "tar.gz",
url = "https://github.com/bazelbuild/bazel-skylib/releases/download/{}/bazel-skylib.{}.tar.gz".format (skylib_version, skylib_version),
sha256 = "2ef429f5d7ce7111263289644d233707dba35e39696377ebab8b0bc701f7818e",
)
load("@bazel_skylib//lib:versions.bzl", "versions")
versions.check(minimum_bazel_version = "1.0.0",
maximum_bazel_version = "1.2.1")
# ABSL cpp library lts_2020_02_25
http_archive(
name = "com_google_absl",
urls = [
"https://github.com/abseil/abseil-cpp/archive/20200225.tar.gz",
],
# Remove after https://github.com/abseil/abseil-cpp/issues/326 is solved.
patches = [
"@//third_party:com_google_absl_f863b622fe13612433fdf43f76547d5edda0c93001.diff"
],
patch_args = [
"-p1",
],
strip_prefix = "abseil-cpp-20200225",
sha256 = "728a813291bdec2aa46eab8356ace9f75ac2ed9dfe2df5ab603c4e6c09f1c353"
)
http_archive(
name = "rules_cc",
strip_prefix = "rules_cc-master",
urls = ["https://github.com/bazelbuild/rules_cc/archive/master.zip"],
)
# GoogleTest/GoogleMock framework. Used by most unit-tests.
http_archive(
name = "com_google_googletest",
urls = ["https://github.com/google/googletest/archive/master.zip"],
strip_prefix = "googletest-master",
)
# Google Benchmark library.
http_archive(
name = "com_google_benchmark",
urls = ["https://github.com/google/benchmark/archive/master.zip"],
strip_prefix = "benchmark-master",
build_file = "@//third_party:benchmark.BUILD",
)
# gflags needed by glog
http_archive(
name = "com_github_gflags_gflags",
sha256 = "6e16c8bc91b1310a44f3965e616383dbda48f83e8c1eaa2370a215057b00cabe",
strip_prefix = "gflags-77592648e3f3be87d6c7123eb81cbad75f9aef5a",
urls = [
"https://mirror.bazel.build/github.com/gflags/gflags/archive/77592648e3f3be87d6c7123eb81cbad75f9aef5a.tar.gz",
"https://github.com/gflags/gflags/archive/77592648e3f3be87d6c7123eb81cbad75f9aef5a.tar.gz",
],
)
# glog
http_archive(
name = "com_github_glog_glog",
url = "https://github.com/google/glog/archive/v0.3.5.zip",
sha256 = "267103f8a1e9578978aa1dc256001e6529ef593e5aea38193d31c2872ee025e8",
strip_prefix = "glog-0.3.5",
build_file = "@//third_party:glog.BUILD",
patches = [
"@//third_party:com_github_glog_glog_9779e5ea6ef59562b030248947f787d1256132ae.diff"
],
patch_args = [
"-p1",
],
)
# easyexif
http_archive(
name = "easyexif",
url = "https://github.com/mayanklahiri/easyexif/archive/master.zip",
strip_prefix = "easyexif-master",
build_file = "@//third_party:easyexif.BUILD",
)
# libyuv
http_archive(
name = "libyuv",
urls = ["https://chromium.googlesource.com/libyuv/libyuv/+archive/refs/heads/master.tar.gz"],
build_file = "@//third_party:libyuv.BUILD",
)
http_archive(
name = "com_google_protobuf_javalite",
sha256 = "79d102c61e2a479a0b7e5fc167bcfaa4832a0c6aad4a75fa7da0480564931bcc",
strip_prefix = "protobuf-384989534b2246d413dbcd750744faab2607b516",
urls = ["https://github.com/google/protobuf/archive/384989534b2246d413dbcd750744faab2607b516.zip"],
)
http_archive(
name = "com_google_audio_tools",
strip_prefix = "multichannel-audio-tools-master",
urls = ["https://github.com/google/multichannel-audio-tools/archive/master.zip"],
)
# Needed by TensorFlow
http_archive(
name = "io_bazel_rules_closure",
sha256 = "e0a111000aeed2051f29fcc7a3f83be3ad8c6c93c186e64beb1ad313f0c7f9f9",
strip_prefix = "rules_closure-cf1e44edb908e9616030cc83d085989b8e6cd6df",
urls = [
"http://mirror.tensorflow.org/github.com/bazelbuild/rules_closure/archive/cf1e44edb908e9616030cc83d085989b8e6cd6df.tar.gz",
"https://github.com/bazelbuild/rules_closure/archive/cf1e44edb908e9616030cc83d085989b8e6cd6df.tar.gz", # 2019-04-04
],
)
# 2020-02-12
# The last commit before TensorFlow switched to Bazel 2.0
_TENSORFLOW_GIT_COMMIT = "77e9ffb9b2bfb1a4f7056e62d84039626923e328"
_TENSORFLOW_SHA256= "176ccd82f7dd17c5e117b50d353603b129c7a6ccbfebd522ca47cc2a40f33f13"
http_archive(
name = "org_tensorflow",
urls = [
"https://mirror.bazel.build/github.com/tensorflow/tensorflow/archive/%s.tar.gz" % _TENSORFLOW_GIT_COMMIT,
"https://github.com/tensorflow/tensorflow/archive/%s.tar.gz" % _TENSORFLOW_GIT_COMMIT,
],
# A compatibility patch
patches = [
"@//third_party:org_tensorflow_528e22eae8bf3206189a066032c66e9e5c9b4a61.diff"
],
patch_args = [
"-p1",
],
strip_prefix = "tensorflow-%s" % _TENSORFLOW_GIT_COMMIT,
sha256 = _TENSORFLOW_SHA256,
)
load("@org_tensorflow//tensorflow:workspace.bzl", "tf_workspace")
tf_workspace(tf_repo_name = "org_tensorflow")
http_archive(
name = "ceres_solver",
url = "https://github.com/ceres-solver/ceres-solver/archive/1.14.0.zip",
patches = [
"@//third_party:ceres_solver_9bf9588988236279e1262f75d7f4d85711dfa172.diff"
],
patch_args = [
"-p1",
],
strip_prefix = "ceres-solver-1.14.0",
sha256 = "5ba6d0db4e784621fda44a50c58bb23b0892684692f0c623e2063f9c19f192f1"
)
# Please run
# $ sudo apt-get install libopencv-core-dev libopencv-highgui-dev \
# libopencv-calib3d-dev libopencv-features2d-dev \
# libopencv-imgproc-dev libopencv-video-dev
new_local_repository(
name = "linux_opencv",
build_file = "@//third_party:opencv_linux.BUILD",
path = "/usr",
)
new_local_repository(
name = "linux_ffmpeg",
build_file = "@//third_party:ffmpeg_linux.BUILD",
path = "/usr"
)
# Please run $ brew install opencv@3
new_local_repository(
name = "macos_opencv",
build_file = "@//third_party:opencv_macos.BUILD",
path = "/usr",
)
new_local_repository(
name = "macos_ffmpeg",
build_file = "@//third_party:ffmpeg_macos.BUILD",
path = "/usr",
)
http_archive(
name = "android_opencv",
build_file = "@//third_party:opencv_android.BUILD",
strip_prefix = "OpenCV-android-sdk",
type = "zip",
url = "https://github.com/opencv/opencv/releases/download/3.4.3/opencv-3.4.3-android-sdk.zip",
)
# After OpenCV 3.2.0, the pre-compiled opencv2.framework has google protobuf symbols, which will
# trigger duplicate symbol errors in the linking stage of building a mediapipe ios app.
# To get a higher version of OpenCV for iOS, opencv2.framework needs to be built from source with
# '-DBUILD_PROTOBUF=OFF -DBUILD_opencv_dnn=OFF'.
http_archive(
name = "ios_opencv",
sha256 = "7dd536d06f59e6e1156b546bd581523d8df92ce83440002885ec5abc06558de2",
build_file = "@//third_party:opencv_ios.BUILD",
type = "zip",
url = "https://github.com/opencv/opencv/releases/download/3.2.0/opencv-3.2.0-ios-framework.zip",
)
RULES_JVM_EXTERNAL_TAG = "2.2"
RULES_JVM_EXTERNAL_SHA = "f1203ce04e232ab6fdd81897cf0ff76f2c04c0741424d192f28e65ae752ce2d6"
http_archive(
name = "rules_jvm_external",
strip_prefix = "rules_jvm_external-%s" % RULES_JVM_EXTERNAL_TAG,
sha256 = RULES_JVM_EXTERNAL_SHA,
url = "https://github.com/bazelbuild/rules_jvm_external/archive/%s.zip" % RULES_JVM_EXTERNAL_TAG,
)
load("@rules_jvm_external//:defs.bzl", "maven_install")
maven_install(
artifacts = [
"androidx.annotation:annotation:aar:1.1.0",
"androidx.appcompat:appcompat:aar:1.1.0-rc01",
"androidx.camera:camera-core:aar:1.0.0-alpha06",
"androidx.camera:camera-camera2:aar:1.0.0-alpha06",
"androidx.constraintlayout:constraintlayout:aar:1.1.3",
"androidx.core:core:aar:1.1.0-rc03",
"androidx.legacy:legacy-support-v4:aar:1.0.0",
"androidx.recyclerview:recyclerview:aar:1.1.0-beta02",
"com.google.android.material:material:aar:1.0.0-rc01",
],
repositories = [
"https://dl.google.com/dl/android/maven2",
"https://repo1.maven.org/maven2",
],
)
maven_server(
name = "google_server",
url = "https://dl.google.com/dl/android/maven2",
)
maven_jar(
name = "androidx_lifecycle",
artifact = "androidx.lifecycle:lifecycle-common:2.0.0",
sha1 = "e070ffae07452331bc5684734fce6831d531785c",
server = "google_server",
)
maven_jar(
name = "androidx_concurrent_futures",
artifact = "androidx.concurrent:concurrent-futures:1.0.0-alpha03",
sha1 = "b528df95c7e2fefa2210c0c742bf3e491c1818ae",
server = "google_server",
)
maven_jar(
name = "com_google_guava_android",
artifact = "com.google.guava:guava:27.0.1-android",
sha1 = "b7e1c37f66ef193796ccd7ea6e80c2b05426182d",
)
maven_jar(
name = "com_google_common_flogger",
artifact = "com.google.flogger:flogger:0.3.1",
sha1 = "585030fe1ec709760cbef997a459729fb965df0e",
)
maven_jar(
name = "com_google_common_flogger_system_backend",
artifact = "com.google.flogger:flogger-system-backend:0.3.1",
sha1 = "287b569d76abcd82f9de87fe41829fbc7ebd8ac9",
)
maven_jar(
name = "com_google_code_findbugs",
artifact = "com.google.code.findbugs:jsr305:3.0.2",
sha1 = "25ea2e8b0c338a877313bd4672d3fe056ea78f0d",
)
# You may run setup_android.sh to install Android SDK and NDK.
android_ndk_repository(
name = "androidndk",
)
android_sdk_repository(
name = "androidsdk",
)
# iOS basic build deps.
http_archive(
name = "build_bazel_rules_apple",
sha256 = "bdc8e66e70b8a75da23b79f1f8c6207356df07d041d96d2189add7ee0780cf4e",
strip_prefix = "rules_apple-b869b0d3868d78a1d4ffd866ccb304fb68aa12c3",
url = "https://github.com/bazelbuild/rules_apple/archive/b869b0d3868d78a1d4ffd866ccb304fb68aa12c3.tar.gz",
)
load(
"@build_bazel_rules_apple//apple:repositories.bzl",
"apple_rules_dependencies",
)
apple_rules_dependencies()
load(
"@build_bazel_rules_swift//swift:repositories.bzl",
"swift_rules_dependencies",
)
swift_rules_dependencies()
load(
"@build_bazel_apple_support//lib:repositories.bzl",
"apple_support_dependencies",
)
apple_support_dependencies()
# More iOS deps.
http_archive(
name = "google_toolbox_for_mac",
url = "https://github.com/google/google-toolbox-for-mac/archive/v2.2.1.zip",
sha256 = "e3ac053813c989a88703556df4dc4466e424e30d32108433ed6beaec76ba4fdc",
strip_prefix = "google-toolbox-for-mac-2.2.1",
build_file = "@//third_party:google_toolbox_for_mac.BUILD",
)
### Coral ###
#COMMIT=$(git ls-remote https://github.com/google-coral/crosstool master | awk '{print $1}')
#SHA256=$(curl -L "https://github.com/google-coral/crosstool/archive/${COMMIT}.tar.gz" | sha256sum | awk '{print $1}')
# Oct 2019
#COMMIT=9e00d5be43bf001f883b5700f5d04882fea00229
#SHA256=cb31b1417ccdcf7dd9fca5ec63e1571672372c30427730255997a547569d2feb
http_archive(
name = "coral_crosstool",
sha256 = "cb31b1417ccdcf7dd9fca5ec63e1571672372c30427730255997a547569d2feb",
strip_prefix = "crosstool-9e00d5be43bf001f883b5700f5d04882fea00229",
urls = [
"https://github.com/google-coral/crosstool/archive/9e00d5be43bf001f883b5700f5d04882fea00229.tar.gz",
],
)
load("@coral_crosstool//:configure.bzl", "cc_crosstool")
cc_crosstool(name = "crosstool")
# EdgeTPU
new_local_repository(
name = "edgetpu",
path = "/edgetpu/libedgetpu",
build_file = "/edgetpu/libedgetpu/BUILD"
)
new_local_repository(
name = "libedgetpu",
path = "/usr/lib/aarch64-linux-gnu",
build_file = "/edgetpu/libedgetpu/BUILD"
)

View File

@ -0,0 +1,30 @@
### Coral additions to MediaPipe WORKSPACE ###
#COMMIT=$(git ls-remote https://github.com/google-coral/crosstool master | awk '{print $1}')
#SHA256=$(curl -L "https://github.com/google-coral/crosstool/archive/${COMMIT}.tar.gz" | sha256sum | awk '{print $1}')
# Oct 2019
#COMMIT=9e00d5be43bf001f883b5700f5d04882fea00229
#SHA256=cb31b1417ccdcf7dd9fca5ec63e1571672372c30427730255997a547569d2feb
http_archive(
name = "coral_crosstool",
sha256 = "cb31b1417ccdcf7dd9fca5ec63e1571672372c30427730255997a547569d2feb",
strip_prefix = "crosstool-9e00d5be43bf001f883b5700f5d04882fea00229",
urls = [
"https://github.com/google-coral/crosstool/archive/9e00d5be43bf001f883b5700f5d04882fea00229.tar.gz",
],
)
load("@coral_crosstool//:configure.bzl", "cc_crosstool")
cc_crosstool(name = "crosstool")
# EdgeTPU
new_local_repository(
name = "edgetpu",
path = "/edgetpu/libedgetpu",
build_file = "/edgetpu/libedgetpu/BUILD"
)
new_local_repository(
name = "libedgetpu",
path = "/usr/lib/aarch64-linux-gnu",
build_file = "/edgetpu/libedgetpu/BUILD"
)

View File

@ -10,12 +10,25 @@ sleep 3
mkdir -p opencv32_arm64_libs mkdir -p opencv32_arm64_libs
# prepare docker aux script
cp mediapipe/examples/coral/update_sources.sh update_sources.sh cp mediapipe/examples/coral/update_sources.sh update_sources.sh
chmod +x update_sources.sh chmod +x update_sources.sh
# backup non-coral Dockerfile
mv Dockerfile Dockerfile.orig mv Dockerfile Dockerfile.orig
cp mediapipe/examples/coral/Dockerfile Dockerfile cp mediapipe/examples/coral/Dockerfile Dockerfile
# backup non-coral workspace
cp WORKSPACE WORKSPACE.orig cp WORKSPACE WORKSPACE.orig
cp mediapipe/examples/coral/WORKSPACE WORKSPACE
# create temps
cp WORKSPACE WORKSPACE.1
cp mediapipe/examples/coral/WORKSPACE.coral WORKSPACE.2
# merge (shell decides concat order, unless numbered appropriately)
cat WORKSPACE.1 WORKSPACE.2 > WORKSPACE
# cleanup
rm WORKSPACE.1 WORKSPACE.2
echo 'done'

View File

@ -85,7 +85,7 @@ REGISTER_CALCULATOR(ShotBoundaryCalculator);
void ShotBoundaryCalculator::ComputeHistogram(const cv::Mat& image, void ShotBoundaryCalculator::ComputeHistogram(const cv::Mat& image,
cv::Mat* image_histogram) { cv::Mat* image_histogram) {
cv::Mat equalized_image; cv::Mat equalized_image;
cv::cvtColor(image.clone(), equalized_image, CV_RGB2GRAY); cv::cvtColor(image.clone(), equalized_image, cv::COLOR_RGB2GRAY);
double min, max; double min, max;
cv::minMaxLoc(equalized_image, &min, &max); cv::minMaxLoc(equalized_image, &min, &max);

View File

@ -1496,13 +1496,17 @@ cc_test(
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"//mediapipe/framework/stream_handler:barrier_input_stream_handler", "//mediapipe/framework/stream_handler:barrier_input_stream_handler",
"//mediapipe/framework/stream_handler:early_close_input_stream_handler", "//mediapipe/framework/stream_handler:early_close_input_stream_handler",
"//mediapipe/framework/stream_handler:fixed_size_input_stream_handler",
"//mediapipe/framework/stream_handler:immediate_input_stream_handler", "//mediapipe/framework/stream_handler:immediate_input_stream_handler",
"//mediapipe/framework/stream_handler:mux_input_stream_handler", "//mediapipe/framework/stream_handler:mux_input_stream_handler",
"//mediapipe/framework/stream_handler:sync_set_input_stream_handler",
"//mediapipe/framework/stream_handler:timestamp_align_input_stream_handler",
"//mediapipe/framework/tool:sink", "//mediapipe/framework/tool:sink",
"//mediapipe/framework/tool:status_util", "//mediapipe/framework/tool:status_util",
"@com_google_absl//absl/container:fixed_array", "@com_google_absl//absl/container:fixed_array",
"@com_google_absl//absl/memory", "@com_google_absl//absl/memory",
"@com_google_absl//absl/strings", "@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format",
"@com_google_absl//absl/time", "@com_google_absl//absl/time",
], ],
) )

View File

@ -29,6 +29,7 @@
#include "absl/memory/memory.h" #include "absl/memory/memory.h"
#include "absl/strings/escaping.h" #include "absl/strings/escaping.h"
#include "absl/strings/str_cat.h" #include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
#include "absl/strings/substitute.h" #include "absl/strings/substitute.h"
#include "absl/time/clock.h" #include "absl/time/clock.h"
@ -4558,5 +4559,68 @@ TEST(CalculatorGraph, SimpleMuxCalculatorWithCustomInputStreamHandler) {
testing::HasSubstr("ImmediateInputStreamHandler class comment"))); testing::HasSubstr("ImmediateInputStreamHandler class comment")));
} }
void DoTestMultipleGraphRuns(absl::string_view input_stream_handler,
bool select_packet) {
std::string graph_proto = absl::StrFormat(R"(
input_stream: 'input'
input_stream: 'select'
node {
calculator: 'PassThroughCalculator'
input_stream: 'input'
input_stream: 'select'
input_stream_handler {
input_stream_handler: "%s"
}
output_stream: 'output'
output_stream: 'select_out'
}
)",
input_stream_handler.data());
CalculatorGraphConfig config =
::mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(graph_proto);
std::vector<Packet> packet_dump;
tool::AddVectorSink("output", &config, &packet_dump);
CalculatorGraph graph;
MP_ASSERT_OK(graph.Initialize(config));
struct Run {
Timestamp timestamp;
int value;
};
std::vector<Run> runs = {{.timestamp = Timestamp(2000), .value = 2},
{.timestamp = Timestamp(1000), .value = 1}};
for (const Run& run : runs) {
MP_ASSERT_OK(graph.StartRun({}));
if (select_packet) {
MP_EXPECT_OK(graph.AddPacketToInputStream(
"select", MakePacket<int>(0).At(run.timestamp)));
}
MP_EXPECT_OK(graph.AddPacketToInputStream(
"input", MakePacket<int>(run.value).At(run.timestamp)));
MP_ASSERT_OK(graph.WaitUntilIdle());
ASSERT_EQ(1, packet_dump.size());
EXPECT_EQ(run.value, packet_dump[0].Get<int>());
EXPECT_EQ(run.timestamp, packet_dump[0].Timestamp());
MP_ASSERT_OK(graph.CloseAllPacketSources());
MP_ASSERT_OK(graph.WaitUntilDone());
packet_dump.clear();
}
}
TEST(CalculatorGraph, MultipleRunsWithDifferentInputStreamHandlers) {
DoTestMultipleGraphRuns("BarrierInputStreamHandler", true);
DoTestMultipleGraphRuns("DefaultInputStreamHandler", true);
DoTestMultipleGraphRuns("EarlyCloseInputStreamHandler", true);
DoTestMultipleGraphRuns("FixedSizeInputStreamHandler", true);
DoTestMultipleGraphRuns("ImmediateInputStreamHandler", false);
DoTestMultipleGraphRuns("MuxInputStreamHandler", true);
DoTestMultipleGraphRuns("SyncSetInputStreamHandler", true);
DoTestMultipleGraphRuns("TimestampAlignInputStreamHandler", true);
}
} // namespace } // namespace
} // namespace mediapipe } // namespace mediapipe

View File

@ -814,7 +814,8 @@ std::string CalculatorNode::DebugName() const {
input_stream_handler_->FinalizeInputSet(input_timestamp, inputs); input_stream_handler_->FinalizeInputSet(input_timestamp, inputs);
output_stream_handler_->PrepareOutputs(input_timestamp, outputs); output_stream_handler_->PrepareOutputs(input_timestamp, outputs);
VLOG(2) << "Calling Calculator::Process() for node: " << DebugName(); VLOG(2) << "Calling Calculator::Process() for node: " << DebugName()
<< " timestamp: " << input_timestamp;
if (OutputsAreConstant(calculator_context)) { if (OutputsAreConstant(calculator_context)) {
// Do nothing. // Do nothing.
@ -826,6 +827,9 @@ std::string CalculatorNode::DebugName() const {
result = calculator_->Process(calculator_context); result = calculator_->Process(calculator_context);
} }
VLOG(2) << "Called Calculator::Process() for node: " << DebugName()
<< " timestamp: " << input_timestamp;
// Removes one packet from each shard and progresses to the next input // Removes one packet from each shard and progresses to the next input
// timestamp. // timestamp.
input_stream_handler_->ClearCurrentInputs(calculator_context); input_stream_handler_->ClearCurrentInputs(calculator_context);

View File

@ -113,7 +113,10 @@ message GraphTrace {
optional int32 stream_id = 4; optional int32 stream_id = 4;
// The address of the packet contents. // The address of the packet contents.
optional int64 packet_id = 5; optional int64 packet_id = 5 [deprecated = true];
// Data describing the event, such as the packet contents.
optional int64 event_data = 6;
} }
// The kind of event recorded. // The kind of event recorded.
@ -133,6 +136,7 @@ message GraphTrace {
DSP_TASK = 12; DSP_TASK = 12;
TPU_TASK = 13; TPU_TASK = 13;
GPU_CALIBRATION = 14; GPU_CALIBRATION = 14;
PACKET_QUEUED = 15;
} }
// The timing for one packet set being processed at one caclulator node. // The timing for one packet set being processed at one caclulator node.

View File

@ -13,7 +13,7 @@
# limitations under the License. # limitations under the License.
# #
load("//mediapipe/framework/port:build_config.bzl", "mediapipe_cc_proto_library") load("//mediapipe/framework/port:build_config.bzl", "mediapipe_proto_library")
package( package(
default_visibility = ["//visibility:private"], default_visibility = ["//visibility:private"],
@ -24,95 +24,45 @@ licenses(["notice"]) # Apache 2.0
exports_files(["LICENSE"]) exports_files(["LICENSE"])
proto_library( mediapipe_proto_library(
name = "detection_proto", name = "detection_proto",
srcs = ["detection.proto"], srcs = ["detection.proto"],
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = ["//mediapipe/framework/formats:location_data_proto"], deps = ["//mediapipe/framework/formats:location_data_proto"],
) )
proto_library( mediapipe_proto_library(
name = "classification_proto", name = "classification_proto",
srcs = ["classification.proto"], srcs = ["classification.proto"],
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
) )
proto_library( mediapipe_proto_library(
name = "image_format_proto", name = "image_format_proto",
srcs = ["image_format.proto"], srcs = ["image_format.proto"],
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
) )
proto_library( mediapipe_proto_library(
name = "matrix_data_proto", name = "matrix_data_proto",
srcs = ["matrix_data.proto"], srcs = ["matrix_data.proto"],
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
) )
proto_library( mediapipe_proto_library(
name = "location_data_proto", name = "location_data_proto",
srcs = ["location_data.proto"], srcs = ["location_data.proto"],
portable_deps = ["//mediapipe/framework/formats/annotation:rasterization_cc_proto"],
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = ["//mediapipe/framework/formats/annotation:rasterization_proto"], deps = ["//mediapipe/framework/formats/annotation:rasterization_proto"],
) )
proto_library( mediapipe_proto_library(
name = "time_series_header_proto", name = "time_series_header_proto",
srcs = ["time_series_header.proto"], srcs = ["time_series_header.proto"],
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
) )
mediapipe_cc_proto_library(
name = "detection_cc_proto",
srcs = ["detection.proto"],
cc_deps = [":location_data_cc_proto"],
visibility = ["//visibility:public"],
deps = [":detection_proto"],
)
java_lite_proto_library(
name = "detection_java_proto_lite",
strict_deps = 0,
visibility = ["//mediapipe:__subpackages__"],
deps = [":detection_proto"],
)
mediapipe_cc_proto_library(
name = "classification_cc_proto",
srcs = ["classification.proto"],
visibility = ["//visibility:public"],
deps = [":classification_proto"],
)
mediapipe_cc_proto_library(
name = "image_format_cc_proto",
srcs = ["image_format.proto"],
visibility = ["//visibility:public"],
deps = [":image_format_proto"],
)
mediapipe_cc_proto_library(
name = "matrix_data_cc_proto",
srcs = ["matrix_data.proto"],
visibility = ["//visibility:public"],
deps = [":matrix_data_proto"],
)
mediapipe_cc_proto_library(
name = "location_data_cc_proto",
srcs = ["location_data.proto"],
cc_deps = ["//mediapipe/framework/formats/annotation:rasterization_cc_proto"],
visibility = ["//visibility:public"],
deps = [":location_data_proto"],
)
mediapipe_cc_proto_library(
name = "time_series_header_cc_proto",
srcs = ["time_series_header.proto"],
visibility = ["//visibility:public"],
deps = [":time_series_header_proto"],
)
cc_library( cc_library(
name = "deleting_file", name = "deleting_file",
srcs = ["deleting_file.cc"], srcs = ["deleting_file.cc"],
@ -245,33 +195,14 @@ cc_test(
], ],
) )
proto_library( mediapipe_proto_library(
name = "rect_proto", name = "rect_proto",
srcs = ["rect.proto"], srcs = ["rect.proto"],
visibility = [ visibility = ["//visibility:public"],
"//visibility:public", deps = ["//mediapipe/framework/formats:location_data_proto"],
],
) )
mediapipe_cc_proto_library( mediapipe_proto_library(
name = "rect_cc_proto",
srcs = ["rect.proto"],
visibility = [
"//visibility:public",
],
deps = [":rect_proto"],
)
java_lite_proto_library(
name = "rect_java_proto_lite",
strict_deps = 0,
visibility = [
"//mediapipe:__subpackages__",
],
deps = [":rect_proto"],
)
proto_library(
name = "landmark_proto", name = "landmark_proto",
srcs = ["landmark.proto"], srcs = ["landmark.proto"],
visibility = [ visibility = [
@ -279,22 +210,6 @@ proto_library(
], ],
) )
mediapipe_cc_proto_library(
name = "landmark_cc_proto",
srcs = ["landmark.proto"],
visibility = ["//visibility:public"],
deps = [":landmark_proto"],
)
java_lite_proto_library(
name = "landmark_java_proto_lite",
strict_deps = 0,
visibility = [
"//mediapipe:__subpackages__",
],
deps = [":landmark_proto"],
)
# Expose the proto source files for building mediapipe AAR. # Expose the proto source files for building mediapipe AAR.
filegroup( filegroup(
name = "protos_src", name = "protos_src",

View File

@ -14,42 +14,28 @@
# limitations under the License. # limitations under the License.
# #
load("//mediapipe/framework/port:build_config.bzl", "mediapipe_proto_library")
package(default_visibility = ["//visibility:private"])
licenses(["notice"]) # Apache 2.0 licenses(["notice"]) # Apache 2.0
exports_files(["LICENSE"]) exports_files(["LICENSE"])
load("//mediapipe/framework/port:build_config.bzl", "mediapipe_cc_proto_library") mediapipe_proto_library(
package(default_visibility = ["//visibility:private"])
proto_library(
name = "locus_proto", name = "locus_proto",
srcs = ["locus.proto"], srcs = ["locus.proto"],
portable_deps = ["//mediapipe/framework/formats/annotation:rasterization_cc_proto"],
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = ["//mediapipe/framework/formats/annotation:rasterization_proto"], deps = ["//mediapipe/framework/formats/annotation:rasterization_proto"],
) )
proto_library( mediapipe_proto_library(
name = "rasterization_proto", name = "rasterization_proto",
srcs = ["rasterization.proto"], srcs = ["rasterization.proto"],
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
) )
mediapipe_cc_proto_library(
name = "locus_cc_proto",
srcs = ["locus.proto"],
cc_deps = [":rasterization_cc_proto"],
visibility = ["//visibility:public"],
deps = [":locus_proto"],
)
mediapipe_cc_proto_library(
name = "rasterization_cc_proto",
srcs = ["rasterization.proto"],
visibility = ["//visibility:public"],
deps = [":rasterization_proto"],
)
# Expose the proto source files for building mediapipe AAR. # Expose the proto source files for building mediapipe AAR.
filegroup( filegroup(
name = "protos_src", name = "protos_src",

View File

@ -230,8 +230,36 @@ void InputStreamHandler::FinalizeInputSet(Timestamp timestamp,
} }
} }
// Returns the default CalculatorContext.
CalculatorContext* GetCalculatorContext(CalculatorContextManager* manager) {
return (manager && manager->HasDefaultCalculatorContext())
? manager->GetDefaultCalculatorContext()
: nullptr;
}
// Logs the current queue size of an input stream.
void LogQueuedPackets(CalculatorContext* context, InputStreamManager* stream,
Packet queue_tail) {
if (context) {
TraceEvent event = TraceEvent(TraceEvent::PACKET_QUEUED)
.set_node_id(context->NodeId())
.set_input_ts(queue_tail.Timestamp())
.set_stream_id(&stream->Name())
.set_event_data(stream->QueueSize() + 1);
::mediapipe::LogEvent(context->GetProfilingContext(),
event.set_packet_ts(queue_tail.Timestamp()));
Packet queue_head = stream->QueueHead();
if (!queue_head.IsEmpty()) {
::mediapipe::LogEvent(context->GetProfilingContext(),
event.set_packet_ts(queue_head.Timestamp()));
}
}
}
void InputStreamHandler::AddPackets(CollectionItemId id, void InputStreamHandler::AddPackets(CollectionItemId id,
const std::list<Packet>& packets) { const std::list<Packet>& packets) {
LogQueuedPackets(GetCalculatorContext(calculator_context_manager_),
input_stream_managers_.Get(id), packets.back());
bool notify = false; bool notify = false;
::mediapipe::Status result = ::mediapipe::Status result =
input_stream_managers_.Get(id)->AddPackets(packets, &notify); input_stream_managers_.Get(id)->AddPackets(packets, &notify);
@ -245,6 +273,8 @@ void InputStreamHandler::AddPackets(CollectionItemId id,
void InputStreamHandler::MovePackets(CollectionItemId id, void InputStreamHandler::MovePackets(CollectionItemId id,
std::list<Packet>* packets) { std::list<Packet>* packets) {
LogQueuedPackets(GetCalculatorContext(calculator_context_manager_),
input_stream_managers_.Get(id), packets->back());
bool notify = false; bool notify = false;
::mediapipe::Status result = ::mediapipe::Status result =
input_stream_managers_.Get(id)->MovePackets(packets, &notify); input_stream_managers_.Get(id)->MovePackets(packets, &notify);
@ -307,6 +337,8 @@ SyncSet::SyncSet(InputStreamHandler* input_stream_handler,
: input_stream_handler_(input_stream_handler), : input_stream_handler_(input_stream_handler),
stream_ids_(std::move(stream_ids)) {} stream_ids_(std::move(stream_ids)) {}
void SyncSet::PrepareForRun() { last_processed_ts_ = Timestamp::Unset(); }
NodeReadiness SyncSet::GetReadiness(Timestamp* min_stream_timestamp) { NodeReadiness SyncSet::GetReadiness(Timestamp* min_stream_timestamp) {
Timestamp min_bound = Timestamp::Done(); Timestamp min_bound = Timestamp::Done();
Timestamp min_packet = Timestamp::Done(); Timestamp min_packet = Timestamp::Done();

View File

@ -201,6 +201,9 @@ class InputStreamHandler {
SyncSet(InputStreamHandler* input_stream_handler, SyncSet(InputStreamHandler* input_stream_handler,
std::vector<CollectionItemId> stream_ids); std::vector<CollectionItemId> stream_ids);
// Reinitializes this SyncSet before each CalculatorGraph run.
void PrepareForRun();
// Answers whether this stream is ready for Process or Close. // Answers whether this stream is ready for Process or Close.
NodeReadiness GetReadiness(Timestamp* min_stream_timestamp); NodeReadiness GetReadiness(Timestamp* min_stream_timestamp);

View File

@ -152,7 +152,7 @@ template <typename Container>
// If the caller is MovePackets(), packet's underlying holder should be // If the caller is MovePackets(), packet's underlying holder should be
// transferred into queue_. Otherwise, queue_ keeps a copy of the packet. // transferred into queue_. Otherwise, queue_ keeps a copy of the packet.
++num_packets_added_; ++num_packets_added_;
VLOG(2) << "Input stream:" << name_ VLOG(3) << "Input stream:" << name_
<< " has added packet at time: " << packet.Timestamp(); << " has added packet at time: " << packet.Timestamp();
if (std::is_const< if (std::is_const<
typename std::remove_reference<Container>::type>::value) { typename std::remove_reference<Container>::type>::value) {
@ -163,15 +163,15 @@ template <typename Container>
} }
queue_became_full = (!was_queue_full && max_queue_size_ != -1 && queue_became_full = (!was_queue_full && max_queue_size_ != -1 &&
queue_.size() >= max_queue_size_); queue_.size() >= max_queue_size_);
VLOG_IF(2, queue_.size() > 1) VLOG_IF(3, queue_.size() > 1)
<< "Queue size greater than 1: stream name: " << name_ << "Queue size greater than 1: stream name: " << name_
<< " queue_size: " << queue_.size(); << " queue_size: " << queue_.size();
VLOG(2) << "Input stream:" << name_ VLOG(3) << "Input stream:" << name_
<< " becomes non-empty status:" << queue_became_non_empty << " becomes non-empty status:" << queue_became_non_empty
<< " Size: " << queue_.size(); << " Size: " << queue_.size();
} }
if (queue_became_full) { if (queue_became_full) {
VLOG(2) << "Queue became full: " << Name(); VLOG(3) << "Queue became full: " << Name();
becomes_full_callback_(this, &last_reported_stream_full_); becomes_full_callback_(this, &last_reported_stream_full_);
} }
*notify = queue_became_non_empty; *notify = queue_became_non_empty;
@ -257,7 +257,7 @@ Packet InputStreamManager::PopPacketAtTimestamp(Timestamp timestamp,
next_timestamp_bound_ = timestamp.NextAllowedInStream(); next_timestamp_bound_ = timestamp.NextAllowedInStream();
} }
VLOG(2) << "Input stream " << name_ VLOG(3) << "Input stream " << name_
<< " selecting at timestamp:" << timestamp.Value() << " selecting at timestamp:" << timestamp.Value()
<< " next timestamp bound: " << next_timestamp_bound_; << " next timestamp bound: " << next_timestamp_bound_;
@ -282,13 +282,13 @@ Packet InputStreamManager::PopPacketAtTimestamp(Timestamp timestamp,
++(*num_packets_dropped); ++(*num_packets_dropped);
} }
VLOG(2) << "Input stream removed packets:" << name_ VLOG(3) << "Input stream removed packets:" << name_
<< " Size:" << queue_.size(); << " Size:" << queue_.size();
queue_became_non_full = (was_queue_full && queue_.size() < max_queue_size_); queue_became_non_full = (was_queue_full && queue_.size() < max_queue_size_);
*stream_is_done = IsDone(); *stream_is_done = IsDone();
} }
if (queue_became_non_full) { if (queue_became_non_full) {
VLOG(2) << "Queue became non-full: " << Name(); VLOG(3) << "Queue became non-full: " << Name();
becomes_not_full_callback_(this, &last_reported_stream_full_); becomes_not_full_callback_(this, &last_reported_stream_full_);
} }
return packet; return packet;
@ -302,7 +302,7 @@ Packet InputStreamManager::PopQueueHead(bool* stream_is_done) {
{ {
absl::MutexLock stream_lock(&stream_mutex_); absl::MutexLock stream_lock(&stream_mutex_);
VLOG(2) << "Input stream " << name_ << " selecting at queue head"; VLOG(3) << "Input stream " << name_ << " selecting at queue head";
// Check if queue is full. // Check if queue is full.
bool was_queue_full = bool was_queue_full =
@ -315,13 +315,13 @@ Packet InputStreamManager::PopQueueHead(bool* stream_is_done) {
packet = Packet(); packet = Packet();
} }
VLOG(2) << "Input stream removed a packet:" << name_ VLOG(3) << "Input stream removed a packet:" << name_
<< " Size:" << queue_.size(); << " Size:" << queue_.size();
queue_became_non_full = (was_queue_full && queue_.size() < max_queue_size_); queue_became_non_full = (was_queue_full && queue_.size() < max_queue_size_);
*stream_is_done = IsDone(); *stream_is_done = IsDone();
} }
if (queue_became_non_full) { if (queue_became_non_full) {
VLOG(2) << "Queue became non-full: " << Name(); VLOG(3) << "Queue became non-full: " << Name();
becomes_not_full_callback_(this, &last_reported_stream_full_); becomes_not_full_callback_(this, &last_reported_stream_full_);
} }
return packet; return packet;
@ -349,10 +349,10 @@ void InputStreamManager::SetMaxQueueSize(int max_queue_size) {
// QueueSizeCallback is called with no mutexes held. // QueueSizeCallback is called with no mutexes held.
if (!was_full && is_full) { if (!was_full && is_full) {
VLOG(2) << "Queue became full: " << Name(); VLOG(3) << "Queue became full: " << Name();
becomes_full_callback_(this, &last_reported_stream_full_); becomes_full_callback_(this, &last_reported_stream_full_);
} else if (was_full && !is_full) { } else if (was_full && !is_full) {
VLOG(2) << "Queue became non-full: " << Name(); VLOG(3) << "Queue became non-full: " << Name();
becomes_not_full_callback_(this, &last_reported_stream_full_); becomes_not_full_callback_(this, &last_reported_stream_full_);
} }
} }
@ -382,12 +382,12 @@ void InputStreamManager::ErasePacketsEarlierThan(Timestamp timestamp) {
queue_.pop_front(); queue_.pop_front();
} }
VLOG(2) << "Input stream removed packets:" << name_ VLOG(3) << "Input stream removed packets:" << name_
<< " Size:" << queue_.size(); << " Size:" << queue_.size();
queue_became_non_full = (was_queue_full && queue_.size() < max_queue_size_); queue_became_non_full = (was_queue_full && queue_.size() < max_queue_size_);
} }
if (queue_became_non_full) { if (queue_became_non_full) {
VLOG(2) << "Queue became non-full: " << Name(); VLOG(3) << "Queue became non-full: " << Name();
becomes_not_full_callback_(this, &last_reported_stream_full_); becomes_not_full_callback_(this, &last_reported_stream_full_);
} }
} }

View File

@ -164,9 +164,9 @@ void OutputStreamManager::PropagateUpdatesToMirrors(
next_timestamp_bound_ = next_timestamp_bound; next_timestamp_bound_ = next_timestamp_bound;
} }
std::list<Packet>* packets_to_propagate = output_stream_shard->OutputQueue(); std::list<Packet>* packets_to_propagate = output_stream_shard->OutputQueue();
VLOG(2) << "Output stream: " << Name() VLOG(3) << "Output stream: " << Name()
<< " queue size: " << packets_to_propagate->size(); << " queue size: " << packets_to_propagate->size();
VLOG(2) << "Output stream: " << Name() VLOG(3) << "Output stream: " << Name()
<< " next timestamp: " << next_timestamp_bound; << " next timestamp: " << next_timestamp_bound;
bool add_packets = !packets_to_propagate->empty(); bool add_packets = !packets_to_propagate->empty();
bool set_bound = bool set_bound =

View File

@ -540,11 +540,11 @@ const Holder<T>* HolderBase::As() const {
inline Packet::Packet(const Packet& packet) inline Packet::Packet(const Packet& packet)
: holder_(packet.holder_), timestamp_(packet.timestamp_) { : holder_(packet.holder_), timestamp_(packet.timestamp_) {
VLOG(2) << "Using copy constructor of " << packet.DebugString(); VLOG(4) << "Using copy constructor of " << packet.DebugString();
} }
inline Packet& Packet::operator=(const Packet& packet) { inline Packet& Packet::operator=(const Packet& packet) {
VLOG(2) << "Using copy assignment operator of " << packet.DebugString(); VLOG(4) << "Using copy assignment operator of " << packet.DebugString();
if (this != &packet) { if (this != &packet) {
holder_ = packet.holder_; holder_ = packet.holder_;
timestamp_ = packet.timestamp_; timestamp_ = packet.timestamp_;
@ -559,11 +559,11 @@ inline ::mediapipe::StatusOr<std::unique_ptr<T>> Packet::Consume() {
// Clients who use this function are responsible for ensuring that no // Clients who use this function are responsible for ensuring that no
// other thread is doing anything with this Packet. // other thread is doing anything with this Packet.
if (holder_.unique()) { if (holder_.unique()) {
VLOG(1) << "Consuming the data of " << DebugString(); VLOG(2) << "Consuming the data of " << DebugString();
::mediapipe::StatusOr<std::unique_ptr<T>> release_result = ::mediapipe::StatusOr<std::unique_ptr<T>> release_result =
holder_->As<T>()->Release(); holder_->As<T>()->Release();
if (release_result.ok()) { if (release_result.ok()) {
VLOG(1) << "Setting " << DebugString() << " to empty."; VLOG(2) << "Setting " << DebugString() << " to empty.";
holder_.reset(); holder_.reset();
} }
return release_result; return release_result;
@ -582,11 +582,11 @@ inline ::mediapipe::StatusOr<std::unique_ptr<T>> Packet::ConsumeOrCopy(
// If holder is the sole owner of the underlying data, consumes this packet. // If holder is the sole owner of the underlying data, consumes this packet.
if (!holder_->HolderIsOfType<packet_internal::ForeignHolder<T>>() && if (!holder_->HolderIsOfType<packet_internal::ForeignHolder<T>>() &&
holder_.unique()) { holder_.unique()) {
VLOG(1) << "Consuming the data of " << DebugString(); VLOG(2) << "Consuming the data of " << DebugString();
::mediapipe::StatusOr<std::unique_ptr<T>> release_result = ::mediapipe::StatusOr<std::unique_ptr<T>> release_result =
holder_->As<T>()->Release(); holder_->As<T>()->Release();
if (release_result.ok()) { if (release_result.ok()) {
VLOG(1) << "Setting " << DebugString() << " to empty."; VLOG(2) << "Setting " << DebugString() << " to empty.";
holder_.reset(); holder_.reset();
} }
if (was_copied) { if (was_copied) {
@ -594,9 +594,9 @@ inline ::mediapipe::StatusOr<std::unique_ptr<T>> Packet::ConsumeOrCopy(
} }
return release_result; return release_result;
} }
VLOG(1) << "Copying the data of " << DebugString(); VLOG(2) << "Copying the data of " << DebugString();
std::unique_ptr<T> data_ptr = absl::make_unique<T>(Get<T>()); std::unique_ptr<T> data_ptr = absl::make_unique<T>(Get<T>());
VLOG(1) << "Setting " << DebugString() << " to empty."; VLOG(2) << "Setting " << DebugString() << " to empty.";
holder_.reset(); holder_.reset();
if (was_copied) { if (was_copied) {
*was_copied = true; *was_copied = true;
@ -613,11 +613,11 @@ inline ::mediapipe::StatusOr<std::unique_ptr<T>> Packet::ConsumeOrCopy(
// If holder is the sole owner of the underlying data, consumes this packet. // If holder is the sole owner of the underlying data, consumes this packet.
if (!holder_->HolderIsOfType<packet_internal::ForeignHolder<T>>() && if (!holder_->HolderIsOfType<packet_internal::ForeignHolder<T>>() &&
holder_.unique()) { holder_.unique()) {
VLOG(1) << "Consuming the data of " << DebugString(); VLOG(2) << "Consuming the data of " << DebugString();
::mediapipe::StatusOr<std::unique_ptr<T>> release_result = ::mediapipe::StatusOr<std::unique_ptr<T>> release_result =
holder_->As<T>()->Release(); holder_->As<T>()->Release();
if (release_result.ok()) { if (release_result.ok()) {
VLOG(1) << "Setting " << DebugString() << " to empty."; VLOG(2) << "Setting " << DebugString() << " to empty.";
holder_.reset(); holder_.reset();
} }
if (was_copied) { if (was_copied) {
@ -625,7 +625,7 @@ inline ::mediapipe::StatusOr<std::unique_ptr<T>> Packet::ConsumeOrCopy(
} }
return release_result; return release_result;
} }
VLOG(1) << "Copying the data of " << DebugString(); VLOG(2) << "Copying the data of " << DebugString();
const auto& original_array = Get<T>(); const auto& original_array = Get<T>();
// Type T is bounded array type, such as int[N] and float[M]. // Type T is bounded array type, such as int[N] and float[M].
// The new operator creates a new bounded array. // The new operator creates a new bounded array.
@ -633,7 +633,7 @@ inline ::mediapipe::StatusOr<std::unique_ptr<T>> Packet::ConsumeOrCopy(
// Copies bounded array data into data_ptr. // Copies bounded array data into data_ptr.
std::copy(std::begin(original_array), std::end(original_array), std::copy(std::begin(original_array), std::end(original_array),
std::begin(*data_ptr)); std::begin(*data_ptr));
VLOG(1) << "Setting " << DebugString() << " to empty."; VLOG(2) << "Setting " << DebugString() << " to empty.";
holder_.reset(); holder_.reset();
if (was_copied) { if (was_copied) {
*was_copied = true; *was_copied = true;
@ -650,14 +650,14 @@ inline ::mediapipe::StatusOr<std::unique_ptr<T>> Packet::ConsumeOrCopy(
} }
inline Packet::Packet(Packet&& packet) { inline Packet::Packet(Packet&& packet) {
VLOG(2) << "Using move constructor of " << packet.DebugString(); VLOG(4) << "Using move constructor of " << packet.DebugString();
holder_ = std::move(packet.holder_); holder_ = std::move(packet.holder_);
timestamp_ = packet.timestamp_; timestamp_ = packet.timestamp_;
packet.timestamp_ = Timestamp::Unset(); packet.timestamp_ = Timestamp::Unset();
} }
inline Packet& Packet::operator=(Packet&& packet) { inline Packet& Packet::operator=(Packet&& packet) {
VLOG(2) << "Using move assignment operator of " << packet.DebugString(); VLOG(4) << "Using move assignment operator of " << packet.DebugString();
if (this != &packet) { if (this != &packet) {
holder_ = std::move(packet.holder_); holder_ = std::move(packet.holder_);
timestamp_ = packet.timestamp_; timestamp_ = packet.timestamp_;

View File

@ -246,6 +246,7 @@ cc_library(
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = [ deps = [
":opencv_core", ":opencv_core",
"//mediapipe/framework:port",
"//third_party:opencv", "//third_party:opencv",
], ],
) )

View File

@ -5,6 +5,98 @@
load("@com_google_protobuf//:protobuf.bzl", "cc_proto_library", "py_proto_library") load("@com_google_protobuf//:protobuf.bzl", "cc_proto_library", "py_proto_library")
def provided_args(**kwargs):
"""Returns the keyword arguments omitting None arguments."""
return {k: v for k, v in kwargs.items() if v != None}
def allowed_args(**kwargs):
"""Returns the keyword arguments allowed for proto_library().
Args:
**kwargs: the specified keyword arguments.
Returns:
the allowed keyword arguments.
"""
result = dict(kwargs)
result.pop("cc_api_version", None)
return result
# TODO: load this macro from a common helper file.
def mediapipe_proto_library(
name,
srcs,
deps = [],
visibility = None,
testonly = 0,
compatible_with = [],
def_proto = True,
def_cc_proto = True,
def_py_proto = True,
def_java_lite_proto = True,
def_portable_proto = True,
portable_deps = None):
"""Defines the proto_library targets needed for all mediapipe platforms.
Args:
name: the new proto_library target name.
srcs: the ".proto" source files to compile.
deps: the proto_library targets for all referenced protobufs.
portable_deps: the portable_proto_library targets for all referenced protobufs.
visibility: visibility of this target.
testonly: true means the proto can be used for testing only.
compatible_with: see go/target-constraints.
def_proto: define the proto_library target
def_cc_proto: define the cc_proto_library target
def_py_proto: define the py_proto_library target
def_java_lite_proto: define the java_lite_proto_library target
def_portable_proto: define the portable_proto_library target
"""
_ignore = [def_portable_proto, portable_deps]
# The proto_library targets for the compiled ".proto" source files.
proto_deps = [":" + name]
if def_proto:
native.proto_library(**allowed_args(**provided_args(
name = name,
srcs = srcs,
deps = deps,
visibility = visibility,
testonly = testonly,
cc_api_version = 2,
compatible_with = compatible_with,
)))
if def_cc_proto:
cc_deps = [dep.replace("_proto", "_cc_proto") for dep in deps]
mediapipe_cc_proto_library(**provided_args(
name = name.replace("_proto", "_cc_proto"),
srcs = srcs,
deps = proto_deps,
cc_deps = cc_deps,
visibility = visibility,
testonly = testonly,
))
if def_py_proto:
py_deps = [dep.replace("_proto", "_py_pb2") for dep in deps]
mediapipe_py_proto_library(**provided_args(
name = name.replace("_proto", "_py_pb2"),
srcs = srcs,
proto_deps = proto_deps,
py_proto_deps = py_deps,
visibility = visibility,
api_version = 2,
))
if def_java_lite_proto:
native.java_lite_proto_library(**provided_args(
name = name.replace("_proto", "_java_proto_lite"),
deps = proto_deps,
strict_deps = 0,
visibility = visibility,
))
def mediapipe_py_proto_library( def mediapipe_py_proto_library(
name, name,
srcs, srcs,
@ -21,14 +113,14 @@ def mediapipe_py_proto_library(
py_proto_deps: a list of dependency labels for Bazel use; must be py_proto_library. py_proto_deps: a list of dependency labels for Bazel use; must be py_proto_library.
""" """
_ignore = [api_version, proto_deps] _ignore = [api_version, proto_deps]
py_proto_library( py_proto_library(**provided_args(
name = name, name = name,
srcs = srcs, srcs = srcs,
visibility = visibility, visibility = visibility,
default_runtime = "@com_google_protobuf//:protobuf_python", default_runtime = "@com_google_protobuf//:protobuf_python",
protoc = "@com_google_protobuf//:protoc", protoc = "@com_google_protobuf//:protoc",
deps = py_proto_deps + ["@com_google_protobuf//:protobuf_python"], deps = py_proto_deps + ["@com_google_protobuf//:protobuf_python"],
) ))
def mediapipe_cc_proto_library(name, srcs, visibility, deps = [], cc_deps = [], testonly = 0): def mediapipe_cc_proto_library(name, srcs, visibility, deps = [], cc_deps = [], testonly = 0):
"""Generate cc_proto_library for mediapipe open source version. """Generate cc_proto_library for mediapipe open source version.
@ -41,7 +133,7 @@ def mediapipe_cc_proto_library(name, srcs, visibility, deps = [], cc_deps = [],
testonly: test only proto or not. testonly: test only proto or not.
""" """
_ignore = [deps] _ignore = [deps]
cc_proto_library( cc_proto_library(**provided_args(
name = name, name = name,
srcs = srcs, srcs = srcs,
visibility = visibility, visibility = visibility,
@ -51,4 +143,4 @@ def mediapipe_cc_proto_library(name, srcs, visibility, deps = [], cc_deps = [],
protoc = "@com_google_protobuf//:protoc", protoc = "@com_google_protobuf//:protoc",
default_runtime = "@com_google_protobuf//:protobuf", default_runtime = "@com_google_protobuf//:protobuf",
alwayslink = 1, alwayslink = 1,
) ))

View File

@ -17,6 +17,7 @@
#include <opencv2/core/version.hpp> #include <opencv2/core/version.hpp>
#include "mediapipe/framework/port.h"
#include "mediapipe/framework/port/opencv_core_inc.h" #include "mediapipe/framework/port/opencv_core_inc.h"
#ifdef CV_VERSION_EPOCH // for OpenCV 2.x #ifdef CV_VERSION_EPOCH // for OpenCV 2.x
@ -83,7 +84,7 @@ inline int fourcc(char c1, char c2, char c3, char c4) {
#include <opencv2/video.hpp> #include <opencv2/video.hpp>
#include <opencv2/videoio.hpp> #include <opencv2/videoio.hpp>
#if CV_VERSION_MAJOR == 4 #if CV_VERSION_MAJOR == 4 && !defined(MEDIAPIPE_MOBILE)
#include <opencv2/optflow.hpp> #include <opencv2/optflow.hpp>
namespace cv { namespace cv {

View File

@ -270,17 +270,15 @@ cc_library(
srcs = select({ srcs = select({
"//conditions:default": ["profiler_resource_util.cc"], "//conditions:default": ["profiler_resource_util.cc"],
"//mediapipe:android": ["profiler_resource_util_android.cc"], "//mediapipe:android": ["profiler_resource_util_android.cc"],
"//mediapipe:apple": ["profiler_resource_util_apple.cc"], "//mediapipe:ios": ["profiler_resource_util_ios.cc"],
"//mediapipe:macos": ["profiler_resource_util.cc"],
}), }),
hdrs = ["profiler_resource_util.h"], hdrs = ["profiler_resource_util.h"],
# We use Objective-C++ on iOS. # We use Objective-C++ on iOS.
copts = select({ copts = select({
"//conditions:default": [], "//conditions:default": [],
"//mediapipe:apple": [ "//mediapipe:ios": [
"-ObjC++", "-ObjC++",
], ],
"//mediapipe:macos": [],
}), }),
visibility = [ visibility = [
"//mediapipe/framework:mediapipe_internal", "//mediapipe/framework:mediapipe_internal",

View File

@ -53,6 +53,8 @@ class TraceEvent {
GPU_TASK, GPU_TASK,
DSP_TASK, DSP_TASK,
TPU_TASK, TPU_TASK,
GPU_CALIBRATION,
PACKET_QUEUED,
}; };
TraceEvent(const EventType& event_type) {} TraceEvent(const EventType& event_type) {}
TraceEvent() {} TraceEvent() {}
@ -69,6 +71,7 @@ class TraceEvent {
inline TraceEvent& set_packet_data_id(const Packet* packet) { return *this; } inline TraceEvent& set_packet_data_id(const Packet* packet) { return *this; }
inline TraceEvent& set_thread_id(int thread_id) { return *this; } inline TraceEvent& set_thread_id(int thread_id) { return *this; }
inline TraceEvent& set_is_finish(bool is_finish) { return *this; } inline TraceEvent& set_is_finish(bool is_finish) { return *this; }
inline TraceEvent& set_event_data(int64 data) { return *this; }
}; };
// Empty implementation of ProfilingContext to be used in place of the // Empty implementation of ProfilingContext to be used in place of the

View File

@ -26,6 +26,7 @@
namespace mediapipe { namespace mediapipe {
namespace { namespace {
using EventType = GraphTrace::EventType;
const absl::Duration kDefaultTraceLogInterval = absl::Milliseconds(500); const absl::Duration kDefaultTraceLogInterval = absl::Milliseconds(500);
@ -52,14 +53,18 @@ int64 GraphTracer::GetTraceLogCapacity() {
GraphTracer::GraphTracer(const ProfilerConfig& profiler_config) GraphTracer::GraphTracer(const ProfilerConfig& profiler_config)
: profiler_config_(profiler_config), trace_buffer_(GetTraceLogCapacity()) { : profiler_config_(profiler_config), trace_buffer_(GetTraceLogCapacity()) {
event_types_disabled_.resize(static_cast<int>(GraphTrace::EventType_MAX + 1)); for (int disabled : profiler_config_.trace_event_types_disabled()) {
for (int32 event_type : profiler_config_.trace_event_types_disabled()) { EventType event_type = static_cast<EventType>(disabled);
event_types_disabled_[event_type] = true; (*trace_event_registry())[event_type].set_enabled(false);
} }
} }
TraceEventRegistry* GraphTracer::trace_event_registry() {
return trace_builder_.trace_event_registry();
}
void GraphTracer::LogEvent(TraceEvent event) { void GraphTracer::LogEvent(TraceEvent event) {
if (event_types_disabled_[static_cast<int>(event.event_type)]) { if (!(*trace_event_registry())[event.event_type].enabled()) {
return; return;
} }
event.set_thread_id(GetCurrentThreadId()); event.set_thread_id(GetCurrentThreadId());

View File

@ -55,6 +55,9 @@ class GraphTracer {
// Create a tracer to record up to |capacity| recent events. // Create a tracer to record up to |capacity| recent events.
GraphTracer(const ProfilerConfig& profiler_config); GraphTracer(const ProfilerConfig& profiler_config);
// Returns the registry of trace event types.
TraceEventRegistry* trace_event_registry();
// Append a TraceEvent to the TraceBuffer. // Append a TraceEvent to the TraceBuffer.
void LogEvent(TraceEvent event); void LogEvent(TraceEvent event);
@ -85,9 +88,6 @@ class GraphTracer {
// The settings for this tracer. // The settings for this tracer.
ProfilerConfig profiler_config_; ProfilerConfig profiler_config_;
// Indicates event types that will not be logged.
std::vector<bool> event_types_disabled_;
// The circular buffer of TraceEvents. // The circular buffer of TraceEvents.
TraceBuffer trace_buffer_; TraceBuffer trace_buffer_;

View File

@ -161,7 +161,7 @@ TEST_F(GraphTracerTest, CalculatorTrace) {
finish_time: 0 finish_time: 0
packet_timestamp: 0 packet_timestamp: 0
stream_id: 1 stream_id: 1
packet_id: 1 event_data: 1
} }
output_trace { packet_timestamp: 0 stream_id: 2 } output_trace { packet_timestamp: 0 stream_id: 2 }
} }
@ -236,7 +236,7 @@ TEST_F(GraphTracerTest, GraphTrace) {
finish_time: 0 finish_time: 0
packet_timestamp: 0 packet_timestamp: 0
stream_id: 1 stream_id: 1
packet_id: 1 event_data: 1
} }
output_trace { packet_timestamp: 0 stream_id: 2 } output_trace { packet_timestamp: 0 stream_id: 2 }
output_trace { packet_timestamp: 0 stream_id: 3 } output_trace { packet_timestamp: 0 stream_id: 3 }
@ -254,7 +254,7 @@ TEST_F(GraphTracerTest, GraphTrace) {
finish_time: 11000 finish_time: 11000
packet_timestamp: 0 packet_timestamp: 0
stream_id: 2 stream_id: 2
packet_id: 2 event_data: 2
} }
output_trace { packet_timestamp: 0 stream_id: 4 } output_trace { packet_timestamp: 0 stream_id: 4 }
} }
@ -270,7 +270,7 @@ TEST_F(GraphTracerTest, GraphTrace) {
finish_time: 16000 finish_time: 16000
packet_timestamp: 0 packet_timestamp: 0
stream_id: 3 stream_id: 3
packet_id: 3 event_data: 3
} }
output_trace { packet_timestamp: 0 stream_id: 5 } output_trace { packet_timestamp: 0 stream_id: 5 }
} }
@ -286,7 +286,7 @@ TEST_F(GraphTracerTest, GraphTrace) {
finish_time: 38000 finish_time: 38000
packet_timestamp: 5 packet_timestamp: 5
stream_id: 3 stream_id: 3
packet_id: 4 event_data: 4
} }
output_trace { packet_timestamp: 5 stream_id: 5 } output_trace { packet_timestamp: 5 stream_id: 5 }
} }
@ -452,12 +452,15 @@ class GraphTracerE2ETest : public ::testing::Test {
} }
} }
void StripDataIds(GraphTrace* trace) { void StripDataIds(GraphTrace* trace) {
TraceBuilder builder;
for (auto& ct : *trace->mutable_calculator_trace()) { for (auto& ct : *trace->mutable_calculator_trace()) {
for (auto& st : *ct.mutable_input_trace()) { if ((*builder.trace_event_registry())[ct.event_type()].id_event_data()) {
st.clear_packet_id(); for (auto& st : *ct.mutable_input_trace()) {
} st.clear_event_data();
for (auto& st : *ct.mutable_output_trace()) { }
st.clear_packet_id(); for (auto& st : *ct.mutable_output_trace()) {
st.clear_event_data();
}
} }
} }
} }
@ -656,63 +659,81 @@ TEST_F(GraphTracerE2ETest, DemuxGraphLog) {
calculator_trace { node_id: 1 input_timestamp: 10000 } calculator_trace { node_id: 1 input_timestamp: 10000 }
calculator_trace { node_id: 1 input_timestamp: 10000 } calculator_trace { node_id: 1 input_timestamp: 10000 }
calculator_trace { node_id: 1 input_timestamp: 10000 } calculator_trace { node_id: 1 input_timestamp: 10000 }
calculator_trace { node_id: 1 input_timestamp: 10000 }
calculator_trace { node_id: 2 input_timestamp: 10000 }
calculator_trace { node_id: 2 input_timestamp: 10000 } calculator_trace { node_id: 2 input_timestamp: 10000 }
calculator_trace { node_id: 1 input_timestamp: 10000 } calculator_trace { node_id: 1 input_timestamp: 10000 }
calculator_trace { node_id: 2 input_timestamp: 10000 } calculator_trace { node_id: 2 input_timestamp: 10000 }
calculator_trace { node_id: 2 input_timestamp: 10000 } calculator_trace { node_id: 2 input_timestamp: 10000 }
calculator_trace { node_id: 3 input_timestamp: 10000 } calculator_trace { node_id: 3 input_timestamp: 10000 }
calculator_trace { node_id: 3 input_timestamp: 10000 }
calculator_trace { node_id: 2 input_timestamp: 10000 } calculator_trace { node_id: 2 input_timestamp: 10000 }
calculator_trace { node_id: 3 input_timestamp: 10000 } calculator_trace { node_id: 3 input_timestamp: 10000 }
calculator_trace { node_id: 0 input_timestamp: 20000 } calculator_trace { node_id: 0 input_timestamp: 20000 }
calculator_trace { node_id: 1 input_timestamp: 20000 }
calculator_trace { node_id: 1 input_timestamp: 10000 } calculator_trace { node_id: 1 input_timestamp: 10000 }
calculator_trace { node_id: 1 input_timestamp: 20000 } calculator_trace { node_id: 1 input_timestamp: 20000 }
calculator_trace { node_id: 1 input_timestamp: 20000 } calculator_trace { node_id: 1 input_timestamp: 20000 }
calculator_trace { node_id: 2 input_timestamp: 20000 }
calculator_trace { node_id: 2 input_timestamp: 10000 } calculator_trace { node_id: 2 input_timestamp: 10000 }
calculator_trace { node_id: 1 input_timestamp: 10000 } calculator_trace { node_id: 1 input_timestamp: 10000 }
calculator_trace { node_id: 2 input_timestamp: 20000 } calculator_trace { node_id: 2 input_timestamp: 20000 }
calculator_trace { node_id: 2 input_timestamp: 20000 } calculator_trace { node_id: 2 input_timestamp: 20000 }
calculator_trace { node_id: 4 input_timestamp: 20000 }
calculator_trace { node_id: 4 input_timestamp: 10000 } calculator_trace { node_id: 4 input_timestamp: 10000 }
calculator_trace { node_id: 2 input_timestamp: 10000 } calculator_trace { node_id: 2 input_timestamp: 10000 }
calculator_trace { node_id: 4 input_timestamp: 20000 } calculator_trace { node_id: 4 input_timestamp: 20000 }
calculator_trace { node_id: 0 input_timestamp: 30000 } calculator_trace { node_id: 0 input_timestamp: 30000 }
calculator_trace { node_id: 1 input_timestamp: 30000 }
calculator_trace { node_id: 1 input_timestamp: 10000 } calculator_trace { node_id: 1 input_timestamp: 10000 }
calculator_trace { node_id: 1 input_timestamp: 30000 } calculator_trace { node_id: 1 input_timestamp: 30000 }
calculator_trace { node_id: 1 input_timestamp: 30000 } calculator_trace { node_id: 1 input_timestamp: 30000 }
calculator_trace { node_id: 2 input_timestamp: 30000 }
calculator_trace { node_id: 2 input_timestamp: 10000 } calculator_trace { node_id: 2 input_timestamp: 10000 }
calculator_trace { node_id: 1 input_timestamp: 10000 } calculator_trace { node_id: 1 input_timestamp: 10000 }
calculator_trace { node_id: 2 input_timestamp: 30000 } calculator_trace { node_id: 2 input_timestamp: 30000 }
calculator_trace { node_id: 2 input_timestamp: 30000 } calculator_trace { node_id: 2 input_timestamp: 30000 }
calculator_trace { node_id: 3 input_timestamp: 30000 }
calculator_trace { node_id: 2 input_timestamp: 10000 } calculator_trace { node_id: 2 input_timestamp: 10000 }
calculator_trace { node_id: 0 input_timestamp: 40000 } calculator_trace { node_id: 0 input_timestamp: 40000 }
calculator_trace { node_id: 1 input_timestamp: 40000 }
calculator_trace { node_id: 1 input_timestamp: 10000 } calculator_trace { node_id: 1 input_timestamp: 10000 }
calculator_trace { node_id: 1 input_timestamp: 40000 } calculator_trace { node_id: 1 input_timestamp: 40000 }
calculator_trace { node_id: 1 input_timestamp: 40000 } calculator_trace { node_id: 1 input_timestamp: 40000 }
calculator_trace { node_id: 2 input_timestamp: 40000 }
calculator_trace { node_id: 2 input_timestamp: 10000 } calculator_trace { node_id: 2 input_timestamp: 10000 }
calculator_trace { node_id: 1 input_timestamp: 10000 } calculator_trace { node_id: 1 input_timestamp: 10000 }
calculator_trace { node_id: 2 input_timestamp: 40000 } calculator_trace { node_id: 2 input_timestamp: 40000 }
calculator_trace { node_id: 2 input_timestamp: 40000 } calculator_trace { node_id: 2 input_timestamp: 40000 }
calculator_trace { node_id: 4 input_timestamp: 40000 }
calculator_trace { node_id: 2 input_timestamp: 10000 } calculator_trace { node_id: 2 input_timestamp: 10000 }
calculator_trace { node_id: 3 input_timestamp: 10000 } calculator_trace { node_id: 3 input_timestamp: 10000 }
calculator_trace { node_id: 5 input_timestamp: 10000 } calculator_trace { node_id: 5 input_timestamp: 10000 }
calculator_trace { node_id: 5 input_timestamp: 10000 }
calculator_trace { node_id: 3 input_timestamp: 10000 } calculator_trace { node_id: 3 input_timestamp: 10000 }
calculator_trace { node_id: 5 input_timestamp: 10000 } calculator_trace { node_id: 5 input_timestamp: 10000 }
calculator_trace { node_id: 5 input_timestamp: 10000 } calculator_trace { node_id: 5 input_timestamp: 10000 }
calculator_trace { node_id: 5 input_timestamp: 10000 } calculator_trace { node_id: 5 input_timestamp: 10000 }
calculator_trace { node_id: 1 input_timestamp: 10000 } calculator_trace { node_id: 1 input_timestamp: 10000 }
calculator_trace { node_id: 1 input_timestamp: 10000 }
calculator_trace { node_id: 5 input_timestamp: 10000 } calculator_trace { node_id: 5 input_timestamp: 10000 }
calculator_trace { node_id: 3 input_timestamp: 30000 } calculator_trace { node_id: 3 input_timestamp: 30000 }
calculator_trace { node_id: 1 input_timestamp: 10000 } calculator_trace { node_id: 1 input_timestamp: 10000 }
calculator_trace { node_id: 1 input_timestamp: 10000 } calculator_trace { node_id: 1 input_timestamp: 10000 }
calculator_trace { node_id: 0 input_timestamp: 50000 } calculator_trace { node_id: 0 input_timestamp: 50000 }
calculator_trace { node_id: 1 input_timestamp: 50000 }
calculator_trace { node_id: 1 input_timestamp: 10000 } calculator_trace { node_id: 1 input_timestamp: 10000 }
calculator_trace { node_id: 1 input_timestamp: 50000 } calculator_trace { node_id: 1 input_timestamp: 50000 }
calculator_trace { node_id: 1 input_timestamp: 50000 } calculator_trace { node_id: 1 input_timestamp: 50000 }
calculator_trace { node_id: 2 input_timestamp: 50000 }
calculator_trace { node_id: 2 input_timestamp: 10000 } calculator_trace { node_id: 2 input_timestamp: 10000 }
calculator_trace { node_id: 1 input_timestamp: 10000 } calculator_trace { node_id: 1 input_timestamp: 10000 }
calculator_trace { node_id: 2 input_timestamp: 50000 } calculator_trace { node_id: 2 input_timestamp: 50000 }
calculator_trace { node_id: 2 input_timestamp: 50000 } calculator_trace { node_id: 2 input_timestamp: 50000 }
calculator_trace { node_id: 3 input_timestamp: 50000 }
calculator_trace { node_id: 2 input_timestamp: 10000 } calculator_trace { node_id: 2 input_timestamp: 10000 }
calculator_trace { node_id: 0 input_timestamp: 60000 } calculator_trace { node_id: 0 input_timestamp: 60000 }
calculator_trace { node_id: 1 input_timestamp: 60000 }
calculator_trace { node_id: 1 input_timestamp: 10000 } calculator_trace { node_id: 1 input_timestamp: 10000 }
calculator_trace { node_id: 1 input_timestamp: 60000 } calculator_trace { node_id: 1 input_timestamp: 60000 }
calculator_trace { node_id: 2 input_timestamp: 10000 } calculator_trace { node_id: 2 input_timestamp: 10000 }
@ -721,33 +742,39 @@ TEST_F(GraphTracerE2ETest, DemuxGraphLog) {
calculator_trace { node_id: 2 input_timestamp: 10000 } calculator_trace { node_id: 2 input_timestamp: 10000 }
calculator_trace { node_id: 1 input_timestamp: 10000 } calculator_trace { node_id: 1 input_timestamp: 10000 }
calculator_trace { node_id: 4 input_timestamp: 20000 } calculator_trace { node_id: 4 input_timestamp: 20000 }
calculator_trace { node_id: 5 input_timestamp: 20000 }
calculator_trace { node_id: 5 input_timestamp: 10000 } calculator_trace { node_id: 5 input_timestamp: 10000 }
calculator_trace { node_id: 4 input_timestamp: 10000 } calculator_trace { node_id: 4 input_timestamp: 10000 }
calculator_trace { node_id: 5 input_timestamp: 20000 } calculator_trace { node_id: 5 input_timestamp: 20000 }
calculator_trace { node_id: 5 input_timestamp: 20000 } calculator_trace { node_id: 5 input_timestamp: 20000 }
calculator_trace { node_id: 5 input_timestamp: 20000 } calculator_trace { node_id: 5 input_timestamp: 20000 }
calculator_trace { node_id: 1 input_timestamp: 20000 }
calculator_trace { node_id: 1 input_timestamp: 10000 } calculator_trace { node_id: 1 input_timestamp: 10000 }
calculator_trace { node_id: 5 input_timestamp: 10000 } calculator_trace { node_id: 5 input_timestamp: 10000 }
calculator_trace { node_id: 4 input_timestamp: 40000 } calculator_trace { node_id: 4 input_timestamp: 40000 }
calculator_trace { node_id: 1 input_timestamp: 20000 } calculator_trace { node_id: 1 input_timestamp: 20000 }
calculator_trace { node_id: 1 input_timestamp: 10000 } calculator_trace { node_id: 1 input_timestamp: 10000 }
calculator_trace { node_id: 3 input_timestamp: 30000 } calculator_trace { node_id: 3 input_timestamp: 30000 }
calculator_trace { node_id: 5 input_timestamp: 30000 }
calculator_trace { node_id: 5 input_timestamp: 10000 } calculator_trace { node_id: 5 input_timestamp: 10000 }
calculator_trace { node_id: 3 input_timestamp: 10000 } calculator_trace { node_id: 3 input_timestamp: 10000 }
calculator_trace { node_id: 5 input_timestamp: 30000 } calculator_trace { node_id: 5 input_timestamp: 30000 }
calculator_trace { node_id: 5 input_timestamp: 30000 } calculator_trace { node_id: 5 input_timestamp: 30000 }
calculator_trace { node_id: 5 input_timestamp: 30000 } calculator_trace { node_id: 5 input_timestamp: 30000 }
calculator_trace { node_id: 1 input_timestamp: 30000 }
calculator_trace { node_id: 1 input_timestamp: 10000 } calculator_trace { node_id: 1 input_timestamp: 10000 }
calculator_trace { node_id: 5 input_timestamp: 10000 } calculator_trace { node_id: 5 input_timestamp: 10000 }
calculator_trace { node_id: 3 input_timestamp: 50000 } calculator_trace { node_id: 3 input_timestamp: 50000 }
calculator_trace { node_id: 1 input_timestamp: 30000 } calculator_trace { node_id: 1 input_timestamp: 30000 }
calculator_trace { node_id: 1 input_timestamp: 10000 } calculator_trace { node_id: 1 input_timestamp: 10000 }
calculator_trace { node_id: 3 input_timestamp: 50000 } calculator_trace { node_id: 3 input_timestamp: 50000 }
calculator_trace { node_id: 5 input_timestamp: 50000 }
calculator_trace { node_id: 5 input_timestamp: 10000 } calculator_trace { node_id: 5 input_timestamp: 10000 }
calculator_trace { node_id: 3 input_timestamp: 10000 } calculator_trace { node_id: 3 input_timestamp: 10000 }
calculator_trace { node_id: 5 input_timestamp: 50000 } calculator_trace { node_id: 5 input_timestamp: 50000 }
calculator_trace { node_id: 5 input_timestamp: 50000 } calculator_trace { node_id: 5 input_timestamp: 50000 }
calculator_trace { node_id: 5 input_timestamp: 50000 } calculator_trace { node_id: 5 input_timestamp: 50000 }
calculator_trace { node_id: 1 input_timestamp: 50000 }
calculator_trace { node_id: 1 input_timestamp: 10000 } calculator_trace { node_id: 1 input_timestamp: 10000 }
calculator_trace { node_id: 5 input_timestamp: 10000 } calculator_trace { node_id: 5 input_timestamp: 10000 }
calculator_trace { node_id: 5 input_timestamp: 10000 } calculator_trace { node_id: 5 input_timestamp: 10000 }
@ -755,16 +782,17 @@ TEST_F(GraphTracerE2ETest, DemuxGraphLog) {
calculator_trace { node_id: 1 input_timestamp: 50000 } calculator_trace { node_id: 1 input_timestamp: 50000 }
calculator_trace { node_id: 1 input_timestamp: 10000 } calculator_trace { node_id: 1 input_timestamp: 10000 }
calculator_trace { node_id: 4 input_timestamp: 40000 } calculator_trace { node_id: 4 input_timestamp: 40000 }
calculator_trace { node_id: 5 input_timestamp: 40000 }
calculator_trace { node_id: 5 input_timestamp: 10000 } calculator_trace { node_id: 5 input_timestamp: 10000 }
calculator_trace { node_id: 4 input_timestamp: 10000 } calculator_trace { node_id: 4 input_timestamp: 10000 }
calculator_trace { node_id: 5 input_timestamp: 40000 } calculator_trace { node_id: 5 input_timestamp: 40000 }
calculator_trace { node_id: 5 input_timestamp: 40000 } calculator_trace { node_id: 5 input_timestamp: 40000 }
calculator_trace { node_id: 1 input_timestamp: 50001 }
calculator_trace { node_id: 1 input_timestamp: 10000 } calculator_trace { node_id: 1 input_timestamp: 10000 }
calculator_trace { node_id: 5 input_timestamp: 10000 } calculator_trace { node_id: 5 input_timestamp: 10000 }
calculator_trace { node_id: 5 input_timestamp: 10000 } calculator_trace { node_id: 5 input_timestamp: 10000 }
calculator_trace { node_id: 1 input_timestamp: 50001 } calculator_trace { node_id: 1 input_timestamp: 50001 }
calculator_trace { node_id: 1 input_timestamp: 10000 } calculator_trace { node_id: 1 input_timestamp: 10000 })")));
)")));
// Validate a one-timestamp slice of the event trace. // Validate a one-timestamp slice of the event trace.
GraphTrace trace_2; GraphTrace trace_2;
@ -773,142 +801,179 @@ TEST_F(GraphTracerE2ETest, DemuxGraphLog) {
&trace_2); &trace_2);
StripThreadIds(&trace_2); StripThreadIds(&trace_2);
StripDataIds(&trace_2); StripDataIds(&trace_2);
EXPECT_THAT(trace_2, EXPECT_THAT(
EqualsProto(::mediapipe::ParseTextProtoOrDie<GraphTrace>( trace_2,
R"( EqualsProto(::mediapipe::ParseTextProtoOrDie<GraphTrace>(
base_time: 1544086800000000 R"(
base_timestamp: 10000 base_time: 1544086800000000
stream_name: "" base_timestamp: 10000
stream_name: "input_packets_0" stream_name: ""
stream_name: "input_0_sampled" stream_name: "input_packets_0"
stream_name: "input_0" stream_name: "input_0_sampled"
stream_name: "input_1" stream_name: "input_0"
stream_name: "output_0" stream_name: "input_1"
stream_name: "output_packets_0" stream_name: "output_0"
stream_name: "finish_indicator" stream_name: "output_packets_0"
stream_name: "output_1" stream_name: "finish_indicator"
calculator_trace { stream_name: "output_1"
node_id: 3 calculator_trace {
input_timestamp: 0 node_id: 3
event_type: PROCESS input_timestamp: 0
finish_time: 25002 event_type: PROCESS
output_trace { packet_timestamp: 0 stream_id: 5 } finish_time: 25002
} output_trace { packet_timestamp: 0 stream_id: 5 }
calculator_trace { }
node_id: 5 calculator_trace {
event_type: READY_FOR_PROCESS node_id: 5
start_time: 25002 input_timestamp: 0
} event_type: PACKET_QUEUED
calculator_trace { start_time: 25002
node_id: 3 input_trace { packet_timestamp: 0 stream_id: 5 event_data: 1 }
event_type: READY_FOR_PROCESS }
start_time: 25002 calculator_trace {
} node_id: 5
calculator_trace { event_type: READY_FOR_PROCESS
node_id: 5 start_time: 25002
input_timestamp: 0 }
event_type: PROCESS calculator_trace {
start_time: 25002 node_id: 3
input_trace { packet_timestamp: 0 stream_id: 5 } event_type: READY_FOR_PROCESS
} start_time: 25002
calculator_trace { }
node_id: 5 calculator_trace {
input_timestamp: 0 node_id: 5
event_type: PROCESS input_timestamp: 0
finish_time: 25002 event_type: PROCESS
output_trace { packet_timestamp: 0 stream_id: 6 } start_time: 25002
} input_trace { packet_timestamp: 0 stream_id: 5 }
calculator_trace { }
node_id: 5 calculator_trace {
input_timestamp: 0 node_id: 5
event_type: PROCESS input_timestamp: 0
finish_time: 25002 event_type: PROCESS
output_trace { packet_timestamp: 0 stream_id: 7 } finish_time: 25002
} output_trace { packet_timestamp: 0 stream_id: 6 }
calculator_trace { }
node_id: 1 calculator_trace {
event_type: READY_FOR_PROCESS node_id: 5
start_time: 25002 input_timestamp: 0
} event_type: PROCESS
calculator_trace { finish_time: 25002
node_id: 5 output_trace { packet_timestamp: 0 stream_id: 7 }
event_type: NOT_READY }
start_time: 25002 calculator_trace {
} node_id: 1
calculator_trace { input_timestamp: 0
node_id: 3 event_type: PACKET_QUEUED
input_timestamp: 20000 start_time: 25002
event_type: PROCESS input_trace { packet_timestamp: 0 stream_id: 7 event_data: 1 }
start_time: 25002 }
input_trace { packet_timestamp: 20000 stream_id: 3 } calculator_trace {
} node_id: 1
calculator_trace { event_type: READY_FOR_PROCESS
node_id: 1 start_time: 25002
input_timestamp: 0 }
event_type: PROCESS calculator_trace {
start_time: 25002 node_id: 5
input_trace { packet_timestamp: 0 stream_id: 7 } event_type: NOT_READY
} start_time: 25002
calculator_trace { }
node_id: 1 calculator_trace {
event_type: NOT_READY node_id: 3
start_time: 25002 input_timestamp: 20000
} event_type: PROCESS
calculator_trace { start_time: 25002
node_id: 0 input_trace { packet_timestamp: 20000 stream_id: 3 }
input_timestamp: 40000 }
event_type: PROCESS calculator_trace {
finish_time: 25005 node_id: 1
output_trace { packet_timestamp: 40000 stream_id: 1 } input_timestamp: 0
} event_type: PROCESS
calculator_trace { start_time: 25002
node_id: 1 input_trace { packet_timestamp: 0 stream_id: 7 }
event_type: READY_FOR_PROCESS }
start_time: 25005 calculator_trace {
} node_id: 1
calculator_trace { event_type: NOT_READY
node_id: 1 start_time: 25002
input_timestamp: 40000 }
event_type: PROCESS calculator_trace {
start_time: 25005 node_id: 0
input_trace { packet_timestamp: 40000 stream_id: 1 } input_timestamp: 40000
} event_type: PROCESS
calculator_trace { finish_time: 25005
node_id: 1 output_trace { packet_timestamp: 40000 stream_id: 1 }
input_timestamp: 40000 }
event_type: PROCESS calculator_trace {
finish_time: 25005 node_id: 1
output_trace { packet_timestamp: 40000 stream_id: 2 } input_timestamp: 40000
} event_type: PACKET_QUEUED
calculator_trace { start_time: 25005
node_id: 2 input_trace { packet_timestamp: 40000 stream_id: 1 event_data: 1 }
event_type: READY_FOR_PROCESS }
start_time: 25005 calculator_trace {
} node_id: 1
calculator_trace { event_type: READY_FOR_PROCESS
node_id: 1 start_time: 25005
event_type: NOT_READY }
start_time: 25005 calculator_trace {
} node_id: 1
calculator_trace { input_timestamp: 40000
node_id: 2 event_type: PROCESS
input_timestamp: 40000 start_time: 25005
event_type: PROCESS input_trace { packet_timestamp: 40000 stream_id: 1 }
start_time: 25005 }
input_trace { packet_timestamp: 40000 stream_id: 2 } calculator_trace {
} node_id: 1
calculator_trace { input_timestamp: 40000
node_id: 2 event_type: PROCESS
input_timestamp: 40000 finish_time: 25005
event_type: PROCESS output_trace { packet_timestamp: 40000 stream_id: 2 }
finish_time: 25005 }
output_trace { packet_timestamp: 40000 stream_id: 3 } calculator_trace {
} node_id: 2
calculator_trace { input_timestamp: 40000
node_id: 2 event_type: PACKET_QUEUED
event_type: NOT_READY start_time: 25005
start_time: 25005 input_trace { packet_timestamp: 40000 stream_id: 2 event_data: 1 }
})"))); }
calculator_trace {
node_id: 2
event_type: READY_FOR_PROCESS
start_time: 25005
}
calculator_trace {
node_id: 1
event_type: NOT_READY
start_time: 25005
}
calculator_trace {
node_id: 2
input_timestamp: 40000
event_type: PROCESS
start_time: 25005
input_trace { packet_timestamp: 40000 stream_id: 2 }
}
calculator_trace {
node_id: 2
input_timestamp: 40000
event_type: PROCESS
finish_time: 25005
output_trace { packet_timestamp: 40000 stream_id: 3 }
}
calculator_trace {
node_id: 3
input_timestamp: 40000
event_type: PACKET_QUEUED
start_time: 25005
input_trace { packet_timestamp: 40000 stream_id: 3 event_data: 1 }
}
calculator_trace {
node_id: 2
event_type: NOT_READY
start_time: 25005
}
)")));
} }
// Read a GraphProfile from a file path. // Read a GraphProfile from a file path.
@ -931,7 +996,7 @@ TEST_F(GraphTracerE2ETest, DemuxGraphLogFile) {
GraphProfile profile; GraphProfile profile;
MP_EXPECT_OK( MP_EXPECT_OK(
ReadGraphProfile(absl::StrCat(log_path, 0, ".binarypb"), &profile)); ReadGraphProfile(absl::StrCat(log_path, 0, ".binarypb"), &profile));
EXPECT_EQ(89, profile.graph_trace(0).calculator_trace().size()); EXPECT_EQ(111, profile.graph_trace(0).calculator_trace().size());
} }
TEST_F(GraphTracerE2ETest, DemuxGraphLogFiles) { TEST_F(GraphTracerE2ETest, DemuxGraphLogFiles) {
@ -956,7 +1021,11 @@ TEST_F(GraphTracerE2ETest, DemuxGraphLogFiles) {
graph_profiles.push_back(profile); graph_profiles.push_back(profile);
} }
} }
std::vector<int> expected = {37, 52, 9};
// The expected counts of calculator_trace records in each of the log files.
// The processing spans three 12.5ms log files, because
// RunDemuxInFlightGraph adds packets over 30ms.
std::vector<int> expected = {49, 64, 11};
EXPECT_EQ(event_counts, expected); EXPECT_EQ(event_counts, expected);
GraphProfile& profile_2 = graph_profiles[2]; GraphProfile& profile_2 = graph_profiles[2];
profile_2.clear_calculator_profiles(); profile_2.clear_calculator_profiles();
@ -992,6 +1061,18 @@ TEST_F(GraphTracerE2ETest, DemuxGraphLogFiles) {
finish_time: 70004 finish_time: 70004
output_trace { packet_timestamp: 40000 stream_id: 8 } output_trace { packet_timestamp: 40000 stream_id: 8 }
} }
calculator_trace {
node_id: 5
input_timestamp: 40000
event_type: PACKET_QUEUED
start_time: 70004
input_trace {
finish_time: 70004
packet_timestamp: 40000
stream_id: 8
event_data: 1
}
}
calculator_trace { calculator_trace {
node_id: 5 node_id: 5
event_type: READY_FOR_PROCESS event_type: READY_FOR_PROCESS
@ -1016,6 +1097,18 @@ TEST_F(GraphTracerE2ETest, DemuxGraphLogFiles) {
} }
output_trace { packet_timestamp: 50001 stream_id: 7 } output_trace { packet_timestamp: 50001 stream_id: 7 }
} }
calculator_trace {
node_id: 1
input_timestamp: 50001
event_type: PACKET_QUEUED
start_time: 70004
input_trace {
finish_time: 70004
packet_timestamp: 50001
stream_id: 7
event_data: 1
}
}
calculator_trace { calculator_trace {
node_id: 1 node_id: 1
event_type: READY_FOR_PROCESS event_type: READY_FOR_PROCESS
@ -1199,7 +1292,7 @@ TEST_F(GraphTracerE2ETest, GpuTaskTrace) {
finish_time: 0 finish_time: 0
packet_timestamp: 0 packet_timestamp: 0
stream_id: 1 stream_id: 1
packet_id: 0 event_data: 0
} }
output_trace { packet_timestamp: 0 stream_id: 2 } output_trace { packet_timestamp: 0 stream_id: 2 }
thread_id: 0 thread_id: 0
@ -1231,7 +1324,7 @@ TEST_F(GraphTracerE2ETest, GpuTaskTrace) {
input_timestamp: 0 input_timestamp: 0
event_type: PROCESS event_type: PROCESS
start_time: 0 start_time: 0
input_trace { packet_timestamp: 0 stream_id: 1 packet_id: 0 } input_trace { packet_timestamp: 0 stream_id: 1 event_data: 0 }
thread_id: 0 thread_id: 0
} }
calculator_trace { calculator_trace {
@ -1253,7 +1346,7 @@ TEST_F(GraphTracerE2ETest, GpuTaskTrace) {
input_timestamp: 0 input_timestamp: 0
event_type: PROCESS event_type: PROCESS
finish_time: 1000 finish_time: 1000
output_trace { packet_timestamp: 0 stream_id: 2 packet_id: 0 } output_trace { packet_timestamp: 0 stream_id: 2 event_data: 0 }
thread_id: 0 thread_id: 0
} }
)"))); )")));

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -23,45 +23,29 @@
namespace mediapipe { namespace mediapipe {
// Packet content identifier.
using PacketDataId = const void*;
namespace packet_internal { namespace packet_internal {
// Returns the packet data address for a packet data holder. // Returns a hash of the packet data address from a packet data holder.
inline const void* GetPacketDataId(const HolderBase* holder) { inline const int64 GetPacketDataId(const HolderBase* holder) {
return (holder == nullptr) if (holder == nullptr) {
? nullptr return 0;
: &(static_cast<const Holder<int>*>(holder)->data()); }
const void* address = &(static_cast<const Holder<int>*>(holder)->data());
return reinterpret_cast<int64>(address);
} }
} // namespace packet_internal } // namespace packet_internal
// Packet trace log event. // Packet trace log event.
struct TraceEvent { struct TraceEvent {
using EventType = GraphTrace::EventType; using EventType = GraphTrace::EventType;
// GraphTrace::EventType constants, repeated here to match GraphProfilerStub.
static constexpr EventType UNKNOWN = GraphTrace::UNKNOWN;
static constexpr EventType OPEN = GraphTrace::OPEN;
static constexpr EventType PROCESS = GraphTrace::PROCESS;
static constexpr EventType CLOSE = GraphTrace::CLOSE;
static constexpr EventType NOT_READY = GraphTrace::NOT_READY;
static constexpr EventType READY_FOR_PROCESS = GraphTrace::READY_FOR_PROCESS;
static constexpr EventType READY_FOR_CLOSE = GraphTrace::READY_FOR_CLOSE;
static constexpr EventType THROTTLED = GraphTrace::THROTTLED;
static constexpr EventType UNTHROTTLED = GraphTrace::UNTHROTTLED;
static constexpr EventType CPU_TASK_USER = GraphTrace::CPU_TASK_USER;
static constexpr EventType CPU_TASK_SYSTEM = GraphTrace::CPU_TASK_SYSTEM;
static constexpr EventType GPU_TASK = GraphTrace::GPU_TASK;
static constexpr EventType DSP_TASK = GraphTrace::DSP_TASK;
static constexpr EventType TPU_TASK = GraphTrace::TPU_TASK;
absl::Time event_time; absl::Time event_time;
EventType event_type = UNKNOWN; EventType event_type = UNKNOWN;
bool is_finish = false; bool is_finish = false;
Timestamp input_ts = Timestamp::Unset(); Timestamp input_ts = Timestamp::Unset();
Timestamp packet_ts = Timestamp::Unset(); Timestamp packet_ts = Timestamp::Unset();
int node_id = -1; int32 node_id = -1;
const std::string* stream_id = nullptr; const std::string* stream_id = nullptr;
PacketDataId packet_data_id = 0; int32 thread_id = 0;
int thread_id = 0; int64 event_data = 0;
TraceEvent(const EventType& event_type) : event_type(event_type) {} TraceEvent(const EventType& event_type) : event_type(event_type) {}
TraceEvent() {} TraceEvent() {}
@ -91,7 +75,7 @@ struct TraceEvent {
return *this; return *this;
} }
inline TraceEvent& set_packet_data_id(const Packet* packet) { inline TraceEvent& set_packet_data_id(const Packet* packet) {
this->packet_data_id = this->event_data =
packet_internal::GetPacketDataId(packet_internal::GetHolder(*packet)); packet_internal::GetPacketDataId(packet_internal::GetHolder(*packet));
return *this; return *this;
} }
@ -103,11 +87,84 @@ struct TraceEvent {
this->is_finish = is_finish; this->is_finish = is_finish;
return *this; return *this;
} }
inline TraceEvent& set_event_data(int data) {
this->event_data = data;
return *this;
}
// GraphTrace::EventType constants, repeated here to match GraphProfilerStub.
static constexpr EventType UNKNOWN = GraphTrace::UNKNOWN;
static constexpr EventType OPEN = GraphTrace::OPEN;
static constexpr EventType PROCESS = GraphTrace::PROCESS;
static constexpr EventType CLOSE = GraphTrace::CLOSE;
static constexpr EventType NOT_READY = GraphTrace::NOT_READY;
static constexpr EventType READY_FOR_PROCESS = GraphTrace::READY_FOR_PROCESS;
static constexpr EventType READY_FOR_CLOSE = GraphTrace::READY_FOR_CLOSE;
static constexpr EventType THROTTLED = GraphTrace::THROTTLED;
static constexpr EventType UNTHROTTLED = GraphTrace::UNTHROTTLED;
static constexpr EventType CPU_TASK_USER = GraphTrace::CPU_TASK_USER;
static constexpr EventType CPU_TASK_SYSTEM = GraphTrace::CPU_TASK_SYSTEM;
static constexpr EventType GPU_TASK = GraphTrace::GPU_TASK;
static constexpr EventType DSP_TASK = GraphTrace::DSP_TASK;
static constexpr EventType TPU_TASK = GraphTrace::TPU_TASK;
static constexpr EventType GPU_CALIBRATION = GraphTrace::GPU_CALIBRATION;
static constexpr EventType PACKET_QUEUED = GraphTrace::PACKET_QUEUED;
}; };
// Packet trace log buffer. // Packet trace log buffer.
using TraceBuffer = CircularBuffer<TraceEvent>; using TraceBuffer = CircularBuffer<TraceEvent>;
// TraceEvent type traits.
class TraceEventType {
using EventType = TraceEvent::EventType;
public:
TraceEventType() {}
TraceEventType(EventType event_type, std::string description,
bool is_packet_event = false, bool is_stream_event = false,
bool id_event_data = true)
: event_type_(event_type),
description_(description),
is_packet_event_(is_packet_event),
is_stream_event_(is_stream_event),
id_event_data_(id_event_data) {}
// The type of event to log.
inline EventType event_type() const { return event_type_; }
// True if this type of event is logged.
inline bool enabled() const { return event_type_; }
inline void set_enabled(bool enabled) { enabled_ = enabled; }
// True if packet details are logged with this type of event.
inline bool is_packet_event() const { return is_packet_event_; }
// True if stream details are logged with this type of event.
inline bool is_stream_event() const { return is_stream_event_; }
// True if event_data values are assigned compact id's.
inline bool id_event_data() const { return id_event_data_; }
private:
EventType event_type_ = TraceEvent::UNKNOWN;
std::string description_ = "";
bool enabled_ = true;
bool is_packet_event_ = false;
bool is_stream_event_ = false;
bool id_event_data_ = true;
};
// A hash function for TraceEvent::EventType.
struct EventTypeHash {
size_t operator()(const TraceEvent::EventType e) const {
return static_cast<size_t>(e);
}
};
// The registry of trace event types.
using TraceEventRegistry =
std::unordered_map<TraceEvent::EventType, TraceEventType, EventTypeHash>;
} // namespace mediapipe } // namespace mediapipe
#endif // MEDIAPIPE_FRAMEWORK_PROFILER_TRACE_BUFFER_H_ #endif // MEDIAPIPE_FRAMEWORK_PROFILER_TRACE_BUFFER_H_

View File

@ -57,21 +57,37 @@ namespace mediapipe {
namespace { namespace {
// For each event-type, whether packet details are logged. void BasicTraceEventTypes(TraceEventRegistry* result) {
// The event-types are: // The initializer arguments below are: event_type, description,
// UNKNOWN, OPEN, PROCESS, CLOSE, // is_packet_event, is_stream_event, id_event_data.
// NOT_READY, READY_FOR_PROCESS, READY_FOR_CLOSE, THROTTLED, UNTHROTTLED std::vector<TraceEventType> basic_types = {
// CPU_TASK_USER, CPU_TASK_SYSTEM, GPU_TASK, DSP_TASK, TPU_TASK {TraceEvent::UNKNOWN, "An uninitialized trace-event."},
constexpr bool kProfilerPacketEvents[] = { // {TraceEvent::OPEN, "A call to Calculator::Open.", true, true},
false, true, true, true, // {TraceEvent::PROCESS, "A call to Calculator::Open.", true, true},
false, false, false, false, false, // {TraceEvent::CLOSE, "A call to Calculator::Close.", true, true},
true, true, true, true, true};
// For each calculator method, whether StreamTraces are desired. {TraceEvent::NOT_READY, "A calculator cannot process packets yet."},
constexpr bool kProfilerStreamEvents[] = { // {TraceEvent::READY_FOR_PROCESS, "A calculator can process packets."},
false, true, true, true, // {TraceEvent::READY_FOR_CLOSE, "A calculator is done processing packets."},
false, false, false, false, false, // {TraceEvent::THROTTLED, "Input is disabled due to max_queue_size."},
true, true, false, false, false}; {TraceEvent::UNTHROTTLED, "Input is enabled up to max_queue_size."},
{TraceEvent::CPU_TASK_USER, "User-time processing packets.", true, true},
{TraceEvent::CPU_TASK_SYSTEM, "System-time processing packets.", true,
true},
{TraceEvent::GPU_TASK, "GPU-time processing packets.", true, false},
{TraceEvent::DSP_TASK, "DSP-time processing packets.", true, false},
{TraceEvent::TPU_TASK, "TPU-time processing packets.", true, false},
{TraceEvent::GPU_CALIBRATION,
"A time measured by GPU clock and by CPU clock.", true, false},
{TraceEvent::PACKET_QUEUED, "An input queue size when a packet arrives.",
true, true, false},
};
for (TraceEventType t : basic_types) {
(*result)[t.event_type()] = t;
}
}
// A map defining int32 identifiers for std::string object pointers. // A map defining int32 identifiers for std::string object pointers.
// Lookup is fast when the same std::string object is used frequently. // Lookup is fast when the same std::string object is used frequently.
@ -106,7 +122,7 @@ class StringIdMap {
// A map defining int32 identifiers for object pointers. // A map defining int32 identifiers for object pointers.
class AddressIdMap { class AddressIdMap {
public: public:
int32 operator[](const void* id) { int32 operator[](int64 id) {
auto pointer_id = pointer_id_map_.find(id); auto pointer_id = pointer_id_map_.find(id);
if (pointer_id != pointer_id_map_.end()) { if (pointer_id != pointer_id_map_.end()) {
return pointer_id->second; return pointer_id->second;
@ -114,12 +130,10 @@ class AddressIdMap {
return pointer_id_map_[id] = next_id++; return pointer_id_map_[id] = next_id++;
} }
void clear() { pointer_id_map_.clear(); } void clear() { pointer_id_map_.clear(); }
const std::unordered_map<const void*, int32>& map() { const std::unordered_map<int64, int32>& map() { return pointer_id_map_; }
return pointer_id_map_;
}
private: private:
std::unordered_map<const void*, int32> pointer_id_map_; std::unordered_map<int64, int32> pointer_id_map_;
int32 next_id = 0; int32 next_id = 0;
}; };
@ -147,8 +161,12 @@ class TraceBuilder::Impl {
static std::string* empty_string = new std::string(""); static std::string* empty_string = new std::string("");
stream_id_map_[empty_string]; stream_id_map_[empty_string];
packet_data_id_map_[0]; packet_data_id_map_[0];
BasicTraceEventTypes(&trace_event_registry_);
} }
// Returns the registry of trace event types.
TraceEventRegistry* trace_event_registry() { return &trace_event_registry_; }
static Timestamp TimestampAfter(const TraceBuffer& buffer, static Timestamp TimestampAfter(const TraceBuffer& buffer,
absl::Time begin_time) { absl::Time begin_time) {
Timestamp max_ts = Timestamp::Min(); Timestamp max_ts = Timestamp::Min();
@ -176,7 +194,7 @@ class TraceBuilder::Impl {
// Index TraceEvents by task-id and stream-hop-id. // Index TraceEvents by task-id and stream-hop-id.
for (const TraceEvent& event : snapshot) { for (const TraceEvent& event : snapshot) {
if (!kProfilerPacketEvents[static_cast<int>(event.event_type)]) { if (!trace_event_registry_[event.event_type].is_packet_event()) {
continue; continue;
} }
TaskId task_id{event.node_id, event.input_ts, event.event_type}; TaskId task_id{event.node_id, event.input_ts, event.event_type};
@ -195,7 +213,7 @@ class TraceBuilder::Impl {
result->set_base_timestamp(base_ts_); result->set_base_timestamp(base_ts_);
std::unordered_set<TaskId> task_ids; std::unordered_set<TaskId> task_ids;
for (const TraceEvent& event : snapshot) { for (const TraceEvent& event : snapshot) {
if (!kProfilerPacketEvents[static_cast<int>(event.event_type)]) { if (!trace_event_registry_[event.event_type].is_packet_event()) {
BuildEventLog(event, result->add_calculator_trace()); BuildEventLog(event, result->add_calculator_trace());
continue; continue;
} }
@ -280,18 +298,12 @@ class TraceBuilder::Impl {
// Construct the StreamTrace for a TraceEvent. // Construct the StreamTrace for a TraceEvent.
void BuildStreamTrace(const TraceEvent& event, void BuildStreamTrace(const TraceEvent& event,
GraphTrace::StreamTrace* result) { GraphTrace::StreamTrace* result) {
if (event.is_finish) {
result->set_stream_id(stream_id_map_[event.stream_id]);
result->set_packet_timestamp(LogTimestamp(event.packet_ts));
return;
}
result->set_stream_id(stream_id_map_[event.stream_id]); result->set_stream_id(stream_id_map_[event.stream_id]);
result->set_packet_timestamp(LogTimestamp(event.packet_ts)); result->set_packet_timestamp(LogTimestamp(event.packet_ts));
result->set_finish_time(LogTime(event.event_time)); if (trace_event_registry_[event.event_type].id_event_data()) {
result->set_packet_id(packet_data_id_map_[event.packet_data_id]); result->set_event_data(packet_data_id_map_[event.event_data]);
const TraceEvent* output_event = FindOutputEvent(event); } else {
if (output_event) { result->set_event_data(event.event_data);
result->set_start_time(LogTime(output_event->event_time));
} }
} }
@ -301,10 +313,12 @@ class TraceBuilder::Impl {
absl::Time start_time = absl::InfiniteFuture(); absl::Time start_time = absl::InfiniteFuture();
absl::Time finish_time = absl::InfiniteFuture(); absl::Time finish_time = absl::InfiniteFuture();
for (const TraceEvent* event : task_events) { for (const TraceEvent* event : task_events) {
if (result->input_trace().size() + result->output_trace().size() == 0) { if (result->event_type() == TraceEvent::UNKNOWN) {
result->set_node_id(event->node_id); result->set_node_id(event->node_id);
result->set_event_type(event->event_type); result->set_event_type(event->event_type);
result->set_input_timestamp(LogTimestamp(event->input_ts)); if (event->input_ts != Timestamp::Unset()) {
result->set_input_timestamp(LogTimestamp(event->input_ts));
}
result->set_thread_id(event->thread_id); result->set_thread_id(event->thread_id);
} }
if (event->is_finish) { if (event->is_finish) {
@ -312,12 +326,21 @@ class TraceBuilder::Impl {
} else { } else {
start_time = std::min(start_time, event->event_time); start_time = std::min(start_time, event->event_time);
} }
if (kProfilerStreamEvents[static_cast<int>(event->event_type)]) { if (trace_event_registry_[event->event_type].is_stream_event()) {
auto stream_trace = event->is_finish ? result->add_output_trace()
: result->add_input_trace();
if (event->is_finish) { if (event->is_finish) {
BuildStreamTrace(*event, result->add_output_trace()); // Log only the packet id for each output event.
auto s = result->output_trace(result->output_trace_size() - 1); stream_trace->set_stream_id(stream_id_map_[event->stream_id]);
stream_trace->set_packet_timestamp(LogTimestamp(event->packet_ts));
} else { } else {
BuildStreamTrace(*event, result->add_input_trace()); // Log the full stream trace for each input event.
BuildStreamTrace(*event, stream_trace);
stream_trace->set_finish_time(LogTime(event->event_time));
const TraceEvent* output_event = FindOutputEvent(*event);
if (output_event) {
stream_trace->set_start_time(LogTime(output_event->event_time));
}
} }
} }
} }
@ -343,13 +366,11 @@ class TraceBuilder::Impl {
result->set_input_timestamp(LogTimestamp(event.input_ts)); result->set_input_timestamp(LogTimestamp(event.input_ts));
} }
result->set_thread_id(event.thread_id); result->set_thread_id(event.thread_id);
if (kProfilerStreamEvents[static_cast<int>(event.event_type)]) { if (trace_event_registry_[event.event_type].is_stream_event()) {
if (event.stream_id) { if (event.stream_id) {
auto stream_trace = event.is_finish ? result->add_output_trace() auto stream_trace = event.is_finish ? result->add_output_trace()
: result->add_input_trace(); : result->add_input_trace();
stream_trace->set_stream_id(stream_id_map_[event.stream_id]); BuildStreamTrace(event, stream_trace);
stream_trace->set_packet_timestamp(LogTimestamp(event.packet_ts));
stream_trace->set_packet_id(packet_data_id_map_[event.packet_data_id]);
} }
} }
} }
@ -366,11 +387,17 @@ class TraceBuilder::Impl {
int64 base_ts_ = std::numeric_limits<int64>::max(); int64 base_ts_ = std::numeric_limits<int64>::max();
// The time represented as 0 in the trace. // The time represented as 0 in the trace.
int64 base_time_ = std::numeric_limits<int64>::max(); int64 base_time_ = std::numeric_limits<int64>::max();
// Indicates traits of each event type.
TraceEventRegistry trace_event_registry_;
}; };
TraceBuilder::TraceBuilder() : impl_(new Impl) {} TraceBuilder::TraceBuilder() : impl_(new Impl) {}
TraceBuilder::~TraceBuilder() {} TraceBuilder::~TraceBuilder() {}
TraceEventRegistry* TraceBuilder::trace_event_registry() {
return impl_->trace_event_registry();
}
Timestamp TraceBuilder::TimestampAfter(const TraceBuffer& buffer, Timestamp TraceBuilder::TimestampAfter(const TraceBuffer& buffer,
absl::Time begin_time) { absl::Time begin_time) {
return Impl::TimestampAfter(buffer, begin_time); return Impl::TimestampAfter(buffer, begin_time);
@ -400,6 +427,8 @@ const TraceEvent::EventType //
TraceEvent::CPU_TASK_SYSTEM, // TraceEvent::CPU_TASK_SYSTEM, //
TraceEvent::GPU_TASK, // TraceEvent::GPU_TASK, //
TraceEvent::DSP_TASK, // TraceEvent::DSP_TASK, //
TraceEvent::TPU_TASK; TraceEvent::TPU_TASK, //
TraceEvent::GPU_CALIBRATION, //
TraceEvent::PACKET_QUEUED;
} // namespace mediapipe } // namespace mediapipe

View File

@ -28,6 +28,9 @@ class TraceBuilder {
TraceBuilder(); TraceBuilder();
~TraceBuilder(); ~TraceBuilder();
// Returns the registry of trace event types.
TraceEventRegistry* trace_event_registry();
// Returns the earliest packet timestamp appearing only after begin_time. // Returns the earliest packet timestamp appearing only after begin_time.
static Timestamp TimestampAfter(const TraceBuffer& buffer, static Timestamp TimestampAfter(const TraceBuffer& buffer,
absl::Time begin_time); absl::Time begin_time);

View File

@ -45,6 +45,17 @@ DefaultInputStreamHandler::DefaultInputStreamHandler(
} }
} }
void DefaultInputStreamHandler::PrepareForRun(
std::function<void()> headers_ready_callback,
std::function<void()> notification_callback,
std::function<void(CalculatorContext*)> schedule_callback,
std::function<void(::mediapipe::Status)> error_callback) {
sync_set_.PrepareForRun();
InputStreamHandler::PrepareForRun(
std::move(headers_ready_callback), std::move(notification_callback),
std::move(schedule_callback), std::move(error_callback));
}
NodeReadiness DefaultInputStreamHandler::GetNodeReadiness( NodeReadiness DefaultInputStreamHandler::GetNodeReadiness(
Timestamp* min_stream_timestamp) { Timestamp* min_stream_timestamp) {
return sync_set_.GetReadiness(min_stream_timestamp); return sync_set_.GetReadiness(min_stream_timestamp);

View File

@ -35,6 +35,13 @@ class DefaultInputStreamHandler : public InputStreamHandler {
bool calculator_run_in_parallel); bool calculator_run_in_parallel);
protected: protected:
// Reinitializes this InputStreamHandler before each CalculatorGraph run.
void PrepareForRun(
std::function<void()> headers_ready_callback,
std::function<void()> notification_callback,
std::function<void(CalculatorContext*)> schedule_callback,
std::function<void(::mediapipe::Status)> error_callback) override;
// In DefaultInputStreamHandler, a node is "ready" if: // In DefaultInputStreamHandler, a node is "ready" if:
// - all streams are done (need to call Close() in this case), or // - all streams are done (need to call Close() in this case), or
// - the minimum bound (over all empty streams) is greater than the smallest // - the minimum bound (over all empty streams) is greater than the smallest

View File

@ -40,6 +40,13 @@ class ImmediateInputStreamHandler : public InputStreamHandler {
const MediaPipeOptions& options, bool calculator_run_in_parallel); const MediaPipeOptions& options, bool calculator_run_in_parallel);
protected: protected:
// Reinitializes this InputStreamHandler before each CalculatorGraph run.
void PrepareForRun(
std::function<void()> headers_ready_callback,
std::function<void()> notification_callback,
std::function<void(CalculatorContext*)> schedule_callback,
std::function<void(::mediapipe::Status)> error_callback) override;
// Returns kReadyForProcess whenever a Packet is available at any of // Returns kReadyForProcess whenever a Packet is available at any of
// the input streams, or any input stream becomes done. // the input streams, or any input stream becomes done.
NodeReadiness GetNodeReadiness(Timestamp* min_stream_timestamp) override; NodeReadiness GetNodeReadiness(Timestamp* min_stream_timestamp) override;
@ -69,6 +76,23 @@ ImmediateInputStreamHandler::ImmediateInputStreamHandler(
} }
} }
void ImmediateInputStreamHandler::PrepareForRun(
std::function<void()> headers_ready_callback,
std::function<void()> notification_callback,
std::function<void(CalculatorContext*)> schedule_callback,
std::function<void(::mediapipe::Status)> error_callback) {
{
absl::MutexLock lock(&mutex_);
for (int i = 0; i < sync_sets_.size(); ++i) {
sync_sets_[i].PrepareForRun();
ready_timestamps_[i] = Timestamp::Unset();
}
}
InputStreamHandler::PrepareForRun(
std::move(headers_ready_callback), std::move(notification_callback),
std::move(schedule_callback), std::move(error_callback));
}
NodeReadiness ImmediateInputStreamHandler::GetNodeReadiness( NodeReadiness ImmediateInputStreamHandler::GetNodeReadiness(
Timestamp* min_stream_timestamp) { Timestamp* min_stream_timestamp) {
absl::MutexLock lock(&mutex_); absl::MutexLock lock(&mutex_);

View File

@ -61,6 +61,13 @@ GraphRegistry::GraphRegistry(
FunctionRegistry<std::unique_ptr<Subgraph>>* factories) FunctionRegistry<std::unique_ptr<Subgraph>>* factories)
: global_factories_(factories) {} : global_factories_(factories) {}
void GraphRegistry::Register(
const std::string& type_name,
std::function<std::unique_ptr<Subgraph>()> factory) {
local_factories_.Register(type_name, factory);
}
// TODO: Remove this convenience function.
void GraphRegistry::Register(const std::string& type_name, void GraphRegistry::Register(const std::string& type_name,
const CalculatorGraphConfig& config) { const CalculatorGraphConfig& config) {
local_factories_.Register(type_name, [config] { local_factories_.Register(type_name, [config] {
@ -69,6 +76,7 @@ void GraphRegistry::Register(const std::string& type_name,
}); });
} }
// TODO: Remove this convenience function.
void GraphRegistry::Register(const std::string& type_name, void GraphRegistry::Register(const std::string& type_name,
const CalculatorGraphTemplate& templ) { const CalculatorGraphTemplate& templ) {
local_factories_.Register(type_name, [templ] { local_factories_.Register(type_name, [templ] {

View File

@ -94,6 +94,10 @@ class GraphRegistry {
// Ownership of the specified FunctionRegistry is not transferred. // Ownership of the specified FunctionRegistry is not transferred.
GraphRegistry(FunctionRegistry<std::unique_ptr<Subgraph>>* factories); GraphRegistry(FunctionRegistry<std::unique_ptr<Subgraph>>* factories);
// Registers a graph config builder type, using a factory function.
void Register(const std::string& type_name,
std::function<std::unique_ptr<Subgraph>()> factory);
// Registers a graph config by name. // Registers a graph config by name.
void Register(const std::string& type_name, void Register(const std::string& type_name,
const CalculatorGraphConfig& config); const CalculatorGraphConfig& config);

View File

@ -59,7 +59,7 @@ GL_BASE_LINK_OPTS = select({
# runtime. Weak GLESv3 symbols will still be resolved if we # runtime. Weak GLESv3 symbols will still be resolved if we
# load it early enough. # load it early enough.
], ],
"//mediapipe:apple": [ "//mediapipe:ios": [
"-framework OpenGLES", "-framework OpenGLES",
"-framework CoreVideo", "-framework CoreVideo",
], ],
@ -111,7 +111,7 @@ cc_library(
# Note: need the frameworks on Apple platforms to get the headers. # Note: need the frameworks on Apple platforms to get the headers.
linkopts = select({ linkopts = select({
"//conditions:default": [], "//conditions:default": [],
"//mediapipe:apple": [ "//mediapipe:ios": [
"-framework OpenGLES", "-framework OpenGLES",
"-framework CoreVideo", "-framework CoreVideo",
], ],
@ -147,7 +147,7 @@ cc_library(
"//conditions:default": [ "//conditions:default": [
"gl_context_egl.cc", "gl_context_egl.cc",
], ],
"//mediapipe:apple": [ "//mediapipe:ios": [
"gl_context_eagl.cc", "gl_context_eagl.cc",
], ],
"//mediapipe:macos": [ "//mediapipe:macos": [
@ -214,7 +214,7 @@ cc_library(
"//conditions:default": [ "//conditions:default": [
":gl_texture_buffer", ":gl_texture_buffer",
], ],
"//mediapipe:apple": [ "//mediapipe:ios": [
"//mediapipe/objc:CFHolder", "//mediapipe/objc:CFHolder",
], ],
"//mediapipe:macos": [ "//mediapipe:macos": [
@ -246,9 +246,14 @@ objc_library(
"-Wno-shorten-64-to-32", "-Wno-shorten-64-to-32",
], ],
sdk_frameworks = [ sdk_frameworks = [
"Accelerate",
"CoreGraphics",
"CoreVideo", "CoreVideo",
], ],
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = [
"//mediapipe/objc:util",
],
) )
objc_library( objc_library(
@ -408,7 +413,7 @@ cc_library(
"//conditions:default": [ "//conditions:default": [
"gl_texture_buffer_pool.cc", "gl_texture_buffer_pool.cc",
], ],
"//mediapipe:apple": [], "//mediapipe:ios": [],
"//mediapipe:macos": [ "//mediapipe:macos": [
"gl_texture_buffer_pool.cc", "gl_texture_buffer_pool.cc",
], ],
@ -417,7 +422,7 @@ cc_library(
"//conditions:default": [ "//conditions:default": [
"gl_texture_buffer_pool.h", "gl_texture_buffer_pool.h",
], ],
"//mediapipe:apple": [ "//mediapipe:ios": [
# The inclusions check does not see that this is provided by # The inclusions check does not see that this is provided by
# pixel_buffer_pool_util, so we include it here too. This is # pixel_buffer_pool_util, so we include it here too. This is
# b/28066691. # b/28066691.
@ -441,7 +446,7 @@ cc_library(
"//conditions:default": [ "//conditions:default": [
":gl_texture_buffer", ":gl_texture_buffer",
], ],
"//mediapipe:apple": [ "//mediapipe:ios": [
":pixel_buffer_pool_util", ":pixel_buffer_pool_util",
"//mediapipe/objc:CFHolder", "//mediapipe/objc:CFHolder",
], ],

View File

@ -117,6 +117,7 @@ void* GlContext::DedicatedThread::ThreadBody(void* instance) {
void GlContext::DedicatedThread::ThreadBody() { void GlContext::DedicatedThread::ThreadBody() {
SetThreadName("mediapipe_gl_runner"); SetThreadName("mediapipe_gl_runner");
#ifndef __EMSCRIPTEN__ #ifndef __EMSCRIPTEN__
GlThreadCollector::ThreadStarting(); GlThreadCollector::ThreadStarting();
#endif #endif
@ -276,6 +277,11 @@ bool GlContext::HasGlExtension(absl::string_view extension) const {
absl::string_view version_string( absl::string_view version_string(
reinterpret_cast<const char*>(glGetString(GL_VERSION))); reinterpret_cast<const char*>(glGetString(GL_VERSION)));
// We will decide later whether we want to use the version numbers we query
// for, or instead derive that information from the context creation result,
// which we cache here.
GLint gl_major_version_from_context_creation = gl_major_version_;
// Let's try getting the numeric version if possible. // Let's try getting the numeric version if possible.
glGetIntegerv(GL_MAJOR_VERSION, &gl_major_version_); glGetIntegerv(GL_MAJOR_VERSION, &gl_major_version_);
GLenum err = glGetError(); GLenum err = glGetError();
@ -293,6 +299,23 @@ bool GlContext::HasGlExtension(absl::string_view extension) const {
} }
} }
// If our platform-specific CreateContext already set a major GL version,
// then we use that. Otherwise, we use the queried-for result. We do this
// as a workaround for a Swiftshader on Android bug where the ES2 context
// can report major version 3 instead of 2 when queried. Therefore we trust
// the result from context creation more than from query. See b/152519932
// for more details.
if (gl_major_version_from_context_creation > 0 &&
gl_major_version_ != gl_major_version_from_context_creation) {
LOG(WARNING) << "Requested a context with major GL version "
<< gl_major_version_from_context_creation
<< " but context reports major version " << gl_major_version_
<< ". Setting to " << gl_major_version_from_context_creation
<< ".0";
gl_major_version_ = gl_major_version_from_context_creation;
gl_minor_version_ = 0;
}
LOG(INFO) << "GL version: " << gl_major_version_ << "." << gl_minor_version_ LOG(INFO) << "GL version: " << gl_major_version_ << "." << gl_minor_version_
<< " (" << glGetString(GL_VERSION) << ")"; << " (" << glGetString(GL_VERSION) << ")";
if (gl_major_version_ >= 3) { if (gl_major_version_ >= 3) {
@ -613,7 +636,17 @@ std::shared_ptr<GlSyncPoint> GlContext::CreateSyncToken() {
#if MEDIAPIPE_DISABLE_GL_SYNC_FOR_DEBUG #if MEDIAPIPE_DISABLE_GL_SYNC_FOR_DEBUG
token.reset(new GlNopSyncPoint(shared_from_this())); token.reset(new GlNopSyncPoint(shared_from_this()));
#else #else
if (SymbolAvailable(&glWaitSync)) {
#ifdef __EMSCRIPTEN__
// In Emscripten the glWaitSync function is non-null depending on linkopts,
// but only works in a WebGL2 context, so fall back to use Finish if it is a
// WebGL1/ES2 context.
// TODO: apply this more generally once b/152794517 is fixed.
bool useFenceSync = gl_major_version() > 2;
#else
bool useFenceSync = SymbolAvailable(&glWaitSync);
#endif // __EMSCRIPTEN__
if (useFenceSync) {
token.reset(new GlFenceSyncPoint(shared_from_this())); token.reset(new GlFenceSyncPoint(shared_from_this()));
} else { } else {
token.reset(new GlFinishSyncPoint(shared_from_this())); token.reset(new GlFinishSyncPoint(shared_from_this()));
@ -633,8 +666,30 @@ std::shared_ptr<GlSyncPoint> GlContext::TestOnly_CreateSpecificSyncToken(
return nullptr; return nullptr;
} }
// Atomically set var to the greater of its current value or target.
template <typename T>
static void assign_larger_value(std::atomic<T>* var, T target) {
T current = var->load();
while (current < target && !var->compare_exchange_weak(current, target)) {
}
}
// Note: this can get called from an arbitrary thread which is dealing with a
// GlFinishSyncPoint originating from this context.
void GlContext::WaitForGlFinishCountPast(int64_t count_to_pass) { void GlContext::WaitForGlFinishCountPast(int64_t count_to_pass) {
if (gl_finish_count_ > count_to_pass) return; if (gl_finish_count_ > count_to_pass) return;
// If we've been asked to do a glFinish, note the count we need to reach and
// signal the context our thread may currently be blocked on.
{
absl::MutexLock lock(&mutex_);
assign_larger_value(&gl_finish_count_target_, count_to_pass + 1);
wait_for_gl_finish_cv_.SignalAll();
if (context_waiting_on_) {
context_waiting_on_->wait_for_gl_finish_cv_.SignalAll();
}
}
auto finish_task = [this, count_to_pass]() { auto finish_task = [this, count_to_pass]() {
// When a GlFinishSyncToken is created it takes the current finish count // When a GlFinishSyncToken is created it takes the current finish count
// from the GlContext, and we must wait for gl_finish_count_ to pass it. // from the GlContext, and we must wait for gl_finish_count_ to pass it.
@ -646,6 +701,7 @@ void GlContext::WaitForGlFinishCountPast(int64_t count_to_pass) {
GlFinishCalled(); GlFinishCalled();
} }
}; };
if (IsCurrent()) { if (IsCurrent()) {
// If we are already on the current context, we cannot call // If we are already on the current context, we cannot call
// RunWithoutWaiting, since that task will not run until this function // RunWithoutWaiting, since that task will not run until this function
@ -653,13 +709,53 @@ void GlContext::WaitForGlFinishCountPast(int64_t count_to_pass) {
finish_task(); finish_task();
return; return;
} }
std::shared_ptr<GlContext> other = GetCurrent();
if (other) {
// If another context is current, make a note that it is blocked on us, so
// it can signal the right condition variable if it is asked to do a
// glFinish.
absl::MutexLock other_lock(&other->mutex_);
DCHECK(!other->context_waiting_on_);
other->context_waiting_on_ = this;
}
// We do not schedule this action using Run because we don't necessarily // We do not schedule this action using Run because we don't necessarily
// want to wait for it to complete. If another job calls GlFinishCalled // want to wait for it to complete. If another job calls GlFinishCalled
// sooner, we are done. // sooner, we are done.
RunWithoutWaiting(std::move(finish_task)); RunWithoutWaiting(std::move(finish_task));
absl::MutexLock lock(&mutex_); {
while (gl_finish_count_ <= count_to_pass) { absl::MutexLock lock(&mutex_);
wait_for_gl_finish_cv_.Wait(&mutex_); while (gl_finish_count_ <= count_to_pass) {
if (other && other->gl_finish_count_ < other->gl_finish_count_target_) {
// If another context's dedicated thread is current, it is blocked
// waiting for this context to issue a glFinish call. But this context
// may also block waiting for the other context to do the same: this can
// happen when two contexts are handling each other's GlFinishSyncPoints
// (e.g. a producer and a consumer). To avoid a deadlock a context that
// is waiting on another context must still service Wait calls it may
// receive from its own GlFinishSyncPoints.
//
// We unlock this context's mutex to avoid holding both at the same
// time.
mutex_.Unlock();
{
glFinish();
other->GlFinishCalled();
}
mutex_.Lock();
// Because we temporarily unlocked mutex_, we cannot wait on the
// condition variable wait away; we need to go back to re-checking the
// condition. Otherwise we might miss a signal.
continue;
}
wait_for_gl_finish_cv_.Wait(&mutex_);
}
}
if (other) {
// The other context is no longer waiting on us.
absl::MutexLock other_lock(&other->mutex_);
other->context_waiting_on_ = nullptr;
} }
} }

View File

@ -380,6 +380,9 @@ class GlContext : public std::enable_shared_from_this<GlContext> {
// Changes should be guarded by mutex_. However, we use simple atomic // Changes should be guarded by mutex_. However, we use simple atomic
// loads for efficiency on the fast path. // loads for efficiency on the fast path.
std::atomic<int64_t> gl_finish_count_ = ATOMIC_VAR_INIT(0); std::atomic<int64_t> gl_finish_count_ = ATOMIC_VAR_INIT(0);
std::atomic<int64_t> gl_finish_count_target_ = ATOMIC_VAR_INIT(0);
GlContext* context_waiting_on_ ABSL_GUARDED_BY(mutex_) = nullptr;
// This mutex is held by a thread while this GL context is current on that // This mutex is held by a thread while this GL context is current on that
// thread. Since it may be held for extended periods of time, it should not // thread. Since it may be held for extended periods of time, it should not

View File

@ -26,19 +26,28 @@ GlTextureBufferPool::GlTextureBufferPool(int width, int height,
keep_count_(keep_count) {} keep_count_(keep_count) {}
GlTextureBufferSharedPtr GlTextureBufferPool::GetBuffer() { GlTextureBufferSharedPtr GlTextureBufferPool::GetBuffer() {
absl::MutexLock lock(&mutex_);
std::unique_ptr<GlTextureBuffer> buffer; std::unique_ptr<GlTextureBuffer> buffer;
if (available_.empty()) { bool reuse = false;
buffer = GlTextureBuffer::Create(width_, height_, format_);
if (!buffer) return nullptr; {
} else { absl::MutexLock lock(&mutex_);
buffer = std::move(available_.back()); if (available_.empty()) {
available_.pop_back(); buffer = GlTextureBuffer::Create(width_, height_, format_);
buffer->Reuse(); if (!buffer) return nullptr;
} else {
buffer = std::move(available_.back());
available_.pop_back();
reuse = true;
}
++in_use_count_;
} }
++in_use_count_; // This needs to wait on consumer sync points, therefore it should not be
// done while holding the mutex.
if (reuse) {
buffer->Reuse();
}
// Return a shared_ptr with a custom deleter that adds the buffer back // Return a shared_ptr with a custom deleter that adds the buffer back
// to our available list. // to our available list.
@ -60,15 +69,24 @@ std::pair<int, int> GlTextureBufferPool::GetInUseAndAvailableCounts() {
} }
void GlTextureBufferPool::Return(GlTextureBuffer* buf) { void GlTextureBufferPool::Return(GlTextureBuffer* buf) {
absl::MutexLock lock(&mutex_); std::vector<std::unique_ptr<GlTextureBuffer>> trimmed;
--in_use_count_; {
available_.emplace_back(buf); absl::MutexLock lock(&mutex_);
TrimAvailable(); --in_use_count_;
available_.emplace_back(buf);
TrimAvailable(&trimmed);
}
// The trimmed buffers will be released without holding the lock.
} }
void GlTextureBufferPool::TrimAvailable() { void GlTextureBufferPool::TrimAvailable(
std::vector<std::unique_ptr<GlTextureBuffer>>* trimmed) {
int keep = std::max(keep_count_ - in_use_count_, 0); int keep = std::max(keep_count_ - in_use_count_, 0);
if (available_.size() > keep) { if (available_.size() > keep) {
auto trim_it = std::next(available_.begin(), keep);
if (trimmed) {
std::move(available_.begin(), trim_it, std::back_inserter(*trimmed));
}
available_.resize(keep); available_.resize(keep);
} }
} }

View File

@ -60,7 +60,8 @@ class GlTextureBufferPool
// If the total number of buffers is greater than keep_count, destroys any // If the total number of buffers is greater than keep_count, destroys any
// surplus buffers that are no longer in use. // surplus buffers that are no longer in use.
void TrimAvailable() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); void TrimAvailable(std::vector<std::unique_ptr<GlTextureBuffer>>* trimmed)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
const int width_; const int width_;
const int height_; const int height_;

View File

@ -16,6 +16,8 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#include "mediapipe/objc/util.h"
#if !defined(ENABLE_MEDIAPIPE_GPU_BUFFER_THRESHOLD_CHECK) && !defined(NDEBUG) #if !defined(ENABLE_MEDIAPIPE_GPU_BUFFER_THRESHOLD_CHECK) && !defined(NDEBUG)
#define ENABLE_MEDIAPIPE_GPU_BUFFER_THRESHOLD_CHECK 1 #define ENABLE_MEDIAPIPE_GPU_BUFFER_THRESHOLD_CHECK 1
#endif // defined(ENABLE_MEDIAPIPE_GPU_BUFFER_THRESHOLD_CHECK) #endif // defined(ENABLE_MEDIAPIPE_GPU_BUFFER_THRESHOLD_CHECK)
@ -27,17 +29,13 @@ CVPixelBufferPoolRef CreateCVPixelBufferPool(
CFTimeInterval maxAge) { CFTimeInterval maxAge) {
CVPixelBufferPoolRef pool = NULL; CVPixelBufferPoolRef pool = NULL;
NSDictionary *sourcePixelBufferOptions = @{ NSMutableDictionary *sourcePixelBufferOptions =
(id)kCVPixelBufferPixelFormatTypeKey : @(pixelFormat), [(__bridge NSDictionary*)GetCVPixelBufferAttributesForGlCompatibility() mutableCopy];
(id)kCVPixelBufferWidthKey : @(width), [sourcePixelBufferOptions addEntriesFromDictionary:@{
(id)kCVPixelBufferHeightKey : @(height), (id)kCVPixelBufferPixelFormatTypeKey : @(pixelFormat),
#if TARGET_OS_OSX (id)kCVPixelBufferWidthKey : @(width),
(id)kCVPixelFormatOpenGLCompatibility : @(YES), (id)kCVPixelBufferHeightKey : @(height),
#else }];
(id)kCVPixelFormatOpenGLESCompatibility : @(YES),
#endif // TARGET_OS_OSX
(id)kCVPixelBufferIOSurfacePropertiesKey : @{ /*empty dictionary*/ }
};
NSMutableDictionary *pixelBufferPoolOptions = [[NSMutableDictionary alloc] init]; NSMutableDictionary *pixelBufferPoolOptions = [[NSMutableDictionary alloc] init];
pixelBufferPoolOptions[(id)kCVPixelBufferPoolMinimumBufferCountKey] = @(keepCount); pixelBufferPoolOptions[(id)kCVPixelBufferPoolMinimumBufferCountKey] = @(keepCount);
@ -131,14 +129,6 @@ static void FreeRefConReleaseCallback(void* refCon, const void* baseAddress) {
CVReturn CreateCVPixelBufferWithoutPool( CVReturn CreateCVPixelBufferWithoutPool(
int width, int height, OSType pixelFormat, CVPixelBufferRef* outBuffer) { int width, int height, OSType pixelFormat, CVPixelBufferRef* outBuffer) {
NSDictionary *attributes = @{
#if TARGET_OS_OSX
(id)kCVPixelFormatOpenGLCompatibility : @(YES),
#else
(id)kCVPixelFormatOpenGLESCompatibility : @(YES),
#endif // TARGET_OS_OSX
(id)kCVPixelBufferIOSurfacePropertiesKey : @{ /*empty dictionary*/ }
};
#if TARGET_IPHONE_SIMULATOR #if TARGET_IPHONE_SIMULATOR
// On the simulator, syncing the texture with the pixelbuffer does not work, // On the simulator, syncing the texture with the pixelbuffer does not work,
// and we have to use glReadPixels. Since GL_UNPACK_ROW_LENGTH is not // and we have to use glReadPixels. Since GL_UNPACK_ROW_LENGTH is not
@ -151,12 +141,12 @@ CVReturn CreateCVPixelBufferWithoutPool(
void* data = malloc(bytes_per_row * height); void* data = malloc(bytes_per_row * height);
return CVPixelBufferCreateWithBytes( return CVPixelBufferCreateWithBytes(
kCFAllocatorDefault, width, height, pixelFormat, data, bytes_per_row, kCFAllocatorDefault, width, height, pixelFormat, data, bytes_per_row,
FreeRefConReleaseCallback, data, (__bridge CFDictionaryRef)attributes, FreeRefConReleaseCallback, data, GetCVPixelBufferAttributesForGlCompatibility(),
outBuffer); outBuffer);
#else #else
return CVPixelBufferCreate( return CVPixelBufferCreate(
kCFAllocatorDefault, width, height, pixelFormat, kCFAllocatorDefault, width, height, pixelFormat,
(__bridge CFDictionaryRef)attributes, outBuffer); GetCVPixelBufferAttributesForGlCompatibility(), outBuffer);
#endif #endif
} }

View File

@ -31,8 +31,8 @@ android_library(
"//third_party:androidx_core", "//third_party:androidx_core",
"//third_party:androidx_legacy_support_v4", "//third_party:androidx_legacy_support_v4",
"//third_party:androidx_recyclerview", "//third_party:androidx_recyclerview",
"@com_google_code_findbugs//jar", "@maven//:com_google_code_findbugs_jsr305",
"@com_google_guava_android//jar", "@maven//:com_google_guava_guava",
], ],
) )
@ -50,10 +50,10 @@ android_library(
"//third_party:androidx_legacy_support_v4", "//third_party:androidx_legacy_support_v4",
"//third_party:camera2", "//third_party:camera2",
"//third_party:camerax_core", "//third_party:camerax_core",
"@androidx_concurrent_futures//jar", "@maven//:androidx_concurrent_concurrent_futures",
"@androidx_lifecycle//jar", "@maven//:androidx_lifecycle_lifecycle_common",
"@com_google_code_findbugs//jar", "@maven//:com_google_code_findbugs_jsr305",
"@com_google_guava_android//jar", "@maven//:com_google_guava_guava",
], ],
) )
@ -67,8 +67,8 @@ android_library(
], ],
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = [ deps = [
"@com_google_code_findbugs//jar", "@maven//:com_google_code_findbugs_jsr305",
"@com_google_guava_android//jar", "@maven//:com_google_guava_guava",
], ],
) )

View File

@ -59,10 +59,10 @@ android_library(
":android_core", ":android_core",
"//third_party:androidx_annotation", "//third_party:androidx_annotation",
"//third_party:androidx_legacy_support_v4", "//third_party:androidx_legacy_support_v4",
"@com_google_code_findbugs//jar", "@maven//:com_google_code_findbugs_jsr305",
"@com_google_common_flogger//jar", "@maven//:com_google_flogger_flogger",
"@com_google_common_flogger_system_backend//jar", "@maven//:com_google_flogger_flogger_system_backend",
"@com_google_guava_android//jar", "@maven//:com_google_guava_guava",
], ],
) )
@ -85,10 +85,10 @@ android_library(
"//mediapipe/framework:calculator_java_proto_lite", "//mediapipe/framework:calculator_java_proto_lite",
"//mediapipe/framework:calculator_profile_java_proto_lite", "//mediapipe/framework:calculator_profile_java_proto_lite",
"//mediapipe/framework/tool:calculator_graph_template_java_proto_lite", "//mediapipe/framework/tool:calculator_graph_template_java_proto_lite",
"@com_google_code_findbugs//jar", "@maven//:com_google_code_findbugs_jsr305",
"@com_google_common_flogger//jar", "@maven//:com_google_flogger_flogger",
"@com_google_common_flogger_system_backend//jar", "@maven//:com_google_flogger_flogger_system_backend",
"@com_google_guava_android//jar", "@maven//:com_google_guava_guava",
], ],
) )

View File

@ -24,10 +24,10 @@ android_library(
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = [ deps = [
"//mediapipe/java/com/google/mediapipe/framework:android_framework_no_proguard", "//mediapipe/java/com/google/mediapipe/framework:android_framework_no_proguard",
"@com_google_code_findbugs//jar", "@maven//:com_google_code_findbugs_jsr305",
"@com_google_common_flogger//jar", "@maven//:com_google_flogger_flogger",
"@com_google_common_flogger_system_backend//jar", "@maven//:com_google_flogger_flogger_system_backend",
"@com_google_guava_android//jar", "@maven//:com_google_guava_guava",
], ],
) )

View File

@ -8,17 +8,24 @@ Here are descriptions of the models used in the [example applications](../docs/e
### Face Detection ### Face Detection
* [TFLite model](https://github.com/google/mediapipe/tree/master/mediapipe/models/face_detection_front.tflite) * [TFLite model](https://github.com/google/mediapipe/tree/master/mediapipe/models/face_detection_front.tflite)
* Paper: ["BlazeFace: Sub-millisecond Neural Face Detection on Mobile GPUs"](https://sites.google.com/corp/view/perception-cv4arvr/blazeface) * Paper: ["BlazeFace: Sub-millisecond Neural Face Detection on Mobile GPUs"](https://arxiv.org/abs/1907.05047)
* [Model card](https://sites.google.com/corp/view/perception-cv4arvr/blazeface#h.p_21ojPZDx3cqq) * [Model card](https://sites.google.com/corp/view/perception-cv4arvr/blazeface#h.p_21ojPZDx3cqq)
### Face Mesh
* [TF.js model](https://tfhub.dev/mediapipe/facemesh/1)
* Paper: ["Real-time Facial Surface Geometry from Monocular Video on Mobile GPUs"](https://arxiv.org/abs/1907.06724)
* [TensorFlow Blog post](https://blog.tensorflow.org/2020/03/face-and-hand-tracking-in-browser-with-mediapipe-and-tensorflowjs.html)
* [Model card](https://drive.google.com/file/d/1VFC_wIpw4O7xBOiTgUldl79d9LA-LsnA/view)
### Hand Detection and Tracking ### Hand Detection and Tracking
* [Palm detection TfLite model](https://github.com/google/mediapipe/tree/master/mediapipe/models/palm_detection.tflite) * Palm detection: [TFLite model](https://github.com/google/mediapipe/tree/master/mediapipe/models/palm_detection.tflite), [TF.js model](https://tfhub.dev/mediapipe/handdetector/1)
* [2D hand landmark TfLite model](https://github.com/google/mediapipe/tree/master/mediapipe/models/hand_landmark.tflite) * 2D hand landmark: [TFLite model](https://github.com/google/mediapipe/tree/master/mediapipe/models/hand_landmark.tflite)
* [3D hand landmark TFLite model](https://github.com/google/mediapipe/tree/master/mediapipe/models/hand_landmark_3d.tflite) * 3D hand landmark: [TFLite model](https://github.com/google/mediapipe/tree/master/mediapipe/models/hand_landmark_3d.tflite), [TF.js model](https://tfhub.dev/mediapipe/handskeleton/1)
* [Google AI Blog post](https://mediapipe.page.link/handgoogleaiblog) * [Google AI Blog post](https://mediapipe.page.link/handgoogleaiblog)
* [TensorFlow Blog post](https://blog.tensorflow.org/2020/03/face-and-hand-tracking-in-browser-with-mediapipe-and-tensorflowjs.html)
* [Model card](https://mediapipe.page.link/handmc) * [Model card](https://mediapipe.page.link/handmc)
### Hair Segmentation ### Hair Segmentation
* [TFLite model](https://github.com/google/mediapipe/tree/master/mediapipe/models/hair_segmentation.tflite) * [TFLite model](https://github.com/google/mediapipe/tree/master/mediapipe/models/hair_segmentation.tflite)
* Paper: ["Real-time Hair segmentation and recoloring on Mobile GPUs"](https://sites.google.com/corp/view/perception-cv4arvr/hair-segmentation) * Paper: ["Real-time Hair segmentation and recoloring on Mobile GPUs"](https://arxiv.org/abs/1907.06740)
* [Model card](https://sites.google.com/corp/view/perception-cv4arvr/hair-segmentation#h.p_NimuO7PgHxlY) * [Model card](https://sites.google.com/corp/view/perception-cv4arvr/hair-segmentation#h.p_NimuO7PgHxlY)

View File

@ -19,9 +19,14 @@ cc_library(
visibility = ["//mediapipe/framework:mediapipe_internal"], visibility = ["//mediapipe/framework:mediapipe_internal"],
deps = [ deps = [
":CFHolder", ":CFHolder",
"//mediapipe/framework:calculator_framework", "//mediapipe/framework:packet",
"//mediapipe/framework/formats:image_frame", "//mediapipe/framework/formats:image_frame",
"//mediapipe/framework/port:logging",
"//mediapipe/framework/port:ret_check",
"//mediapipe/framework/port:source_location",
"//mediapipe/framework/port:status", "//mediapipe/framework/port:status",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/memory",
], ],
) )

View File

@ -26,6 +26,7 @@
#include "mediapipe/gpu/MPPGraphGPUData.h" #include "mediapipe/gpu/MPPGraphGPUData.h"
#include "mediapipe/gpu/gl_base.h" #include "mediapipe/gpu/gl_base.h"
#include "mediapipe/gpu/gpu_shared_data_internal.h" #include "mediapipe/gpu/gpu_shared_data_internal.h"
#include "mediapipe/objc/util.h"
#import "mediapipe/objc/NSError+util_status.h" #import "mediapipe/objc/NSError+util_status.h"
#import "GTMDefines.h" #import "GTMDefines.h"
@ -116,14 +117,10 @@ void CallFrameDelegate(void* wrapperVoid, const std::string& streamName,
if (format == mediapipe::ImageFormat::SRGBA || if (format == mediapipe::ImageFormat::SRGBA ||
format == mediapipe::ImageFormat::GRAY8) { format == mediapipe::ImageFormat::GRAY8) {
CVPixelBufferRef pixelBuffer; CVPixelBufferRef pixelBuffer;
// To ensure compatibility with CVOpenGLESTextureCache, this attribute should be present.
NSDictionary* attributes = @{
(id)kCVPixelBufferIOSurfacePropertiesKey : @{},
};
// If kCVPixelFormatType_32RGBA does not work, it returns kCVReturnInvalidPixelFormat. // If kCVPixelFormatType_32RGBA does not work, it returns kCVReturnInvalidPixelFormat.
CVReturn error = CVPixelBufferCreate( CVReturn error = CVPixelBufferCreate(
NULL, frame.Width(), frame.Height(), kCVPixelFormatType_32BGRA, NULL, frame.Width(), frame.Height(), kCVPixelFormatType_32BGRA,
(__bridge CFDictionaryRef)attributes, &pixelBuffer); GetCVPixelBufferAttributesForGlCompatibility(), &pixelBuffer);
_GTMDevAssert(error == kCVReturnSuccess, @"CVPixelBufferCreate failed: %d", error); _GTMDevAssert(error == kCVReturnSuccess, @"CVPixelBufferCreate failed: %d", error);
error = CVPixelBufferLockBaseAddress(pixelBuffer, 0); error = CVPixelBufferLockBaseAddress(pixelBuffer, 0);
_GTMDevAssert(error == kCVReturnSuccess, @"CVPixelBufferLockBaseAddress failed: %d", error); _GTMDevAssert(error == kCVReturnSuccess, @"CVPixelBufferLockBaseAddress failed: %d", error);

View File

@ -517,17 +517,29 @@ CFDictionaryRef GetCVPixelBufferAttributesForGlCompatibility() {
CFDictionaryRef empty_dict = CFDictionaryCreate( CFDictionaryRef empty_dict = CFDictionaryCreate(
kCFAllocatorDefault, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, kCFAllocatorDefault, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks); &kCFTypeDictionaryValueCallBacks);
// To ensure compatibility with CVOpenGLESTextureCache, these attributes // To ensure compatibility with CVOpenGLESTextureCache, these attributes
// should be present. // should be present. However, on simulator this IOSurface attribute
// actually causes CVOpenGLESTextureCache to fail. b/144850076
const void* keys[] = { const void* keys[] = {
#if !TARGET_IPHONE_SIMULATOR
kCVPixelBufferIOSurfacePropertiesKey, kCVPixelBufferIOSurfacePropertiesKey,
#endif // !TARGET_IPHONE_SIMULATOR
#if TARGET_OS_OSX #if TARGET_OS_OSX
kCVPixelFormatOpenGLCompatibility, kCVPixelFormatOpenGLCompatibility,
#else #else
kCVPixelFormatOpenGLESCompatibility, kCVPixelFormatOpenGLESCompatibility,
#endif // TARGET_OS_OSX #endif // TARGET_OS_OSX
}; };
const void* values[] = {empty_dict, kCFBooleanTrue};
const void* values[] = {
#if !TARGET_IPHONE_SIMULATOR
empty_dict,
#endif // !TARGET_IPHONE_SIMULATOR
kCFBooleanTrue
};
attrs = CFDictionaryCreate( attrs = CFDictionaryCreate(
kCFAllocatorDefault, keys, values, ABSL_ARRAYSIZE(values), kCFAllocatorDefault, keys, values, ABSL_ARRAYSIZE(values),
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);

View File

@ -173,14 +173,14 @@ cc_library(
srcs = select({ srcs = select({
"//conditions:default": ["resource_util.cc"], "//conditions:default": ["resource_util.cc"],
"//mediapipe:android": ["resource_util_android.cc"], "//mediapipe:android": ["resource_util_android.cc"],
"//mediapipe:apple": ["resource_util_apple.cc"], "//mediapipe:ios": ["resource_util_apple.cc"],
"//mediapipe:macos": ["resource_util.cc"], "//mediapipe:macos": ["resource_util.cc"],
}), }),
hdrs = ["resource_util.h"], hdrs = ["resource_util.h"],
# We use Objective-C++ on iOS. # We use Objective-C++ on iOS.
copts = select({ copts = select({
"//conditions:default": [], "//conditions:default": [],
"//mediapipe:apple": [ "//mediapipe:ios": [
"-ObjC++", "-ObjC++",
], ],
"//mediapipe:macos": [], "//mediapipe:macos": [],
@ -201,7 +201,7 @@ cc_library(
"//mediapipe/util/android:asset_manager_util", "//mediapipe/util/android:asset_manager_util",
"//mediapipe/util/android/file/base", "//mediapipe/util/android/file/base",
], ],
"//mediapipe:apple": [], "//mediapipe:ios": [],
"//mediapipe:macos": [ "//mediapipe:macos": [
"//mediapipe/framework/port:file_helpers", "//mediapipe/framework/port:file_helpers",
], ],

Some files were not shown because too many files have changed in this diff Show More