FFmpeg
dnn_backend_onnx.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2026 Advanced Micro Devices, Inc.
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 ONNX Runtime backend implementation.
24  */
25 
26 #include "libavutil/opt.h"
27 #include "libavutil/avassert.h"
28 #include "libavutil/mem.h"
29 #include "libavutil/avstring.h"
30 #include "libavutil/thread.h"
32 #include "../filters.h"
33 #include "dnn_io_proc.h"
34 #include "dnn_backend_common.h"
35 #include "queue.h"
36 #include "safe_queue.h"
37 #include <onnxruntime_c_api.h>
38 #include <inttypes.h>
39 #include <stdio.h>
40 #include <string.h>
41 
42 typedef struct ONNXModel {
45  OrtEnv *env;
46  OrtSession *session;
47  OrtSessionOptions *session_options;
48  OrtAllocator *allocator;
55 } ONNXModel;
56 
57 typedef struct ONNXInferRequest {
58  OrtValue *input_tensor;
59  OrtValue *output_tensor;
60  void *input_data;
62 
63 typedef struct ONNXRequestItem {
68 
69 #define OFFSET(x) offsetof(ONNXOptions, x)
70 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM
71 static const AVOption dnn_onnx_options[] = {
72  { "threads_per_operation", "number of CPU threads per ORT operator (device=cpu only)",
73  OFFSET(num_threads), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS },
74  { NULL }
75 };
76 
77 AVFILTER_DEFINE_CLASS(dnn_onnx);
78 
79 static const OrtApi *g_ort = NULL;
81 
82 static void init_ort_api(void)
83 {
84  g_ort = OrtGetApiBase()->GetApi(ORT_API_VERSION);
85 }
86 
87 #define ORT_ABORT_ON_ERROR(expr) \
88  do { \
89  OrtStatus *status = (expr); \
90  if (status != NULL) { \
91  const char *msg = g_ort->GetErrorMessage(status); \
92  av_log(ctx, AV_LOG_ERROR, "ONNX Runtime error: %s\n", msg); \
93  g_ort->ReleaseStatus(status); \
94  goto err; \
95  } \
96  } while (0)
97 
98 static int extract_lltask_from_task(TaskItem *task, Queue *lltask_queue)
99 {
100  ONNXModel *onnx_model = (ONNXModel *)task->model;
101  DnnContext *ctx = onnx_model->ctx;
102  LastLevelTaskItem *lltask = av_malloc(sizeof(*lltask));
103 
104  if (!lltask) {
105  av_log(ctx, AV_LOG_ERROR, "Failed to allocate memory for LastLevelTaskItem\n");
106  return AVERROR(ENOMEM);
107  }
108  task->inference_todo = 1;
109  task->inference_done = 0;
110  lltask->task = task;
111  if (ff_queue_push_back(lltask_queue, lltask) < 0) {
112  av_log(ctx, AV_LOG_ERROR, "Failed to push back lltask_queue.\n");
113  av_freep(&lltask);
114  return AVERROR(ENOMEM);
115  }
116  return 0;
117 }
118 
119 static void onnx_free_request(ONNXInferRequest *request)
120 {
121  if (!request)
122  return;
123  if (request->input_tensor) {
124  g_ort->ReleaseValue(request->input_tensor);
125  request->input_tensor = NULL;
126  }
127  av_freep(&request->input_data);
128  if (request->output_tensor) {
129  g_ort->ReleaseValue(request->output_tensor);
130  request->output_tensor = NULL;
131  }
132 }
133 
135 {
136  ONNXRequestItem *item;
137  if (!arg || !*arg)
138  return;
139  item = *arg;
141  av_freep(&item->infer_request);
142  av_freep(&item->lltask);
144  av_freep(arg);
145 }
146 
147 static void dnn_free_model_onnx(DNNModel **model)
148 {
149  ONNXModel *onnx_model;
150  if (!model || !*model)
151  return;
152 
153  onnx_model = (ONNXModel *)(*model);
154 
155  while (ff_safe_queue_size(onnx_model->request_queue) != 0) {
157  destroy_request_item(&item);
158  }
160 
161  while (ff_queue_size(onnx_model->lltask_queue) != 0) {
163  av_freep(&item);
164  }
165  ff_queue_destroy(onnx_model->lltask_queue);
166 
167  while (ff_queue_size(onnx_model->task_queue) != 0) {
168  TaskItem *item = (TaskItem *)ff_queue_pop_front(onnx_model->task_queue);
169  av_frame_free(&item->in_frame);
170  av_frame_free(&item->out_frame);
171  av_freep(&item);
172  }
173  ff_queue_destroy(onnx_model->task_queue);
174 
175  if (onnx_model->session)
176  g_ort->ReleaseSession(onnx_model->session);
177  if (onnx_model->session_options)
178  g_ort->ReleaseSessionOptions(onnx_model->session_options);
179  if (onnx_model->env)
180  g_ort->ReleaseEnv(onnx_model->env);
181 
182  av_freep(&onnx_model);
183  *model = NULL;
184 }
185 
186 static int get_input_onnx(DNNModel *model, DNNData *input, const char *input_name)
187 {
188  ONNXModel *onnx_model = (ONNXModel *)model;
189  DnnContext *ctx = onnx_model->ctx;
190  OrtTypeInfo *type_info = NULL;
191  const OrtTensorTypeAndShapeInfo *tensor_info = NULL;
192  size_t num_dims;
193  size_t input_count = 0;
194  size_t input_index = 0;
195  int found_input = 0;
196  int64_t *dims;
197  ONNXTensorElementDataType tensor_type;
198  OrtStatus *status;
199 
200  if (!input_name || !*input_name) {
201  av_log(ctx, AV_LOG_ERROR, "ONNX input name is not specified\n");
202  return AVERROR(EINVAL);
203  }
204 
205  if (onnx_model->input_resolved) {
206  *input = onnx_model->input_info;
207  return 0;
208  }
209 
210  status = g_ort->SessionGetInputCount(onnx_model->session, &input_count);
211  if (status != NULL) {
212  const char *msg = g_ort->GetErrorMessage(status);
213  av_log(ctx, AV_LOG_ERROR, "Failed to get input count: %s\n", msg);
214  g_ort->ReleaseStatus(status);
215  return AVERROR(EINVAL);
216  }
217 
218  for (size_t i = 0; i < input_count; i++) {
219  char *name = NULL;
220  status = g_ort->SessionGetInputName(onnx_model->session, i,
221  onnx_model->allocator, &name);
222  if (status != NULL) {
223  g_ort->ReleaseStatus(status);
224  continue;
225  }
226  if (!strcmp(name, input_name)) {
227  input_index = i;
228  found_input = 1;
229  }
230  onnx_model->allocator->Free(onnx_model->allocator, name);
231  if (found_input)
232  break;
233  }
234 
235  if (!found_input) {
236  av_log(ctx, AV_LOG_ERROR, "Input name '%s' not found in ONNX model\n",
237  input_name);
238  return AVERROR(EINVAL);
239  }
240 
241  status = g_ort->SessionGetInputTypeInfo(onnx_model->session, input_index,
242  &type_info);
243  if (status != NULL) {
244  const char *msg = g_ort->GetErrorMessage(status);
245  av_log(ctx, AV_LOG_ERROR, "Failed to get input type info: %s\n", msg);
246  g_ort->ReleaseStatus(status);
247  return AVERROR(EINVAL);
248  }
249 
250  status = g_ort->CastTypeInfoToTensorInfo(type_info, &tensor_info);
251  if (status != NULL) {
252  g_ort->ReleaseTypeInfo(type_info);
253  g_ort->ReleaseStatus(status);
254  return AVERROR(EINVAL);
255  }
256 
257  status = g_ort->GetDimensionsCount(tensor_info, &num_dims);
258  if (status != NULL) {
259  g_ort->ReleaseTypeInfo(type_info);
260  g_ort->ReleaseStatus(status);
261  return AVERROR(EINVAL);
262  }
263 
264  if (num_dims != 4) {
265  avpriv_report_missing_feature(ctx, "Support for %zu dimensional input", num_dims);
266  g_ort->ReleaseTypeInfo(type_info);
267  return AVERROR(ENOSYS);
268  }
269 
270  dims = av_malloc(num_dims * sizeof(int64_t));
271  if (!dims) {
272  g_ort->ReleaseTypeInfo(type_info);
273  return AVERROR(ENOMEM);
274  }
275 
276  g_ort->GetDimensions(tensor_info, dims, num_dims);
277  g_ort->GetTensorElementType(tensor_info, &tensor_type);
278 
279  if (dims[0] > 1) {
281  "ONNX model has fixed batch size %"PRId64", but the backend "
282  "only supports a batch size of 1\n", dims[0]);
283  av_free(dims);
284  g_ort->ReleaseTypeInfo(type_info);
285  return AVERROR(ENOSYS);
286  }
287 
288  /*
289  * The ONNX backend assumes a 4-D NCHW input tensor (the rank check
290  * above already rejects anything else).
291  */
292  input->layout = DL_NCHW;
293  input->dims[0] = dims[0] > 0 ? dims[0] : 1;
294  input->dims[1] = dims[1] > 0 ? dims[1] : 3;
295  input->dims[2] = dims[2] > 0 ? dims[2] : -1;
296  input->dims[3] = dims[3] > 0 ? dims[3] : -1;
297 
298  if (tensor_type == ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT) {
299  input->dt = DNN_FLOAT;
300  } else {
301  av_log(ctx, AV_LOG_ERROR, "Unsupported input tensor data type, only float is supported\n");
302  av_free(dims);
303  g_ort->ReleaseTypeInfo(type_info);
304  return AVERROR(ENOSYS);
305  }
306 
307  /*
308  * The DCO_RGB setting below is only consulted by the dnn_detect and dnn_classify;
309  * the dnn_processing path lets the source AVFrame pixel format determine the
310  * tensor channel order, so both RGB24 and BGR24 inputs work transparently
311  * for that flow.
312  */
313  input->order = DCO_RGB;
314  av_free(dims);
315  g_ort->ReleaseTypeInfo(type_info);
316 
317  onnx_model->input_info = *input;
318  onnx_model->input_resolved = 1;
319  return 0;
320 }
321 
322 static int fill_model_input_onnx(ONNXModel *onnx_model, ONNXRequestItem *request)
323 {
324  LastLevelTaskItem *lltask = NULL;
325  TaskItem *task = NULL;
326  ONNXInferRequest *infer_request = NULL;
327  DNNData input = { 0 };
328  DnnContext *ctx = onnx_model->ctx;
329  int ret, width_idx, height_idx, channel_idx;
330  int64_t input_shape[4];
331  size_t input_tensor_size;
332  OrtMemoryInfo *memory_info;
333  OrtStatus *status;
334 
335  lltask = (LastLevelTaskItem *)ff_queue_pop_front(onnx_model->lltask_queue);
336  if (!lltask) {
337  ret = AVERROR(EINVAL);
338  goto err;
339  }
340  request->lltask = lltask;
341  task = lltask->task;
342  infer_request = request->infer_request;
343 
344  ret = get_input_onnx(&onnx_model->model, &input, task->input_name);
345  if (ret != 0) {
346  goto err;
347  }
348 
349  width_idx = dnn_get_width_idx_by_layout(input.layout);
350  height_idx = dnn_get_height_idx_by_layout(input.layout);
351  channel_idx = dnn_get_channel_idx_by_layout(input.layout);
352 
353  input.dims[height_idx] = task->in_frame->height;
354  input.dims[width_idx] = task->in_frame->width;
355 
356  input_shape[0] = input.dims[0];
357  input_shape[1] = input.dims[channel_idx];
358  input_shape[2] = input.dims[height_idx];
359  input_shape[3] = input.dims[width_idx];
360 
361  input_tensor_size = input_shape[0] * input_shape[1] * input_shape[2] * input_shape[3];
362  input_tensor_size *= sizeof(float);
363 
364  input.data = av_malloc(input_tensor_size);
365  if (!input.data) {
366  ret = AVERROR(ENOMEM);
367  goto err;
368  }
369  infer_request->input_data = input.data;
370 
371  switch (onnx_model->model.func_type) {
372  case DFT_PROCESS_FRAME:
373  input.scale = 255;
374  if (task->do_ioproc) {
375  if (onnx_model->model.frame_pre_proc != NULL) {
376  onnx_model->model.frame_pre_proc(task->in_frame, &input, onnx_model->model.filter_ctx);
377  } else {
379  }
380  }
381  break;
384  break;
385  default:
386  avpriv_report_missing_feature(ctx, "model function type %d", onnx_model->model.func_type);
387  ret = AVERROR(ENOSYS);
388  goto err;
389  }
390 
391  status = g_ort->CreateCpuMemoryInfo(OrtArenaAllocator, OrtMemTypeDefault, &memory_info);
392  if (status != NULL) {
393  ret = AVERROR(ENOMEM);
394  goto err;
395  }
396 
397  status = g_ort->CreateTensorWithDataAsOrtValue(
398  memory_info, input.data, input_tensor_size,
399  input_shape, 4, ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT,
400  &infer_request->input_tensor);
401 
402  g_ort->ReleaseMemoryInfo(memory_info);
403 
404  if (status != NULL) {
405  const char *msg = g_ort->GetErrorMessage(status);
406  av_log(ctx, AV_LOG_ERROR, "Failed to create input tensor: %s\n", msg);
407  g_ort->ReleaseStatus(status);
408  ret = AVERROR(ENOMEM);
409  goto err;
410  }
411 
412  return 0;
413 
414 err:
415  onnx_free_request(infer_request);
416  return ret;
417 }
418 
419 static int onnx_start_inference(void *args)
420 {
421  ONNXRequestItem *request = (ONNXRequestItem *)args;
422  ONNXInferRequest *infer_request = NULL;
423  LastLevelTaskItem *lltask = NULL;
424  TaskItem *task = NULL;
425  ONNXModel *onnx_model = NULL;
426  DnnContext *ctx = NULL;
427  OrtStatus *status;
428  const char *input_names[1];
429  const char *output_names[1];
430 
431  if (!request) {
432  av_log(NULL, AV_LOG_ERROR, "ONNXRequestItem is NULL\n");
433  return AVERROR(EINVAL);
434  }
435 
436  infer_request = request->infer_request;
437  lltask = request->lltask;
438  task = lltask->task;
439  onnx_model = (ONNXModel *)task->model;
440  ctx = onnx_model->ctx;
441 
442  if (task->nb_output > 1) {
444  "Multiple output tensors (%u) for ONNX backend", task->nb_output);
445  return AVERROR(ENOSYS);
446  }
447 
448  if (!task->input_name || !task->output_names || !task->output_names[0]) {
450  "ONNX backend: input/output tensor name was not resolved at load time\n");
451  return AVERROR(EINVAL);
452  }
453 
454  if (!infer_request->input_tensor) {
455  av_log(ctx, AV_LOG_ERROR, "Input tensor is NULL\n");
456  return DNN_GENERIC_ERROR;
457  }
458 
459  if (!onnx_model->output_resolved) {
460  size_t output_count = 0;
461  int found_output = 0;
462 
463  status = g_ort->SessionGetOutputCount(onnx_model->session, &output_count);
464  if (status != NULL) {
465  const char *msg = g_ort->GetErrorMessage(status);
466  av_log(ctx, AV_LOG_ERROR, "Failed to get output count: %s\n", msg);
467  g_ort->ReleaseStatus(status);
468  return AVERROR(EINVAL);
469  }
470 
471  for (size_t i = 0; i < output_count; i++) {
472  char *name = NULL;
473  status = g_ort->SessionGetOutputName(onnx_model->session, i,
474  onnx_model->allocator, &name);
475  if (status != NULL) {
476  g_ort->ReleaseStatus(status);
477  continue;
478  }
479  if (!strcmp(name, task->output_names[0]))
480  found_output = 1;
481  onnx_model->allocator->Free(onnx_model->allocator, name);
482  if (found_output)
483  break;
484  }
485 
486  if (!found_output) {
488  "Output name '%s' not found in ONNX model\n",
489  task->output_names[0]);
490  return AVERROR(EINVAL);
491  }
492 
493  onnx_model->output_resolved = 1;
494  }
495 
496  input_names[0] = task->input_name;
497  output_names[0] = task->output_names[0];
498 
499  status = g_ort->Run(onnx_model->session, NULL,
500  input_names, (const OrtValue *const *)&infer_request->input_tensor, 1,
501  output_names, 1, &infer_request->output_tensor);
502 
503  if (status != NULL) {
504  const char *msg = g_ort->GetErrorMessage(status);
505  av_log(ctx, AV_LOG_ERROR, "ONNX inference failed: %s\n", msg);
506  g_ort->ReleaseStatus(status);
507  return DNN_GENERIC_ERROR;
508  }
509 
510  return 0;
511 }
512 
513 static void infer_completion_callback(void *args)
514 {
515  ONNXRequestItem *request = (ONNXRequestItem *)args;
516  LastLevelTaskItem *lltask = request->lltask;
517  TaskItem *task = lltask->task;
518  DNNData outputs = { 0 };
519  ONNXInferRequest *infer_request = request->infer_request;
520  ONNXModel *onnx_model = (ONNXModel *)task->model;
521  DnnContext *ctx = onnx_model->ctx;
522  OrtTensorTypeAndShapeInfo *tensor_info;
523  ONNXTensorElementDataType tensor_type;
524  size_t num_dims;
525  int64_t *dims;
526  void *output_data;
527  OrtStatus *status;
528 
529  if (!infer_request->output_tensor) {
530  av_log(ctx, AV_LOG_ERROR, "Output tensor is NULL\n");
531  goto err;
532  }
533 
534  status = g_ort->GetTensorTypeAndShape(infer_request->output_tensor, &tensor_info);
535  if (status != NULL) {
536  av_log(ctx, AV_LOG_ERROR, "Failed to get output tensor info\n");
537  g_ort->ReleaseStatus(status);
538  goto err;
539  }
540 
541  g_ort->GetDimensionsCount(tensor_info, &num_dims);
542  dims = av_malloc(num_dims * sizeof(int64_t));
543  if (!dims) {
544  av_log(ctx, AV_LOG_ERROR, "Failed to allocate memory for dimensions\n");
545  g_ort->ReleaseTensorTypeAndShapeInfo(tensor_info);
546  goto err;
547  }
548  g_ort->GetDimensions(tensor_info, dims, num_dims);
549 
550  /* Output is interpreted as NCHW, matching the input assumption. */
551  outputs.layout = DL_NCHW;
552  outputs.order = DCO_RGB;
553 
554  g_ort->GetTensorElementType(tensor_info, &tensor_type);
555  if (tensor_type == ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT) {
556  outputs.dt = DNN_FLOAT;
557  } else {
558  av_log(ctx, AV_LOG_ERROR, "Unsupported output tensor data type, only float is supported\n");
559  av_free(dims);
560  g_ort->ReleaseTensorTypeAndShapeInfo(tensor_info);
561  goto err;
562  }
563 
564  if (num_dims == 4) {
565  outputs.dims[0] = dims[0];
566  outputs.dims[1] = dims[1];
567  outputs.dims[2] = dims[2];
568  outputs.dims[3] = dims[3];
569  } else {
570  avpriv_report_missing_feature(ctx, "Support for %zu dimensional output", num_dims);
571  av_free(dims);
572  g_ort->ReleaseTensorTypeAndShapeInfo(tensor_info);
573  goto err;
574  }
575 
576  status = g_ort->GetTensorMutableData(infer_request->output_tensor, &output_data);
577  if (status != NULL) {
578  av_log(ctx, AV_LOG_ERROR, "Failed to get tensor data\n");
579  g_ort->ReleaseStatus(status);
580  av_free(dims);
581  g_ort->ReleaseTensorTypeAndShapeInfo(tensor_info);
582  goto err;
583  }
584 
585  outputs.data = output_data;
586 
587  switch (onnx_model->model.func_type) {
588  case DFT_PROCESS_FRAME:
589  if (task->do_ioproc) {
590  outputs.scale = 255;
591  if (onnx_model->model.frame_post_proc != NULL) {
592  onnx_model->model.frame_post_proc(task->out_frame, &outputs, onnx_model->model.filter_ctx);
593  } else {
595  }
596  } else {
599  }
600  break;
601  default:
602  avpriv_report_missing_feature(ctx, "model function type %d", onnx_model->model.func_type);
603  av_free(dims);
604  g_ort->ReleaseTensorTypeAndShapeInfo(tensor_info);
605  goto err;
606  }
607 
608  av_free(dims);
609  g_ort->ReleaseTensorTypeAndShapeInfo(tensor_info);
610  task->inference_done++;
611 
612 err:
613  av_freep(&request->lltask);
614  onnx_free_request(infer_request);
615  if (ff_safe_queue_push_back(onnx_model->request_queue, request) < 0) {
616  destroy_request_item(&request);
617  av_log(ctx, AV_LOG_ERROR, "Unable to push back request_queue.\n");
618  }
619 }
620 
621 static int execute_model_onnx(ONNXRequestItem *request, Queue *lltask_queue)
622 {
623  ONNXModel *onnx_model = NULL;
624  LastLevelTaskItem *lltask;
625  TaskItem *task = NULL;
626  int ret = 0;
627 
628  if (ff_queue_size(lltask_queue) == 0) {
629  destroy_request_item(&request);
630  return 0;
631  }
632 
633  lltask = (LastLevelTaskItem *)ff_queue_peek_front(lltask_queue);
634  if (lltask == NULL) {
635  av_log(NULL, AV_LOG_ERROR, "Failed to get LastLevelTaskItem\n");
636  destroy_request_item(&request);
637  return AVERROR(EINVAL);
638  }
639  task = lltask->task;
640  onnx_model = (ONNXModel *)task->model;
641 
642  ret = fill_model_input_onnx(onnx_model, request);
643  if (ret != 0) {
644  goto err;
645  }
646 
647  if (task->async) {
648  avpriv_report_missing_feature(onnx_model->ctx, "ONNX async inference");
649  ret = AVERROR(ENOSYS);
650  goto err;
651  } else {
652  ret = onnx_start_inference((void *)request);
653  if (ret != 0) {
654  goto err;
655  }
656  infer_completion_callback(request);
657  return (task->inference_done == task->inference_todo) ? 0 : DNN_GENERIC_ERROR;
658  }
659 
660 err:
661  av_freep(&request->lltask);
663  if (ff_safe_queue_push_back(onnx_model->request_queue, request) < 0) {
664  destroy_request_item(&request);
665  }
666  return ret;
667 }
668 
669 static int get_output_onnx(DNNModel *model, const char *input_name, int input_width, int input_height,
670  const char *output_name, int *output_width, int *output_height)
671 {
672  int ret = 0;
673  ONNXModel *onnx_model = (ONNXModel *)model;
674  DnnContext *ctx = onnx_model->ctx;
675  TaskItem task = { 0 };
676  ONNXRequestItem *request = NULL;
677  DNNExecBaseParams exec_params = {
678  .input_name = input_name,
679  .output_names = &output_name,
680  .nb_output = 1,
681  .in_frame = NULL,
682  .out_frame = NULL,
683  };
684 
685  ret = ff_dnn_fill_gettingoutput_task(&task, &exec_params, onnx_model, input_height, input_width, ctx);
686  if (ret != 0) {
687  goto err;
688  }
689 
690  ret = extract_lltask_from_task(&task, onnx_model->lltask_queue);
691  if (ret != 0) {
692  av_log(ctx, AV_LOG_ERROR, "Unable to extract last level task from task.\n");
693  goto err;
694  }
695 
696  request = (ONNXRequestItem *)ff_safe_queue_pop_front(onnx_model->request_queue);
697  if (!request) {
698  av_log(ctx, AV_LOG_ERROR, "Unable to get infer request.\n");
699  ret = AVERROR(EINVAL);
700  goto err;
701  }
702 
703  ret = execute_model_onnx(request, onnx_model->lltask_queue);
704  *output_width = task.out_frame->width;
705  *output_height = task.out_frame->height;
706 
707 err:
708  av_frame_free(&task.out_frame);
709  av_frame_free(&task.in_frame);
710  return ret;
711 }
712 
714 {
715  ONNXInferRequest *request = av_malloc(sizeof(ONNXInferRequest));
716  if (!request)
717  return NULL;
718  request->input_tensor = NULL;
719  request->output_tensor = NULL;
720  request->input_data = NULL;
721  return request;
722 }
723 
725 {
726  DNNModel *model = NULL;
727  ONNXModel *onnx_model = NULL;
728  ONNXRequestItem *item = NULL;
729  ONNXOptions *options = &ctx->onnx_option;
730  OrtStatus *status;
731 
733  if (!g_ort) {
734  av_log(ctx, AV_LOG_ERROR, "Failed to get ONNX Runtime API\n");
735  return NULL;
736  }
737 
738  onnx_model = av_mallocz(sizeof(ONNXModel));
739  if (!onnx_model)
740  return NULL;
741 
742  model = &onnx_model->model;
743  onnx_model->ctx = ctx;
744 
745  status = g_ort->CreateEnv(ORT_LOGGING_LEVEL_WARNING, "FFmpeg", &onnx_model->env);
746  if (status != NULL) {
747  av_log(ctx, AV_LOG_ERROR, "Failed to create ONNX Runtime environment\n");
748  goto fail;
749  }
750 
751  status = g_ort->CreateSessionOptions(&onnx_model->session_options);
752  if (status != NULL) {
753  av_log(ctx, AV_LOG_ERROR, "Failed to create session options\n");
754  goto fail;
755  }
756 
757  if (options->num_threads > 0 &&
758  (!ctx->device || av_strcasecmp(ctx->device, "cpu") == 0)) {
759  g_ort->SetIntraOpNumThreads(onnx_model->session_options, options->num_threads);
760  }
761  g_ort->SetSessionGraphOptimizationLevel(onnx_model->session_options, ORT_ENABLE_ALL);
762 
763  if (ctx->device && av_strcasecmp(ctx->device, "cpu") != 0) {
764  if (av_strcasecmp(ctx->device, "cuda") == 0) {
765  if (g_ort->SessionOptionsAppendExecutionProvider_CUDA) {
766  OrtCUDAProviderOptions cuda_options;
767  memset(&cuda_options, 0, sizeof(cuda_options));
768  cuda_options.device_id = ctx->device_id;
769 
770  status = g_ort->SessionOptionsAppendExecutionProvider_CUDA(
771  onnx_model->session_options, &cuda_options);
772  if (status != NULL) {
773  const char *msg = g_ort->GetErrorMessage(status);
774  av_log(ctx, AV_LOG_WARNING, "Failed to enable CUDA (device %d): %s. Falling back to CPU\n",
775  ctx->device_id, msg);
776  g_ort->ReleaseStatus(status);
777  } else {
778  av_log(ctx, AV_LOG_INFO, "Using CUDA execution provider on device %d\n", ctx->device_id);
779  }
780  } else {
781  av_log(ctx, AV_LOG_WARNING, "CUDA provider function not available in this ONNX Runtime API version. Falling back to CPU\n");
782  }
783  } else if (av_strcasecmp(ctx->device, "dml") == 0) {
784 #ifdef _WIN32
785  const char* dml_options_keys[] = {"device_id"};
786  const char* dml_options_values[] = {NULL};
787  char device_id_str[32];
788  snprintf(device_id_str, sizeof(device_id_str), "%d", ctx->device_id);
789  dml_options_values[0] = device_id_str;
790 
791  /* DirectML cannot use ORT's memory-pattern optimizer and only
792  * supports sequential execution. */
793  status = g_ort->SetSessionExecutionMode(onnx_model->session_options, ORT_SEQUENTIAL);
794  if (status)
795  g_ort->ReleaseStatus(status);
796  status = g_ort->DisableMemPattern(onnx_model->session_options);
797  if (status)
798  g_ort->ReleaseStatus(status);
799 
800  if (g_ort->SessionOptionsAppendExecutionProvider) {
801  status = g_ort->SessionOptionsAppendExecutionProvider(
802  onnx_model->session_options, "DML",
803  dml_options_keys, dml_options_values, 1);
804  if (status != NULL) {
805  const char *msg = g_ort->GetErrorMessage(status);
806  av_log(ctx, AV_LOG_WARNING, "Failed to enable DirectML (device %d): %s. Falling back to CPU\n",
807  ctx->device_id, msg);
808  g_ort->ReleaseStatus(status);
809  } else {
810  av_log(ctx, AV_LOG_INFO, "Using DirectML execution provider on device %d\n", ctx->device_id);
811  }
812  } else {
813  av_log(ctx, AV_LOG_WARNING, "DirectML provider function not available in this ONNX Runtime API version. Falling back to CPU\n");
814  }
815 #else
816  av_log(ctx, AV_LOG_WARNING, "DirectML is only available on Windows. Falling back to CPU\n");
817 #endif
818  } else if (av_strcasecmp(ctx->device, "vitisai") == 0) {
819  if (g_ort->SessionOptionsAppendExecutionProvider) {
820  status = g_ort->SessionOptionsAppendExecutionProvider(
821  onnx_model->session_options, "VitisAI",
822  NULL, NULL, 0);
823  if (status != NULL) {
824  const char *msg = g_ort->GetErrorMessage(status);
826  "Failed to enable VitisAI EP: %s. Falling back to CPU\n", msg);
827  g_ort->ReleaseStatus(status);
828  } else {
829  av_log(ctx, AV_LOG_INFO, "Using VitisAI execution provider (AMD Ryzen AI NPU)\n");
830  }
831  } else {
833  "VitisAI provider function not available in this ONNX Runtime API version. Falling back to CPU.\n");
834  }
835  } else {
836 #ifdef _WIN32
838  "Unknown device '%s'. Supported: cpu, cuda, dml, vitisai. Using CPU\n",
839  ctx->device);
840 #else
842  "Unknown device '%s'. Supported: cpu, cuda, vitisai. Using CPU\n",
843  ctx->device);
844 #endif
845  }
846  } else {
847  av_log(ctx, AV_LOG_INFO, "Using CPU execution provider\n");
848  }
849 
850 #ifdef _WIN32
851  {
852  wchar_t *wfilename = NULL;
853  if (utf8towchar(ctx->model_filename, &wfilename)) {
854  av_log(ctx, AV_LOG_ERROR, "Failed to convert model filename to UTF-16\n");
855  goto fail;
856  }
857  if (!wfilename) {
858  av_log(ctx, AV_LOG_ERROR, "Failed to convert model filename to UTF-16\n");
859  goto fail;
860  }
861 
862  status = g_ort->CreateSession(onnx_model->env, wfilename,
863  onnx_model->session_options, &onnx_model->session);
864  av_free(wfilename);
865  }
866 #else
867  status = g_ort->CreateSession(onnx_model->env, ctx->model_filename,
868  onnx_model->session_options, &onnx_model->session);
869 #endif
870  if (status != NULL) {
871  const char *msg = g_ort->GetErrorMessage(status);
872  av_log(ctx, AV_LOG_ERROR, "Failed to create ONNX session: %s\n", msg);
873  g_ort->ReleaseStatus(status);
874  goto fail;
875  }
876 
877  status = g_ort->GetAllocatorWithDefaultOptions(&onnx_model->allocator);
878  if (status != NULL) {
879  av_log(ctx, AV_LOG_ERROR, "Failed to get allocator\n");
880  goto fail;
881  }
882 
883  /*
884  * The ONNX backend binds exactly one input tensor to Run(), so only
885  * single-input models are supported.
886  */
887  {
888  size_t input_count = 0;
889  status = g_ort->SessionGetInputCount(onnx_model->session, &input_count);
890  if (status != NULL) {
891  const char *msg = g_ort->GetErrorMessage(status);
892  av_log(ctx, AV_LOG_ERROR, "Failed to get model input count: %s\n", msg);
893  g_ort->ReleaseStatus(status);
894  goto fail;
895  }
896  if (input_count == 0) {
897  av_log(ctx, AV_LOG_ERROR, "ONNX model exposes no input tensors\n");
898  goto fail;
899  }
900  if (input_count > 1) {
902  "ONNX model exposes %zu input tensors; the ONNX backend "
903  "supports single-input models only.\n",
904  input_count);
905  goto fail;
906  }
907  }
908 
909  /* Auto-detect the input tensor name when the user did not pass input=NAME. */
910  if (!ctx->model_inputname || !*ctx->model_inputname) {
911  char *name = NULL;
912  status = g_ort->SessionGetInputName(onnx_model->session, 0,
913  onnx_model->allocator, &name);
914  if (status != NULL) {
915  const char *msg = g_ort->GetErrorMessage(status);
916  av_log(ctx, AV_LOG_ERROR, "Failed to get model input name: %s\n", msg);
917  g_ort->ReleaseStatus(status);
918  goto fail;
919  }
920  av_freep(&ctx->model_inputname);
921  ctx->model_inputname = av_strdup(name);
922  onnx_model->allocator->Free(onnx_model->allocator, name);
923  if (!ctx->model_inputname)
924  goto fail;
925  av_log(ctx, AV_LOG_INFO, "Auto-detected ONNX input tensor '%s'\n",
926  ctx->model_inputname);
927  }
928 
929  /* Auto-detect the output tensor name when the user did not pass output=NAME. */
930  if (!ctx->model_outputnames) {
931  size_t output_count = 0;
932  char *name = NULL;
933  status = g_ort->SessionGetOutputCount(onnx_model->session, &output_count);
934  if (status != NULL) {
935  const char *msg = g_ort->GetErrorMessage(status);
936  av_log(ctx, AV_LOG_ERROR, "Failed to get model output count: %s\n", msg);
937  g_ort->ReleaseStatus(status);
938  goto fail;
939  }
940  if (output_count == 0) {
941  av_log(ctx, AV_LOG_ERROR, "ONNX model exposes no output tensors\n");
942  goto fail;
943  }
944  status = g_ort->SessionGetOutputName(onnx_model->session, 0,
945  onnx_model->allocator, &name);
946  if (status != NULL) {
947  const char *msg = g_ort->GetErrorMessage(status);
948  av_log(ctx, AV_LOG_ERROR, "Failed to get model output name: %s\n", msg);
949  g_ort->ReleaseStatus(status);
950  goto fail;
951  }
952  ctx->model_outputnames = av_calloc(1, sizeof(*ctx->model_outputnames));
953  if (!ctx->model_outputnames) {
954  onnx_model->allocator->Free(onnx_model->allocator, name);
955  goto fail;
956  }
957  ctx->model_outputnames[0] = av_strdup(name);
958  onnx_model->allocator->Free(onnx_model->allocator, name);
959  if (!ctx->model_outputnames[0]) {
960  av_freep(&ctx->model_outputnames);
961  goto fail;
962  }
963  ctx->nb_outputs = 1;
964  if (output_count == 1) {
965  av_log(ctx, AV_LOG_INFO, "Auto-detected ONNX output tensor '%s'\n",
966  ctx->model_outputnames[0]);
967  } else {
969  "ONNX model exposes %zu output tensors; auto-using index 0 ('%s'). "
970  "Specify output=NAME to choose a different one.\n",
971  output_count, ctx->model_outputnames[0]);
972  }
973  }
974 
975  onnx_model->request_queue = ff_safe_queue_create();
976  if (!onnx_model->request_queue) {
977  goto fail;
978  }
979 
980  item = av_mallocz(sizeof(ONNXRequestItem));
981  if (!item) {
982  goto fail;
983  }
984  item->lltask = NULL;
986  if (!item->infer_request) {
987  av_log(ctx, AV_LOG_ERROR, "Failed to allocate memory for ONNX inference request\n");
988  goto fail;
989  }
992  item->exec_module.args = item;
993 
994  if (ff_safe_queue_push_back(onnx_model->request_queue, item) < 0) {
995  goto fail;
996  }
997  item = NULL;
998 
999  onnx_model->task_queue = ff_queue_create();
1000  if (!onnx_model->task_queue) {
1001  goto fail;
1002  }
1003 
1004  onnx_model->lltask_queue = ff_queue_create();
1005  if (!onnx_model->lltask_queue) {
1006  goto fail;
1007  }
1008 
1009  model->get_input = &get_input_onnx;
1010  model->get_output = &get_output_onnx;
1011  model->filter_ctx = filter_ctx;
1012  model->func_type = func_type;
1013 
1014  return model;
1015 
1016 fail:
1017  if (item) {
1018  destroy_request_item(&item);
1019  }
1020  dnn_free_model_onnx(&model);
1021  return NULL;
1022 }
1023 
1024 static int dnn_execute_model_onnx(const DNNModel *model, DNNExecBaseParams *exec_params)
1025 {
1026  ONNXModel *onnx_model = (ONNXModel *)model;
1027  DnnContext *ctx = onnx_model->ctx;
1028  TaskItem *task;
1029  ONNXRequestItem *request;
1030  int ret = 0;
1031 
1032  ret = ff_check_exec_params(ctx, DNN_ONNX, model->func_type, exec_params);
1033  if (ret != 0) {
1034  av_log(ctx, AV_LOG_ERROR, "Exec parameter checking failed.\n");
1035  return ret;
1036  }
1037 
1038  task = av_malloc(sizeof(TaskItem));
1039  if (!task) {
1040  av_log(ctx, AV_LOG_ERROR, "Unable to alloc memory for task item.\n");
1041  return AVERROR(ENOMEM);
1042  }
1043 
1044  ret = ff_dnn_fill_task(task, exec_params, onnx_model, 0, 1);
1045  if (ret != 0) {
1046  av_freep(&task);
1047  av_log(ctx, AV_LOG_ERROR, "Unable to fill task.\n");
1048  return ret;
1049  }
1050 
1051  ret = ff_queue_push_back(onnx_model->task_queue, task);
1052  if (ret < 0) {
1053  av_freep(&task);
1054  av_log(ctx, AV_LOG_ERROR, "Unable to push back task_queue.\n");
1055  return ret;
1056  }
1057 
1058  ret = extract_lltask_from_task(task, onnx_model->lltask_queue);
1059  if (ret != 0) {
1060  av_log(ctx, AV_LOG_ERROR, "Unable to extract last level task from task.\n");
1061  return ret;
1062  }
1063 
1064  request = (ONNXRequestItem *)ff_safe_queue_pop_front(onnx_model->request_queue);
1065  if (!request) {
1066  av_log(ctx, AV_LOG_ERROR, "Unable to get infer request.\n");
1067  return AVERROR(EINVAL);
1068  }
1069 
1070  return execute_model_onnx(request, onnx_model->lltask_queue);
1071 }
1072 
1074 {
1075  ONNXModel *onnx_model = (ONNXModel *)model;
1076  return ff_dnn_get_result_common(onnx_model->task_queue, in, out);
1077 }
1078 
1079 static int dnn_flush_onnx(const DNNModel *model)
1080 {
1081  ONNXModel *onnx_model = (ONNXModel *)model;
1082  ONNXRequestItem *request;
1083 
1084  if (ff_queue_size(onnx_model->lltask_queue) == 0)
1085  return 0;
1086 
1087  request = (ONNXRequestItem *)ff_safe_queue_pop_front(onnx_model->request_queue);
1088  if (!request) {
1089  av_log(onnx_model->ctx, AV_LOG_ERROR, "Unable to get infer request.\n");
1090  return AVERROR(EINVAL);
1091  }
1092 
1093  return execute_model_onnx(request, onnx_model->lltask_queue);
1094 }
1095 
1097  .clazz = DNN_DEFINE_CLASS(dnn_onnx),
1098  .type = DNN_ONNX,
1099  .load_model = dnn_load_model_onnx,
1100  .execute_model = dnn_execute_model_onnx,
1101  .get_result = dnn_get_result_onnx,
1102  .flush = dnn_flush_onnx,
1103  .free_model = dnn_free_model_onnx,
1104 };
wchar_filename.h
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:216
name
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default minimum maximum flags name is the option name
Definition: writing_filters.txt:88
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
opt.h
ff_safe_queue_pop_front
void * ff_safe_queue_pop_front(SafeQueue *sq)
Remove and free first element from the queue in SafeQueue.
Definition: safe_queue.c:105
FLAGS
#define FLAGS
Definition: dnn_backend_onnx.c:70
out
static FILE * out
Definition: movenc.c:55
dnn_free_model_onnx
static void dnn_free_model_onnx(DNNModel **model)
Definition: dnn_backend_onnx.c:147
thread.h
DNNAsyncExecModule
Common Async Execution Mechanism for the DNN Backends.
Definition: dnn_backend_common.h:65
DNNFunctionType
DNNFunctionType
Definition: dnn_interface.h:57
int64_t
long long int64_t
Definition: coverity.c:34
ff_queue_pop_front
void * ff_queue_pop_front(Queue *q)
Remove and free first element from the Queue.
Definition: queue.c:151
g_ort_init_once
static AVOnce g_ort_init_once
Definition: dnn_backend_onnx.c:80
av_strcasecmp
int av_strcasecmp(const char *a, const char *b)
Locale-independent case-insensitive compare.
Definition: avstring.c:208
ff_check_exec_params
int ff_check_exec_params(void *ctx, DNNBackendType backend, DNNFunctionType func_type, DNNExecBaseParams *exec_params)
Definition: dnn_backend_common.c:30
ff_queue_size
size_t ff_queue_size(Queue *q)
Return the length of the Queue.
Definition: queue.c:88
DNN_GENERIC_ERROR
#define DNN_GENERIC_ERROR
Definition: dnn_interface.h:33
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:64
LastLevelTaskItem
Definition: dnn_backend_common.h:57
onnx_start_inference
static int onnx_start_inference(void *args)
Definition: dnn_backend_onnx.c:419
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:466
fill_model_input_onnx
static int fill_model_input_onnx(ONNXModel *onnx_model, ONNXRequestItem *request)
Definition: dnn_backend_onnx.c:322
AVFrame::width
int width
Definition: frame.h:538
ONNXModel::env
OrtEnv * env
Definition: dnn_backend_onnx.c:45
SafeQueue
Double-ended queue with mutex locks ensuring data consistency while multithreading.
Definition: safe_queue.c:46
AVOption
AVOption.
Definition: opt.h:429
DNNModel::frame_pre_proc
FramePrePostProc frame_pre_proc
Definition: dnn_interface.h:111
ONNXModel::ctx
DnnContext * ctx
Definition: dnn_backend_onnx.c:44
output_data
static int output_data(MLPDecodeContext *m, unsigned int substr, AVFrame *frame, int *got_frame_ptr)
Write the audio data into the output buffer.
Definition: mlpdec.c:1107
DNNExecBaseParams::input_name
const char * input_name
Definition: dnn_interface.h:82
destroy_request_item
static void destroy_request_item(ONNXRequestItem **arg)
Definition: dnn_backend_onnx.c:134
dnn_io_proc.h
TaskItem
Definition: dnn_backend_common.h:43
DNNAsyncExecModule::callback
void(* callback)(void *args)
Completion Callback for the backend.
Definition: dnn_backend_common.h:77
AVFILTER_DEFINE_CLASS
AVFILTER_DEFINE_CLASS(dnn_onnx)
DNNModel::filter_ctx
AVFilterContext * filter_ctx
Definition: dnn_interface.h:100
ff_queue_create
Queue * ff_queue_create(void)
Create a Queue instance.
Definition: queue.c:47
dnn_flush_onnx
static int dnn_flush_onnx(const DNNModel *model)
Definition: dnn_backend_onnx.c:1079
ONNXModel::session_options
OrtSessionOptions * session_options
Definition: dnn_backend_onnx.c:47
dnn_get_width_idx_by_layout
static int dnn_get_width_idx_by_layout(DNNLayout layout)
Definition: dnn_interface.h:209
TaskItem::model
void * model
Definition: dnn_backend_common.h:44
DnnContext
Definition: dnn_interface.h:151
onnx_free_request
static void onnx_free_request(ONNXInferRequest *request)
Definition: dnn_backend_onnx.c:119
ONNXInferRequest::input_tensor
OrtValue * input_tensor
Definition: dnn_backend_onnx.c:58
filter_ctx
static FilteringContext * filter_ctx
Definition: transcode.c:52
execute_model_onnx
static int execute_model_onnx(ONNXRequestItem *request, Queue *lltask_queue)
Definition: dnn_backend_onnx.c:621
ONNXModel::session
OrtSession * session
Definition: dnn_backend_onnx.c:46
extract_lltask_from_task
static int extract_lltask_from_task(TaskItem *task, Queue *lltask_queue)
Definition: dnn_backend_onnx.c:98
Queue
Linear double-ended data structure.
Definition: executor.c:51
ONNXModel::model
DNNModel model
Definition: dnn_backend_onnx.c:43
ff_queue_push_back
int ff_queue_push_back(Queue *q, void *v)
Add data to the tail of the queue.
Definition: queue.c:130
avassert.h
ff_thread_once
static int ff_thread_once(char *control, void(*routine)(void))
Definition: thread.h:205
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:210
ONNXModel::task_queue
Queue * task_queue
Definition: dnn_backend_onnx.c:50
infer_completion_callback
static void infer_completion_callback(void *args)
Definition: dnn_backend_onnx.c:513
float
float
Definition: af_crystalizer.c:122
LastLevelTaskItem::task
TaskItem * task
Definition: dnn_backend_common.h:58
ff_dnn_backend_onnx
const DNNModule ff_dnn_backend_onnx
Definition: dnn_backend_onnx.c:1096
dnn_execute_model_onnx
static int dnn_execute_model_onnx(const DNNModel *model, DNNExecBaseParams *exec_params)
Definition: dnn_backend_onnx.c:1024
ff_queue_destroy
void ff_queue_destroy(Queue *q)
Destroy the Queue instance.
Definition: queue.c:72
DNNData
Definition: dnn_interface.h:70
DNNModule::clazz
const AVClass clazz
Definition: dnn_interface.h:188
ff_dnn_fill_gettingoutput_task
int ff_dnn_fill_gettingoutput_task(TaskItem *task, DNNExecBaseParams *exec_params, void *backend_model, int input_height, int input_width, void *ctx)
Allocate input and output frames and fill the Task with execution parameters.
Definition: dnn_backend_common.c:156
DNNModel::get_output
int(* get_output)(struct DNNModel *model, const char *input_name, int input_width, int input_height, const char *output_name, int *output_width, int *output_height)
Definition: dnn_interface.h:107
ctx
static AVFormatContext * ctx
Definition: movenc.c:49
ONNXModel::output_resolved
int output_resolved
Definition: dnn_backend_onnx.c:54
g_ort
static const OrtApi * g_ort
Definition: dnn_backend_onnx.c:79
TaskItem::inference_todo
uint32_t inference_todo
Definition: dnn_backend_common.h:52
DL_NCHW
@ DL_NCHW
Definition: dnn_interface.h:66
av_mallocz
#define av_mallocz(s)
Definition: tableprint_vlc.h:31
ONNXRequestItem::exec_module
DNNAsyncExecModule exec_module
Definition: dnn_backend_onnx.c:66
arg
const char * arg
Definition: jacosubdec.c:65
if
if(ret)
Definition: filter_design.txt:179
ff_safe_queue_size
size_t ff_safe_queue_size(SafeQueue *sq)
Return the length of the SafeQueue.
Definition: safe_queue.c:80
ff_proc_from_frame_to_dnn
int ff_proc_from_frame_to_dnn(AVFrame *frame, DNNData *input, void *log_ctx)
Definition: dnn_io_proc.c:182
fail
#define fail
Definition: test.h:478
AV_ONCE_INIT
#define AV_ONCE_INIT
Definition: thread.h:203
ff_frame_to_dnn_detect
int ff_frame_to_dnn_detect(AVFrame *frame, DNNData *input, void *log_ctx)
Definition: dnn_io_proc.c:423
NULL
#define NULL
Definition: coverity.c:32
ONNXModel::input_info
DNNData input_info
Definition: dnn_backend_onnx.c:52
ff_safe_queue_create
SafeQueue * ff_safe_queue_create(void)
Create and initialize a SafeQueue instance.
Definition: safe_queue.c:52
get_input_onnx
static int get_input_onnx(DNNModel *model, DNNData *input, const char *input_name)
Definition: dnn_backend_onnx.c:186
DNNModel::frame_post_proc
FramePrePostProc frame_post_proc
Definition: dnn_interface.h:114
ff_dnn_async_module_cleanup
int ff_dnn_async_module_cleanup(DNNAsyncExecModule *async_module)
Join the Async Execution thread and set module pointers to NULL.
Definition: dnn_backend_common.c:86
options
Definition: swscale.c:50
dnn_load_model_onnx
static DNNModel * dnn_load_model_onnx(DnnContext *ctx, DNNFunctionType func_type, AVFilterContext *filter_ctx)
Definition: dnn_backend_onnx.c:724
TaskItem::in_frame
AVFrame * in_frame
Definition: dnn_backend_common.h:45
ONNXInferRequest
Definition: dnn_backend_onnx.c:57
AVOnce
#define AVOnce
Definition: thread.h:202
ONNXRequestItem::infer_request
ONNXInferRequest * infer_request
Definition: dnn_backend_onnx.c:64
dnn_onnx_options
static const AVOption dnn_onnx_options[]
Definition: dnn_backend_onnx.c:71
TaskItem::async
uint8_t async
Definition: dnn_backend_common.h:49
TaskItem::inference_done
uint32_t inference_done
Definition: dnn_backend_common.h:53
i
#define i(width, name, range_min, range_max)
Definition: cbs_h264.c:63
queue.h
ONNXInferRequest::output_tensor
OrtValue * output_tensor
Definition: dnn_backend_onnx.c:59
DNNModel::func_type
DNNFunctionType func_type
Definition: dnn_interface.h:102
avpriv_report_missing_feature
void avpriv_report_missing_feature(void *avc, const char *msg,...) av_printf_format(2
Log a generic warning message about a missing feature.
ff_safe_queue_destroy
void ff_safe_queue_destroy(SafeQueue *sq)
Destroy the SafeQueue instance.
Definition: safe_queue.c:69
DNN_ONNX
@ DNN_ONNX
Definition: dnn_interface.h:39
ONNXModel
Definition: dnn_backend_onnx.c:42
DNN_FLOAT
@ DNN_FLOAT
Definition: dnn_interface.h:42
ff_dnn_fill_task
int ff_dnn_fill_task(TaskItem *task, DNNExecBaseParams *exec_params, void *backend_model, int async, int do_ioproc)
Fill the Task for Backend Execution.
Definition: dnn_backend_common.c:50
input
and forward the test the status of outputs and forward it to the corresponding return FFERROR_NOT_READY If the filters stores internally one or a few frame for some input
Definition: filter_design.txt:172
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:221
DNN_DEFINE_CLASS
#define DNN_DEFINE_CLASS(fname)
Definition: dnn_backend_common.h:39
ff_safe_queue_push_back
int ff_safe_queue_push_back(SafeQueue *sq, void *v)
Add data to the tail of queue in the SafeQueue after locking mutex.
Definition: safe_queue.c:95
av_malloc
#define av_malloc(s)
Definition: ops_asmgen.c:44
DFT_ANALYTICS_DETECT
@ DFT_ANALYTICS_DETECT
Definition: dnn_interface.h:60
get_output_onnx
static int get_output_onnx(DNNModel *model, const char *input_name, int input_width, int input_height, const char *output_name, int *output_width, int *output_height)
Definition: dnn_backend_onnx.c:669
DNNAsyncExecModule::start_inference
int(* start_inference)(void *request)
Synchronous inference function for the backend with corresponding request item as the argument.
Definition: dnn_backend_common.h:70
OFFSET
#define OFFSET(x)
Definition: dnn_backend_onnx.c:69
DNNAsyncExecModule::args
void * args
Argument for the execution functions.
Definition: dnn_backend_common.h:83
safe_queue.h
TaskItem::output_names
const char ** output_names
Definition: dnn_backend_common.h:48
onnx_create_inference_request
static ONNXInferRequest * onnx_create_inference_request(void)
Definition: dnn_backend_onnx.c:713
av_calloc
void * av_calloc(size_t nmemb, size_t size)
Definition: mem.c:264
outputs
static const AVFilterPad outputs[]
Definition: af_aap.c:310
ONNXModel::request_queue
SafeQueue * request_queue
Definition: dnn_backend_onnx.c:49
ret
ret
Definition: filter_design.txt:187
ONNXRequestItem::lltask
LastLevelTaskItem * lltask
Definition: dnn_backend_onnx.c:65
TaskItem::out_frame
AVFrame * out_frame
Definition: dnn_backend_common.h:46
AVFrame::height
int height
Definition: frame.h:538
status
ov_status_e status
Definition: dnn_backend_openvino.c:100
dnn_backend_common.h
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition: opt.h:259
ff_dnn_get_result_common
DNNAsyncStatusType ff_dnn_get_result_common(Queue *task_queue, AVFrame **in, AVFrame **out)
Extract input and output frame from the Task Queue after asynchronous inference.
Definition: dnn_backend_common.c:136
ff_queue_peek_front
void * ff_queue_peek_front(Queue *q)
Return a pointer to the data at the head of the queue.
Definition: queue.c:93
DCO_RGB
@ DCO_RGB
Definition: dnn_interface.h:47
ONNXInferRequest::input_data
void * input_data
Definition: dnn_backend_onnx.c:60
AVFilterContext
An instance of a filter.
Definition: avfilter.h:274
init_ort_api
static void init_ort_api(void)
Definition: dnn_backend_onnx.c:82
DNNModel
Definition: dnn_interface.h:98
mem.h
av_strdup
#define av_strdup(s)
Definition: ops_asmgen.c:47
dnn_get_height_idx_by_layout
static int dnn_get_height_idx_by_layout(DNNLayout layout)
Definition: dnn_interface.h:214
TaskItem::input_name
const char * input_name
Definition: dnn_backend_common.h:47
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34
dnn_get_channel_idx_by_layout
static int dnn_get_channel_idx_by_layout(DNNLayout layout)
Definition: dnn_interface.h:219
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
DNNExecBaseParams
Definition: dnn_interface.h:81
DNNModel::get_input
int(* get_input)(struct DNNModel *model, DNNData *input, const char *input_name)
Definition: dnn_interface.h:105
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
ONNXModel::input_resolved
int input_resolved
Definition: dnn_backend_onnx.c:53
ONNXModel::lltask_queue
Queue * lltask_queue
Definition: dnn_backend_onnx.c:51
ONNXRequestItem
Definition: dnn_backend_onnx.c:63
TaskItem::do_ioproc
uint8_t do_ioproc
Definition: dnn_backend_common.h:50
avstring.h
DNNAsyncStatusType
DNNAsyncStatusType
Definition: dnn_interface.h:50
snprintf
#define snprintf
Definition: snprintf.h:34
dnn_get_result_onnx
static DNNAsyncStatusType dnn_get_result_onnx(const DNNModel *model, AVFrame **in, AVFrame **out)
Definition: dnn_backend_onnx.c:1073
ONNXModel::allocator
OrtAllocator * allocator
Definition: dnn_backend_onnx.c:48
DFT_PROCESS_FRAME
@ DFT_PROCESS_FRAME
Definition: dnn_interface.h:59
TaskItem::nb_output
uint32_t nb_output
Definition: dnn_backend_common.h:51
DNNModule
Definition: dnn_interface.h:187
ff_proc_from_dnn_to_frame
int ff_proc_from_dnn_to_frame(AVFrame *frame, DNNData *output, void *log_ctx)
Definition: dnn_io_proc.c:42