Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
8ddef51
adds mediapipe_core package
craiglabenz Oct 13, 2023
688371a
adds makefile for all packages
craiglabenz Oct 13, 2023
4a2e4d8
fixes typo in Makefile
craiglabenz Oct 16, 2023
8f0c39c
Apply suggestions from code review
Piinks Oct 16, 2023
7b1d5ad
Update Makefile
Piinks Oct 16, 2023
ff83c89
Apply suggestions from code review
Piinks Oct 16, 2023
a39e75b
updated generated code's location and license (for 3P status)
craiglabenz Oct 17, 2023
006e8ef
code review responses
craiglabenz Oct 17, 2023
37ea84d
updated README
craiglabenz Oct 18, 2023
61dbdac
setup sharing of base analysis_options
craiglabenz Oct 18, 2023
b93054b
Update packages/mediapipe-core/lib/src/containers.dart
craiglabenz Oct 23, 2023
10a8589
Update packages/mediapipe-core/lib/src/containers.dart
craiglabenz Oct 23, 2023
e02eece
add free methods to core structs
craiglabenz Oct 31, 2023
7e11eef
code review updates to options
craiglabenz Nov 8, 2023
0aae904
adds publish blocker
craiglabenz Nov 8, 2023
48dbf2e
Add GitHub actions for CI/CD (#14)
craiglabenz Nov 8, 2023
bc212e4
adds ffiwrapper to ci/cd
craiglabenz Nov 8, 2023
125c8e3
adds mediapipe_text package
craiglabenz Oct 13, 2023
8897bdf
Update packages/mediapipe-task-text/.gitignore
Piinks Oct 17, 2023
c50be06
responses to code review
craiglabenz Oct 18, 2023
e559799
cleanup after review
craiglabenz Oct 19, 2023
f4993a8
adds a/sync options for classify method
craiglabenz Oct 23, 2023
2cb5594
docstring improvements
craiglabenz Oct 23, 2023
fac4b39
free options struct
craiglabenz Oct 31, 2023
f9f6ab1
moves async delivery of task to isolates
craiglabenz Nov 8, 2023
0f717b6
adds CI to text package
craiglabenz Nov 8, 2023
ed0f61b
code review change from @Piinks
craiglabenz Nov 8, 2023
3e32ea5
moves text bindings into third_party
craiglabenz Nov 8, 2023
e45639e
code review changes
craiglabenz Nov 8, 2023
0edf7c7
removes dead C fakes and Makefile rule
craiglabenz Nov 8, 2023
2266dfd
flutter create
craiglabenz Oct 23, 2023
7d97284
initial commit of example
craiglabenz Oct 23, 2023
30cbdf9
build file changes from `flutter pub get`
craiglabenz Oct 23, 2023
ef20ee4
update main.dart
craiglabenz Oct 31, 2023
d501481
removes commented code
craiglabenz Nov 13, 2023
fa34b32
updates example for isolates design
craiglabenz Nov 13, 2023
6c61f3d
Use `native-assets` to vendor MediaPipe SDK (#9)
craiglabenz Nov 13, 2023
551b463
Add utility to collect headers from google/mediapipe (#10)
craiglabenz Nov 13, 2023
71627a0
adds mediapipe_text package
craiglabenz Oct 13, 2023
fc5d6e5
Update .vscode/settings.json
craiglabenz Nov 13, 2023
1278d3b
resync headers
craiglabenz Nov 13, 2023
87181da
regenerated core bindings
craiglabenz Nov 13, 2023
9420e90
native assets troubleshooting
craiglabenz Nov 14, 2023
74741c4
Merge branch 'ffi-wrapper-text-pkg' into ffi-wrapper-text-example
craiglabenz Nov 14, 2023
f633d03
Removes redundant count field
craiglabenz Nov 14, 2023
1daf13a
update build.dart for correct bindings path
craiglabenz Nov 14, 2023
ae4efb3
download text classification model for CI
craiglabenz Nov 14, 2023
165cd9c
better memory freeing in executor
craiglabenz Nov 14, 2023
e430156
added SafeArea to example
craiglabenz Nov 14, 2023
13ea95a
added CI to PRs into text package
craiglabenz Nov 14, 2023
97ebc4d
ci tooling change
craiglabenz Nov 15, 2023
ffea00d
remove accidentally commited model
craiglabenz Nov 15, 2023
31e8adf
more CI shenanigans
craiglabenz Nov 15, 2023
55d9974
lowers minimum Dart version for builder
craiglabenz Nov 15, 2023
7820a12
added smoke test for text example
craiglabenz Nov 15, 2023
1391705
Added CI/CD for examples
craiglabenz Nov 15, 2023
a4e957f
More CI tweaks
craiglabenz Nov 15, 2023
e246968
entering "please work" territory
craiglabenz Nov 15, 2023
6d8a999
d'oh
craiglabenz Nov 15, 2023
eac9a99
trying more random stuff
craiglabenz Nov 15, 2023
f06f2d1
one more time
craiglabenz Nov 15, 2023
ef9ef0d
it'd be funny if this helped
craiglabenz Nov 16, 2023
58da376
more print statements
craiglabenz Nov 16, 2023
8dea8fd
enable reaching new print statements
craiglabenz Nov 16, 2023
057bb7c
more logging
craiglabenz Nov 16, 2023
e6028df
see what's in build dir
craiglabenz Nov 17, 2023
bd5d878
another test
craiglabenz Nov 17, 2023
5c92168
adding flutter config list
craiglabenz Nov 17, 2023
c201f33
turn off fail-fast for beta and master
craiglabenz Nov 17, 2023
515e17d
moar logs
craiglabenz Nov 17, 2023
1c83734
way moar prints
craiglabenz Nov 21, 2023
d67fc08
moare things
craiglabenz Nov 21, 2023
21309a3
commit rest of rename
craiglabenz Nov 21, 2023
40cf3b3
moar whatevers
craiglabenz Nov 21, 2023
444226b
adds manifest files generated by new sdks_finder command
craiglabenz Jan 4, 2024
d4f7944
adds sdks_finder command to builder utility
craiglabenz Jan 4, 2024
a156a6e
propagates changes to existing commands
craiglabenz Jan 4, 2024
0afda0c
updates in response to code review
craiglabenz Jan 9, 2024
2e71cf5
updates to build.dart and tests
craiglabenz Jan 12, 2024
06f4b95
add Android runtime
craiglabenz Jan 19, 2024
95e0be9
sdks_finder logging improvement for when build folders change names
craiglabenz Jan 19, 2024
db0236a
refreshed symbols from google/mediapipe
craiglabenz Jan 19, 2024
8c3a510
cleanup
craiglabenz Jan 19, 2024
5344bf3
loosens closeness thresholds in integration tests
craiglabenz Jan 19, 2024
c2f428f
separate build commands for macos architectures
craiglabenz Jan 19, 2024
15d7c55
restores fail-fast setting to CI
craiglabenz Jan 19, 2024
1776f84
removed stale logging statements from CI
craiglabenz Jan 19, 2024
9784456
removes accidentally committed lines
craiglabenz Jan 19, 2024
cb32372
add formatting of sdk_downloads.dart for CI
craiglabenz Jan 19, 2024
940712a
fixes broken example test
craiglabenz Jan 19, 2024
02dede8
code touch ups from @piinks code review
craiglabenz Jan 19, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
push:
branches: [main]
pull_request:
branches: [main, ffi-wrapper, ffi-wrapper-core-pkg]
branches: [main, ffi-wrapper, ffi-wrapper-text-pkg]
workflow_dispatch:
schedule:
- cron: "0 0 * * *" # Every day at midnight
Expand All @@ -25,7 +25,9 @@ jobs:
strategy:
fail-fast: false
matrix:
flutter_version: [stable, beta, master]
flutter_version: [master]
# TODO(craiglabenz): reverse once CI works
# flutter_version: [stable, beta, master]
# TODO(craiglabenz): Add `ubuntu-latest` and `windows-latest` when those artifacts exist
os: [macos-latest]
steps:
Expand Down
25 changes: 17 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,25 @@ headers:
# Runs `ffigen` for all packages
generate: generate_core generate_text

# Runs `ffigen` for all packages, compiles the faked C artifacts, and runs all tests
# Runs `ffigen` for all packages and runs all tests
test: generate_text test_text generate_core test_core

# Runs `ffigen` for all packages and all tests for all packages
# Runs all tests for all packages
test_only: test_core test_text

# Rebuilds the MediaPipe task for macOS
# Assumes google/mediapipe and google/flutter-mediapipe are siblings on the file system
compile_text_classifier_macos:
compile_text_classifier_macos_arm:
cd ../mediapipe && bazel build --linkopt -s --config darwin_arm64 --strip always --define MEDIAPIPE_DISABLE_GPU=1 mediapipe/tasks/c/text/text_classifier:libtext_classifier.dylib
cd ../mediapipe && sudo cp bazel-bin/mediapipe/tasks/c/text/text_classifier/libtext_classifier.dylib ../flutter-mediapipe/packages/mediapipe-task-text/example/assets
cd ../mediapipe && sudo cp bazel-bin/mediapipe/tasks/c/text/text_classifier/libtext_classifier.dylib ../flutter-mediapipe/packages/mediapipe-task-text/example/assets/libtext_classifier_arm64.dylib

compile_text_classifier_macos_x86:
cd ../mediapipe && bazel build --linkopt -s --config darwin_x86_64 --strip always --define MEDIAPIPE_DISABLE_GPU=1 mediapipe/tasks/c/text/text_classifier:libtext_classifier.dylib
cd ../mediapipe && sudo cp bazel-bin/mediapipe/tasks/c/text/text_classifier/libtext_classifier.dylib ../flutter-mediapipe/packages/mediapipe-task-text/example/assets/libtext_classifier_x64.dylib

# Runs `sdks_finder` to update manifest files
sdks:
dart tool/builder/bin/main.dart sdks

# Core ---

Expand All @@ -33,9 +41,10 @@ test_core:
generate_text:
cd packages/mediapipe-task-text && dart --enable-experiment=native-assets run ffigen --config=ffigen.yaml

# Runs `ffigen` for `mediapipe_text` and all text tests
test_text: compile_fake_text test_text_only

# Runs all text tests
test_text_only:
test_text:
cd packages/mediapipe-task-text && flutter test
cd packages/mediapipe-task-text/example && flutter test

example_text:
cd packages/mediapipe-task-text/example && flutter run -d macos
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
# Flutter-MediaPipe

This repository will be home to the source code for the mediapipe_task_vision, mediapipe_task_audio, and mediapipe_task_text plugins for Flutter.

## Releasing

### Updating MediaPipe SDKs

Anytime MediaPipe releases new versions of their SDKs, this package will need to be updated to incorporate those latest builds. SDK versions are pinned in the `sdk_downloads.json` files in each package, which are updated by running the following command from the root of the repository:

```
$ make sdks
```

The Google Cloud Storage bucket in question only gives read-list access to a specific list of Googlers' accounts, so this command must be run from such a Googler's corp machines.

After this, create and merge a PR with the changes and then proceed to `Releasing to pub.dev`.

### Releasing to pub.dev

TODO
2 changes: 2 additions & 0 deletions packages/mediapipe-core/lib/generated/core_symbols.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ files:
symbols:
c:@S@BaseOptions:
name: BaseOptions
c:@S@Categories:
name: Categories
c:@S@Category:
name: Category
c:@S@ClassificationResult:
Expand Down
28 changes: 17 additions & 11 deletions packages/mediapipe-core/lib/src/containers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,19 @@ class Category {

/// Accepts a pointer to a list of structs, and a count representing the length
/// of the list, and returns a list of pure-Dart [Category] instances.
static List<Category> fromStructs(
static List<Category> structsToDart(
Pointer<bindings.Category> structs,
int count,
) {
final categories = <Category>[];
for (int i = 0; i < count; i++) {
categories.add(fromStruct(structs[i]));
categories.add(structToDart(structs[i]));
}
return categories;
}

/// Accepts a pointer to a single struct and returns a pure-Dart [Category] instance.
static Category fromStruct(bindings.Category struct) {
static Category structToDart(bindings.Category struct) {
return Category(
index: struct.index,
score: struct.score,
Expand All @@ -62,19 +62,25 @@ class Category {
}

/// Releases all C memory associated with a list of [bindings.Category] pointers.
/// This method is important to call after calling [Category.fromStructs] to
/// This method is important to call after calling [Category.structsToDart] to
/// convert that C memory into pure-Dart objects.
static void freeStructs(Pointer<bindings.Category> structs, int count) {
int index = 0;
while (index < count) {
bindings.Category obj = structs[index];
calloc.free(obj.category_name);
calloc.free(obj.display_name);
Category.freeStruct(obj);
index++;
}
calloc.free(structs);
}

/// Releases the string fields associated with a single [bindings.Category]
/// struct.
static void freeStruct(bindings.Category struct) {
calloc.free(struct.category_name);
calloc.free(struct.display_name);
}

@override
String toString() => 'Category(index=$index, score=$score, '
'categoryName=$categoryName, displayName=$displayName)';
Expand Down Expand Up @@ -108,22 +114,22 @@ class Classifications {

/// Accepts a pointer to a list of structs, and a count representing the length
/// of the list, and returns a list of pure-Dart [Classifications] instances.
static List<Classifications> fromStructs(
static List<Classifications> structsToDart(
Pointer<bindings.Classifications> structs,
int count,
) {
final classifications = <Classifications>[];
for (int i = 0; i < count; i++) {
classifications.add(fromStruct(structs[i]));
classifications.add(structToDart(structs[i]));
}
return classifications;
}

/// Accepts a pointer to a single struct and returns a pure-Dart [Classifications]
/// instance.
static Classifications fromStruct(bindings.Classifications struct) {
static Classifications structToDart(bindings.Classifications struct) {
return Classifications(
categories: Category.fromStructs(
categories: Category.structsToDart(
struct.categories,
struct.categories_count,
),
Expand All @@ -133,7 +139,7 @@ class Classifications {
}

/// Releases all C memory associated with a list of [bindings.Classifications]
/// pointers. This method is important to call after calling [Classifications.fromStructs]
/// pointers. This method is important to call after calling [Classifications.structsToDart]
/// to convert that C memory into pure-Dart objects.
static void freeStructs(
Pointer<bindings.Classifications> structs,
Expand Down
70 changes: 54 additions & 16 deletions packages/mediapipe-core/lib/src/task_options.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,51 +21,89 @@ import 'third_party/mediapipe/generated/mediapipe_common_bindings.dart'
/// classifier's desired behavior.
class BaseOptions extends Equatable {
/// Generative constructor that creates a [BaseOptions] instance.
const BaseOptions({this.modelAssetBuffer, this.modelAssetPath})
: assert(
const BaseOptions._({
this.modelAssetBuffer,
this.modelAssetPath,
required _BaseOptionsType type,
}) : assert(
!(modelAssetBuffer == null && modelAssetPath == null),
'You must supply either `modelAssetBuffer` or `modelAssetPath`',
),
assert(
!(modelAssetBuffer != null && modelAssetPath != null),
'You must only supply one of `modelAssetBuffer` and `modelAssetPath`',
);
),
_type = type;

/// Constructor for [BaseOptions] classes using a file system path.
///
/// In practice, this is unsupported, as assets in Flutter are bundled into
/// the build output and not available on disk. However, it can potentially
/// be helpful for testing / development purposes.
factory BaseOptions.path(String path) => BaseOptions._(
modelAssetPath: path,
type: _BaseOptionsType.path,
);

/// Constructor for [BaseOptions] classes using an in-memory pointer to the
/// MediaPipe SDK.
///
/// In practice, this is the only option supported for production builds.
factory BaseOptions.memory(Uint8List buffer) {
return BaseOptions._(
modelAssetBuffer: buffer,
type: _BaseOptionsType.memory,
);
}

/// The model asset file contents as bytes;
final Uint8List? modelAssetBuffer;

/// Path to the model asset file.
final String? modelAssetPath;

final _BaseOptionsType _type;

/// Converts this pure-Dart representation into C-memory suitable for the
/// MediaPipe SDK to instantiate various classifiers.
Pointer<bindings.BaseOptions> toStruct() {
final struct = calloc<bindings.BaseOptions>();

if (modelAssetPath != null) {
struct.ref.model_asset_path = prepareString(modelAssetPath!);
}
if (modelAssetBuffer != null) {
struct.ref.model_asset_buffer = prepareUint8List(modelAssetBuffer!);
struct.ref.model_asset_buffer_count = modelAssetBuffer!.lengthInBytes;
switch (_type) {
case _BaseOptionsType.path:
{
struct.ref.model_asset_path = prepareString(modelAssetPath!);
}
case _BaseOptionsType.memory:
{
struct.ref.model_asset_buffer = prepareUint8List(modelAssetBuffer!);
struct.ref.model_asset_buffer_count = modelAssetBuffer!.lengthInBytes;
}
}

return struct;
}

@override
List<Object?> get props => [modelAssetBuffer, modelAssetPath];

/// Releases all C memory held by this [bindings.BaseOptions] struct.
static void freeStruct(bindings.BaseOptions struct) {
if (struct.model_asset_buffer.address != 0) {
calloc.free(struct.model_asset_buffer);
}
if (struct.model_asset_path.address != 0) {
if (struct.model_asset_path.isNotNullPointer) {
calloc.free(struct.model_asset_path);
}
if (struct.model_asset_buffer.isNotNullPointer) {
calloc.free(struct.model_asset_buffer);
}
}

@override
List<Object?> get props => [
modelAssetBuffer,
modelAssetPath,
modelAssetBuffer?.lengthInBytes,
];
}

enum _BaseOptionsType { path, memory }

/// Dart representation of MediaPipe's "ClassifierOptions" concept.
///
/// Classifier options shared across MediaPipe classification tasks.
Expand Down
54 changes: 54 additions & 0 deletions packages/mediapipe-core/lib/src/test_utils.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';

import 'package:mediapipe_core/mediapipe_core.dart';
import 'package:mediapipe_core/src/third_party/mediapipe/generated/mediapipe_common_bindings.dart'
as core_bindings;

/// Hydrates a faked [core_bindings.Category] object.
void populateCategory(
core_bindings.Category category, {
int index = 1,
double score = 0.9,
String? categoryName = 'Positive',
String? displayName,
}) {
category.index = index;
category.score = score;

if (categoryName != null) {
category.category_name = prepareString(categoryName);
}
if (displayName != null) {
category.display_name = prepareString(displayName);
}
}

/// Hydrates a faked [core_bindings.Classifications] object.
///
/// If [categories] is passed, [numCategories] must indicate its length;
/// otherwise, this function generates [numCategories] faked
/// [core_bindings.Category] objects.
void populateClassifications(
core_bindings.Classifications classifications, {
Pointer<core_bindings.Category>? categories,
int numCategories = 2,
int headIndex = 1,
String headName = 'Head',
}) {
if (isNotNullOrNullPointer(categories)) {
classifications.categories = categories!;
classifications.categories_count = numCategories;
} else {
final ptrs = calloc<core_bindings.Category>(numCategories);
int count = 0;
while (count < numCategories) {
populateCategory(ptrs[count]);
count++;
}
classifications.categories = ptrs;
classifications.categories_count = numCategories;
}
classifications.head_name = prepareString(headName);
classifications.head_index = headIndex;
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ import 'dart:ffi' as ffi;
final class BaseOptions extends ffi.Struct {
external ffi.Pointer<ffi.Char> model_asset_buffer;

external ffi.Pointer<ffi.Char> model_asset_path;

@ffi.UnsignedInt()
external int model_asset_buffer_count;

external ffi.Pointer<ffi.Char> model_asset_path;
}

final class __mbstate_t extends ffi.Union {
Expand Down Expand Up @@ -152,6 +152,13 @@ final class Category extends ffi.Struct {
external ffi.Pointer<ffi.Char> display_name;
}

final class Categories extends ffi.Struct {
external ffi.Pointer<Category> categories;

@ffi.Uint32()
external int categories_count;
}

final class Classifications extends ffi.Struct {
external ffi.Pointer<Category> categories;

Expand Down
Loading