1 /*
2 * Copyright (c) 2020
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 /**
22 * @file
23 * DNN OpenVINO backend implementation.
24 */
25
34 #include "../internal.h"
36 #include <c_api/ie_c_api.h>
38
46
51
62
63 // one request for one call to openvino
70
71 #define APPEND_STRING(generated_string, iterate_string) \
72 generated_string = generated_string ? av_asprintf("%s %s", generated_string, iterate_string) : \
73 av_asprintf("%s", iterate_string);
74
75 #define OFFSET(x) offsetof(OVContext, x)
76 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM
83 };
84
86
88 {
89 switch (precision)
90 {
91 case FP32:
93 case U8:
95 default:
98 }
99 }
100
102 {
103 switch (dt)
104 {
106 return sizeof(float);
108 return sizeof(uint8_t);
109 default:
111 return 1;
112 }
113 }
114
116 {
117 dimensions_t dims;
118 precision_e precision;
119 ie_blob_buffer_t blob_buffer;
123 ie_blob_t *input_blob =
NULL;
126
130
135 }
136
137 status |= ie_blob_get_dims(input_blob, &dims);
138 status |= ie_blob_get_precision(input_blob, &precision);
140 ie_blob_free(&input_blob);
143 }
144
145 status = ie_blob_get_buffer(input_blob, &blob_buffer);
147 ie_blob_free(&input_blob);
150 }
151
152 input.height = dims.dims[2];
153 input.width = dims.dims[3];
154 input.channels = dims.dims[1];
155 input.data = blob_buffer.buffer;
157 // all models in openvino open model zoo use BGR as input,
158 // change to be an option when necessary.
160
161 for (
int i = 0;
i <
ctx->options.batch_size; ++
i) {
163 if (!lltask) {
164 break;
165 }
174 } else {
176 }
177 }
178 break;
181 break;
184 break;
185 default:
187 break;
188 }
191 }
192 ie_blob_free(&input_blob);
193
195 }
196
198 {
199 dimensions_t dims;
200 precision_e precision;
207 ie_blob_t *output_blob =
NULL;
208 ie_blob_buffer_t blob_buffer;
211
214 //incorrect output name
215 char *model_output_name =
NULL;
216 char *all_output_names =
NULL;
217 size_t model_output_count = 0;
219 status = ie_network_get_outputs_number(ov_model->
network, &model_output_count);
220 for (
size_t i = 0;
i < model_output_count;
i++) {
221 status = ie_network_get_output_name(ov_model->
network,
i, &model_output_name);
222 APPEND_STRING(all_output_names, model_output_name)
223 }
225 "output \"%s\" may not correct, all output(s) are: \"%s\"\n",
227 return;
228 }
229
230 status = ie_blob_get_buffer(output_blob, &blob_buffer);
232 ie_blob_free(&output_blob);
234 return;
235 }
236
237 status |= ie_blob_get_dims(output_blob, &dims);
238 status |= ie_blob_get_precision(output_blob, &precision);
240 ie_blob_free(&output_blob);
242 return;
243 }
244
245 output.channels = dims.dims[1];
246 output.height = dims.dims[2];
247 output.width = dims.dims[3];
249 output.data = blob_buffer.buffer;
250
256
262 } else {
264 }
265 } else {
268 }
269 break;
273 return;
274 }
276 break;
280 return;
281 }
283 break;
284 default:
286 break;
287 }
288
292 }
293 ie_blob_free(&output_blob);
294
300 return;
301 }
302 }
303
305 {
308 ie_available_devices_t a_dev;
310 char *all_dev_names =
NULL;
311
312 // batch size
313 if (
ctx->options.batch_size <= 0) {
314 ctx->options.batch_size = 1;
315 }
316
317 if (
ctx->options.batch_size > 1) {
318 input_shapes_t input_shapes;
319 status = ie_network_get_input_shapes(ov_model->
network, &input_shapes);
321 goto err;
322 for (
int i = 0;
i < input_shapes.shape_num;
i++)
323 input_shapes.shapes[
i].shape.dims[0] =
ctx->options.batch_size;
324 status = ie_network_reshape(ov_model->
network, input_shapes);
325 ie_network_input_shapes_free(&input_shapes);
327 goto err;
328 }
329
330 // The order of dims in the openvino is fixed and it is always NCHW for 4-D data.
331 // while we pass NHWC data from FFmpeg to openvino
332 status = ie_network_set_input_layout(ov_model->
network, input_name, NHWC);
335 goto err;
336 }
337 status = ie_network_set_output_layout(ov_model->
network, output_name, NHWC);
340 goto err;
341 }
342
343 // all models in openvino open model zoo use BGR with range [0.0f, 255.0f] as input,
344 // we don't have a AVPixelFormat to describe it, so we'll use AV_PIX_FMT_BGR24 and
345 // ask openvino to do the conversion internally.
346 // the current supported SR model (frame processing) is generated from tensorflow model,
347 // and its input is Y channel as float with range [0.0f, 1.0f], so do not set for this case.
348 // TODO: we need to get a final clear&general solution with all backends/formats considered.
350 status = ie_network_set_input_precision(ov_model->
network, input_name, U8);
353 goto err;
354 }
355 }
356
360 status = ie_core_get_available_devices(ov_model->
core, &a_dev);
363 goto err;
364 }
365 for (
int i = 0;
i < a_dev.num_devices;
i++) {
366 APPEND_STRING(all_dev_names, a_dev.devices[
i])
367 }
369 ctx->options.device_type, all_dev_names);
370 goto err;
371 }
372
373 // create infer_requests for async execution
374 if (
ctx->options.nireq <= 0) {
375 // the default value is a rough estimation
377 }
378
381 goto err;
382 }
383
384 for (
int i = 0;
i <
ctx->options.nireq;
i++) {
386 if (!item) {
387 goto err;
388 }
389
394 goto err;
395 }
396
399 goto err;
400 }
401
404 goto err;
405 }
407 }
408
411 goto err;
412 }
413
416 goto err;
417 }
418
420
421 err:
424 }
425
427 {
434
439 }
440
443 ov_model = task->
model;
445
449 goto err;
450 }
454 goto err;
455 }
459 goto err;
460 }
462 } else {
465 goto err;
466 }
470 goto err;
471 }
474 }
475 err:
479 }
481 }
482
484 {
487 char *model_input_name =
NULL;
488 char *all_input_names =
NULL;
490 size_t model_input_count = 0;
491 dimensions_t dims;
492 precision_e precision;
493 int input_resizable =
ctx->options.input_resizable;
494
495 status = ie_network_get_inputs_number(ov_model->
network, &model_input_count);
499 }
500
501 for (
size_t i = 0;
i < model_input_count;
i++) {
502 status = ie_network_get_input_name(ov_model->
network,
i, &model_input_name);
506 }
507 if (strcmp(model_input_name, input_name) == 0) {
508 ie_network_name_free(&model_input_name);
509 status |= ie_network_get_input_dims(ov_model->
network, input_name, &dims);
510 status |= ie_network_get_input_precision(ov_model->
network, input_name, &precision);
514 }
515
516 input->channels = dims.dims[1];
517 input->height = input_resizable ? -1 : dims.dims[2];
518 input->width = input_resizable ? -1 : dims.dims[3];
521 } else {
522 //incorrect input name
523 APPEND_STRING(all_input_names, model_input_name)
524 }
525
526 ie_network_name_free(&model_input_name);
527 }
528
529 av_log(
ctx,
AV_LOG_ERROR,
"Could not find \"%s\" in model, all input(s) are: \"%s\"\n", input_name, all_input_names);
531 }
532
534 {
538
540 if (!sd) { // this frame has nothing detected
541 return 0;
542 }
543
545 return 0;
546 }
547
550 return 0;
551 }
552
553 for (uint32_t
i = 0;
i <
header->nb_bboxes;
i++) {
555 if (bbox->
x < 0 || bbox->
w < 0 || bbox->
x + bbox->
w >=
frame->width) {
556 return 0;
557 }
558 if (bbox->
y < 0 || bbox->
h < 0 || bbox->
y + bbox->
h >=
frame->width) {
559 return 0;
560 }
561
563 return 0;
564 }
565 }
566
567 return 1;
568 }
569
571 {
572 switch (func_type) {
575 {
577 if (!lltask) {
579 }
586 }
588 }
590 {
595
598
601 }
602
605
609
612 continue;
613 }
614 }
615
617 if (!lltask) {
619 }
626 }
627 }
629 }
630 default:
633 }
634 }
635
637 const char *output_name, int *output_width, int *output_height)
638 {
645 input_shapes_t input_shapes;
648 .output_names = &output_name,
649 .nb_output = 1,
652 };
653
657 }
658
659 if (
ctx->options.input_resizable) {
660 status = ie_network_get_input_shapes(ov_model->
network, &input_shapes);
661 input_shapes.shapes->shape.dims[2] = input_height;
662 input_shapes.shapes->shape.dims[3] = input_width;
663 status |= ie_network_reshape(ov_model->
network, input_shapes);
664 ie_network_input_shapes_free(&input_shapes);
668 }
669 }
670
675 }
676 }
677
680 }
681
685 goto err;
686 }
687
689 if (!request) {
692 goto err;
693 }
694
698 err:
702 }
703
705 {
710
712 if (!model){
714 }
715
717 if (!ov_model) {
720 }
721 model->
model = ov_model;
722 ov_model->
model = model;
723 ov_model->
ctx.
class = &dnn_openvino_class;
725
726 //parse options
730 goto err;
731 }
732
735 goto err;
736
739 ie_version_t ver;
740 ver = ie_c_api_version();
742 "Please check if the model version matches the runtime OpenVINO %s\n",
743 model_filename, ver.api_version);
744 ie_version_free(&ver);
745 goto err;
746 }
747
753
754 return model;
755
756 err:
759 }
760
762 {
768
771 }
772
777 }
778 }
779
781 if (!task) {
784 }
785
789 }
790
795 }
796
800 }
801
802 if (
ctx->options.async) {
805 if (!request) {
808 }
809
813 }
814 }
815
817 }
818 else {
820 // Classification filter has not been completely
821 // tested with the sync mode. So, do not support now.
824 }
825
826 if (
ctx->options.batch_size > 1) {
829 }
830
832 if (!request) {
835 }
837 }
838 }
839
841 {
844 }
845
847 {
853
855 // no pending task need to flush
857 }
858
860 if (!request) {
863 }
864
869 }
874 }
879 }
880
882 }
883
885 {
886 if (*model){
892 }
895 }
897
901 }
903
909 }
911
915 ie_network_free(&ov_model->
network);
917 ie_core_free(&ov_model->
core);
920 }
921 }