Skip to content

Commit 736c6b5

Browse files
committed
Deal with edge cases
Isolate was being fidgety about transferring the Status over isolate barriers. Timestamp needs to be kept inside the graph runner and then recovered so that when switching from camera and live image you always get the latest timestamp.
1 parent 8525a1c commit 736c6b5

File tree

11 files changed

+97
-11
lines changed

11 files changed

+97
-11
lines changed

lib/interop/generated_bindings.dart

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,20 @@ class OpenVINO {
4747
late final _freeStatusOrString = _freeStatusOrStringPtr
4848
.asFunction<void Function(ffi.Pointer<StatusOrString>)>();
4949

50+
void freeStatusOrInt(
51+
ffi.Pointer<StatusOrInt> status,
52+
) {
53+
return _freeStatusOrInt(
54+
status,
55+
);
56+
}
57+
58+
late final _freeStatusOrIntPtr =
59+
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<StatusOrInt>)>>(
60+
'freeStatusOrInt');
61+
late final _freeStatusOrInt =
62+
_freeStatusOrIntPtr.asFunction<void Function(ffi.Pointer<StatusOrInt>)>();
63+
5064
void freeStatusOrImageInference(
5165
ffi.Pointer<StatusOrImageInference> status,
5266
) {
@@ -843,6 +857,20 @@ class OpenVINO {
843857
ffi.Pointer<Status> Function(CGraphRunner, int,
844858
ImageInferenceCallbackFunction, bool, bool, bool)>();
845859

860+
ffi.Pointer<StatusOrInt> graphRunnerGetTimestamp(
861+
CGraphRunner instance,
862+
) {
863+
return _graphRunnerGetTimestamp(
864+
instance,
865+
);
866+
}
867+
868+
late final _graphRunnerGetTimestampPtr = _lookup<
869+
ffi.NativeFunction<ffi.Pointer<StatusOrInt> Function(CGraphRunner)>>(
870+
'graphRunnerGetTimestamp');
871+
late final _graphRunnerGetTimestamp = _graphRunnerGetTimestampPtr
872+
.asFunction<ffi.Pointer<StatusOrInt> Function(CGraphRunner)>();
873+
846874
ffi.Pointer<Status> graphRunnerStopCamera(
847875
CGraphRunner instance,
848876
) {

lib/interop/graph_runner.dart

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,21 @@ class GraphRunner {
3636
return GraphRunner(result);
3737
}
3838

39+
int getTimestamp() {
40+
final status = ov.graphRunnerGetTimestamp(instance.ref.value);
41+
42+
if (StatusEnum.fromValue(status.ref.status) != StatusEnum.OkStatus) {
43+
throw "GraphRunner::get error: ${status.ref.status} ${status.ref.message.toDartString()}";
44+
}
45+
final content = status.ref.value;
46+
ov.freeStatusOrInt(status);
47+
return content;
48+
}
49+
3950
Future<String> get() async {
51+
int instanceAddress = instance.ref.value.address;
4052
return await Isolate.run(() {
41-
final status = ov.graphRunnerGet(instance.ref.value);
53+
final status = ov.graphRunnerGet(Pointer<Void>.fromAddress(instanceAddress));
4254

4355
if (StatusEnum.fromValue(status.ref.status) != StatusEnum.OkStatus) {
4456
throw "GraphRunner::get error: ${status.ref.status} ${status.ref.message.toDartString()}";
@@ -78,12 +90,14 @@ class GraphRunner {
7890
}
7991

8092
Future<void> queueImage(String nodeName, int timestamp, Uint8List file) async {
93+
94+
int instanceAddress = instance.ref.value.address;
8195
await Isolate.run(() {
8296
final _data = calloc.allocate<Uint8>(file.lengthInBytes);
8397
final _bytes = _data.asTypedList(file.lengthInBytes);
8498
_bytes.setRange(0, file.lengthInBytes, file);
8599
final nodeNamePtr = nodeName.toNativeUtf8();
86-
final status = ov.graphRunnerQueueImage(instance.ref.value, nodeNamePtr, timestamp, _data, file.lengthInBytes);
100+
final status = ov.graphRunnerQueueImage(Pointer<Void>.fromAddress(instanceAddress), nodeNamePtr, timestamp, _data, file.lengthInBytes);
87101
calloc.free(nodeNamePtr);
88102

89103
if (StatusEnum.fromValue(status.ref.status) != StatusEnum.OkStatus) {
@@ -93,9 +107,10 @@ class GraphRunner {
93107
}
94108

95109
Future<void> queueSerializationOutput(String nodeName, int timestamp, SerializationOutput output) async {
110+
int instanceAddress = instance.ref.value.address;
96111
await Isolate.run(() {
97112
final nodeNamePtr = nodeName.toNativeUtf8();
98-
final status = ov.graphRunnerQueueSerializationOutput(instance.ref.value, nodeNamePtr, timestamp, output.json, output.csv, output.overlay);
113+
final status = ov.graphRunnerQueueSerializationOutput(Pointer<Void>.fromAddress(instanceAddress), nodeNamePtr, timestamp, output.json, output.csv, output.overlay);
99114
calloc.free(nodeNamePtr);
100115

101116
if (StatusEnum.fromValue(status.ref.status) != StatusEnum.OkStatus) {

lib/pages/computer_vision/live_inference.dart

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,20 @@ class LiveInference extends StatefulWidget {
3838

3939
class _LiveInferenceState extends State<LiveInference> {
4040
Future<ImageInferenceResult>? inferenceResult;
41+
late ImageInferenceProvider inferenceProvider;
4142
ui.Image? image;
4243

4344
Future<List<CameraDevice>> cameraDevices = CameraDevice.getDevices();
4445
CameraDevice? cameraDevice;
4546

4647
LiveInferenceMode mode = LiveInferenceMode.image;
4748

49+
@override
50+
void initState() {
51+
super.initState();
52+
inferenceProvider = Provider.of<ImageInferenceProvider>(context, listen: false);
53+
}
54+
4855
void showUploadMenu() async {
4956
FilePickerResult? result = await FilePicker.platform.pickFiles(type: FileType.image);
5057

@@ -54,16 +61,19 @@ class _LiveInferenceState extends State<LiveInference> {
5461
}
5562

5663
void uploadFile(String path) async {
64+
if (mode == LiveInferenceMode.image) {
65+
inferenceProvider.closeCamera();
66+
}
5767
setState(() {
68+
mode = LiveInferenceMode.image;
69+
cameraDevice = null;
5870
image = null;
5971
inferenceResult = null;
6072
});
6173

6274
Uint8List imageData = File(path).readAsBytesSync();
63-
final inferenceProvider = Provider.of<ImageInferenceProvider>(context, listen: false);
6475
final uiImage = await decodeImageFromList(imageData);
6576
setState(() {
66-
mode = LiveInferenceMode.image;
6777
image = uiImage;
6878
inferenceResult = inferenceProvider.infer(imageData, SerializationOutput(json: true));
6979
});
@@ -125,10 +135,10 @@ class _LiveInferenceState extends State<LiveInference> {
125135
buttonBuilder: (context, callback) {
126136
return NoOutlineButton(
127137
onPressed: callback,
128-
child: const Row(
138+
child: Row(
129139
children: [
130-
Text("Choose camera"),
131-
Padding(
140+
cameraDevice == null ? const Text("Choose camera") : Text("Choose camera: ${cameraDevice!.name}"),
141+
const Padding(
132142
padding: EdgeInsets.only(left: 8),
133143
child: Icon(FluentIcons.chevron_down, size: 12),
134144
),

lib/pages/computer_vision/widgets/camera_view.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
/*
2+
* Copyright (c) 2024 Intel Corporation
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
17
import 'dart:async';
28
import 'dart:convert';
39

lib/providers/image_inference_provider.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ class ImageInferenceProvider extends ChangeNotifier {
1717
Completer<void> loaded = Completer<void>();
1818
final Project project;
1919
final String device;
20-
int timestamp = 0;
2120
GraphRunner? _inference;
2221
GraphRunner? get inference => _inference;
2322

@@ -51,9 +50,9 @@ class ImageInferenceProvider extends ChangeNotifier {
5150
}
5251

5352
Future<ImageInferenceResult> infer(Uint8List file, SerializationOutput output) async {
53+
int timestamp = inference!.getTimestamp() + 1;
5454
_inference!.queueImage("input", timestamp, file);
5555
_inference!.queueSerializationOutput("serialization_output", timestamp, output);
56-
timestamp += 1;
5756
final result = await _inference!.get();
5857
return ImageInferenceResult.fromJson(jsonDecode(result));
5958
}

openvino_bindings/src/bindings.cc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ void freeStatusOrString(StatusOrString *status) {
4040
delete status;
4141
}
4242

43+
void freeStatusOrInt(StatusOrInt *status) {
44+
delete status;
45+
}
46+
4347
//void freeStatusOrSpeechToText(StatusOrSpeechToText *status) {
4448
// delete status;
4549
//}
@@ -435,6 +439,16 @@ Status* graphRunnerStartCamera(CGraphRunner instance, int camera_index, ImageInf
435439
}
436440
}
437441

442+
StatusOrInt* graphRunnerGetTimestamp(CGraphRunner instance) {
443+
try {
444+
auto graph_runner = reinterpret_cast<GraphRunner*>(instance);
445+
return new StatusOrInt{OkStatus, "", (int)graph_runner->timestamp};
446+
} catch (...) {
447+
auto except = handle_exceptions();
448+
return new StatusOrInt{except->status, except->message};
449+
}
450+
}
451+
438452
Status* graphRunnerStopCamera(CGraphRunner instance) {
439453
try {
440454
reinterpret_cast<GraphRunner*>(instance)->stop_camera();

openvino_bindings/src/bindings.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ typedef void (*VLMInferenceCallbackFunction)(StatusOrString*);
156156

157157
EXPORT void freeStatus(Status *status);
158158
EXPORT void freeStatusOrString(StatusOrString *status);
159+
EXPORT void freeStatusOrInt(StatusOrInt *status);
159160
EXPORT void freeStatusOrImageInference(StatusOrImageInference *status);
160161
EXPORT void freeStatusOrLLMInference(StatusOrLLMInference *status);
161162
EXPORT void freeStatusOrSpeechToText(StatusOrSpeechToText *status);
@@ -203,6 +204,7 @@ EXPORT Status* graphRunnerQueueSerializationOutput(CGraphRunner instance, const
203204
EXPORT StatusOrString* graphRunnerGet(CGraphRunner instance);
204205
EXPORT Status* graphRunnerStop(CGraphRunner instance);
205206
EXPORT Status* graphRunnerStartCamera(CGraphRunner instance, int cameraIndex, ImageInferenceCallbackFunction callback, bool json, bool csv, bool overlay);
207+
EXPORT StatusOrInt* graphRunnerGetTimestamp(CGraphRunner instance);
206208
EXPORT Status* graphRunnerStopCamera(CGraphRunner instance);
207209

208210
EXPORT StatusOrSpeechToText* speechToTextOpen(const char* model_path, const char* device);

openvino_bindings/src/mediapipe/graph_runner.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@ void GraphRunner::stop() {
4040
void GraphRunner::open_camera(int deviceIndex, SerializationOutput serializationOutput, const std::function<void(std::string output)>& callback) {
4141
camera_handler = std::make_shared<CameraHandler>(deviceIndex);
4242
auto lambda_callback = [this, callback, serializationOutput](cv::Mat frame) {
43+
timestamp++;
4344
queue("input", timestamp, frame);
4445
queue("serialization_output", timestamp, serializationOutput);
4546
callback(get());
46-
timestamp++;
4747
};
4848

4949
camera_handler->open_camera(lambda_callback);

openvino_bindings/src/mediapipe/graph_runner.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ class GraphRunner {
2929
if (timestamp > this->timestamp) {
3030
this->timestamp = timestamp;
3131
}
32+
33+
std::cout << "timestamp: " << timestamp << std::endl;
3234
auto packet = mediapipe::MakePacket<T>(content).At(mediapipe::Timestamp(timestamp));
3335
graph->AddPacketToInputStream(name, packet);
3436
}

openvino_bindings/src/utils/camera_handler.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
/*
2+
* Copyright (c) 2024 Intel Corporation
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
16
#include "camera_handler.h"
27

38

0 commit comments

Comments
 (0)