4 * This file is part of FFmpeg.
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.
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.
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
23 * DNN OpenVINO backend implementation.
26 #include "dnn_backend_openvino.h"
27 #include "libavformat/avio.h"
28 #include "libavutil/avassert.h"
29 #include <c_api/ie_c_api.h>
31 typedef struct OVContext {
35 typedef struct OVModel{
38 ie_network_t *network;
39 ie_executable_network_t *exe_network;
40 ie_infer_request_t *infer_request;
41 ie_blob_t *input_blob;
44 static const AVClass dnn_openvino_class = {
45 .class_name = "dnn_openvino",
46 .item_name = av_default_item_name,
48 .version = LIBAVUTIL_VERSION_INT,
49 .category = AV_CLASS_CATEGORY_FILTER,
52 static DNNDataType precision_to_datatype(precision_e precision)
59 av_assert0(!"not supported yet.");
64 static DNNReturnType get_input_ov(void *model, DNNData *input, const char *input_name)
66 OVModel *ov_model = (OVModel *)model;
67 OVContext *ctx = &ov_model->ctx;
68 char *model_input_name = NULL;
70 size_t model_input_count = 0;
72 precision_e precision;
74 status = ie_network_get_inputs_number(ov_model->network, &model_input_count);
76 av_log(ctx, AV_LOG_ERROR, "Failed to get input count\n");
80 for (size_t i = 0; i < model_input_count; i++) {
81 status = ie_network_get_input_name(ov_model->network, i, &model_input_name);
83 av_log(ctx, AV_LOG_ERROR, "Failed to get No.%d input's name\n", (int)i);
86 if (strcmp(model_input_name, input_name) == 0) {
87 ie_network_name_free(&model_input_name);
88 status |= ie_network_get_input_dims(ov_model->network, input_name, &dims);
89 status |= ie_network_get_input_precision(ov_model->network, input_name, &precision);
91 av_log(ctx, AV_LOG_ERROR, "Failed to get No.%d input's dims or precision\n", (int)i);
95 // The order of dims in the openvino is fixed and it is always NCHW for 4-D data.
96 // while we pass NHWC data from FFmpeg to openvino
97 status = ie_network_set_input_layout(ov_model->network, input_name, NHWC);
99 av_log(ctx, AV_LOG_ERROR, "Input \"%s\" does not match layout NHWC\n", input_name);
103 input->channels = dims.dims[1];
104 input->height = dims.dims[2];
105 input->width = dims.dims[3];
106 input->dt = precision_to_datatype(precision);
110 ie_network_name_free(&model_input_name);
113 av_log(ctx, AV_LOG_ERROR, "Could not find \"%s\" in model\n", model_input_name);
117 static DNNReturnType set_input_ov(void *model, DNNData *input, const char *input_name)
119 OVModel *ov_model = (OVModel *)model;
120 OVContext *ctx = &ov_model->ctx;
123 precision_e precision;
124 ie_blob_buffer_t blob_buffer;
126 status = ie_exec_network_create_infer_request(ov_model->exe_network, &ov_model->infer_request);
130 status = ie_infer_request_get_blob(ov_model->infer_request, input_name, &ov_model->input_blob);
134 status |= ie_blob_get_dims(ov_model->input_blob, &dims);
135 status |= ie_blob_get_precision(ov_model->input_blob, &precision);
139 av_assert0(input->channels == dims.dims[1]);
140 av_assert0(input->height == dims.dims[2]);
141 av_assert0(input->width == dims.dims[3]);
142 av_assert0(input->dt == precision_to_datatype(precision));
144 status = ie_blob_get_buffer(ov_model->input_blob, &blob_buffer);
147 input->data = blob_buffer.buffer;
152 if (ov_model->input_blob)
153 ie_blob_free(&ov_model->input_blob);
154 if (ov_model->infer_request)
155 ie_infer_request_free(&ov_model->infer_request);
156 av_log(ctx, AV_LOG_ERROR, "Failed to create inference instance or get input data/dims/precision/memory\n");
160 DNNModel *ff_dnn_load_model_ov(const char *model_filename, const char *options)
162 DNNModel *model = NULL;
163 OVModel *ov_model = NULL;
165 ie_config_t config = {NULL, NULL, NULL};
167 model = av_malloc(sizeof(DNNModel));
172 ov_model = av_mallocz(sizeof(OVModel));
175 ov_model->ctx.class = &dnn_openvino_class;
177 status = ie_core_create("", &ov_model->core);
181 status = ie_core_read_network(ov_model->core, model_filename, NULL, &ov_model->network);
185 status = ie_core_load_network(ov_model->core, ov_model->network, "CPU", &config, &ov_model->exe_network);
189 model->model = (void *)ov_model;
190 model->set_input = &set_input_ov;
191 model->get_input = &get_input_ov;
192 model->options = options;
200 if (ov_model->exe_network)
201 ie_exec_network_free(&ov_model->exe_network);
202 if (ov_model->network)
203 ie_network_free(&ov_model->network);
205 ie_core_free(&ov_model->core);
211 DNNReturnType ff_dnn_execute_model_ov(const DNNModel *model, DNNData *outputs, const char **output_names, uint32_t nb_output)
214 precision_e precision;
215 ie_blob_buffer_t blob_buffer;
216 OVModel *ov_model = (OVModel *)model->model;
217 OVContext *ctx = &ov_model->ctx;
218 IEStatusCode status = ie_infer_request_infer(ov_model->infer_request);
220 av_log(ctx, AV_LOG_ERROR, "Failed to start synchronous model inference\n");
224 for (uint32_t i = 0; i < nb_output; ++i) {
225 const char *output_name = output_names[i];
226 ie_blob_t *output_blob = NULL;
227 status = ie_infer_request_get_blob(ov_model->infer_request, output_name, &output_blob);
229 av_log(ctx, AV_LOG_ERROR, "Failed to get model output data\n");
233 status = ie_blob_get_buffer(output_blob, &blob_buffer);
235 av_log(ctx, AV_LOG_ERROR, "Failed to access output memory\n");
239 status |= ie_blob_get_dims(output_blob, &dims);
240 status |= ie_blob_get_precision(output_blob, &precision);
242 av_log(ctx, AV_LOG_ERROR, "Failed to get dims or precision of output\n");
246 outputs[i].channels = dims.dims[1];
247 outputs[i].height = dims.dims[2];
248 outputs[i].width = dims.dims[3];
249 outputs[i].dt = precision_to_datatype(precision);
250 outputs[i].data = blob_buffer.buffer;
256 void ff_dnn_free_model_ov(DNNModel **model)
259 OVModel *ov_model = (OVModel *)(*model)->model;
260 if (ov_model->input_blob)
261 ie_blob_free(&ov_model->input_blob);
262 if (ov_model->infer_request)
263 ie_infer_request_free(&ov_model->infer_request);
264 if (ov_model->exe_network)
265 ie_exec_network_free(&ov_model->exe_network);
266 if (ov_model->network)
267 ie_network_free(&ov_model->network);
269 ie_core_free(&ov_model->core);