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  ff_dnn_wait_requests(onnx_model->request_queue, onnx_model->ctx->nireq);
156  while (ff_safe_queue_size(onnx_model->request_queue) != 0) {
158  destroy_request_item(&item);
159  }
161 
162  while (ff_queue_size(onnx_model->lltask_queue) != 0) {
164  av_freep(&item);
165  }
166  ff_queue_destroy(onnx_model->lltask_queue);
167 
168  while (ff_queue_size(onnx_model->task_queue) != 0) {
169  TaskItem *item = (TaskItem *)ff_queue_pop_front(onnx_model->task_queue);
170  av_frame_free(&item->in_frame);
171  av_frame_free(&item->out_frame);
172  av_freep(&item);
173  }
174  ff_queue_destroy(onnx_model->task_queue);
175 
176  if (onnx_model->session)
177  g_ort->ReleaseSession(onnx_model->session);
178  if (onnx_model->session_options)
179  g_ort->ReleaseSessionOptions(onnx_model->session_options);
180  if (onnx_model->env)
181  g_ort->ReleaseEnv(onnx_model->env);
182 
183  av_freep(&onnx_model);
184  *model = NULL;
185 }
186 
187 static int get_input_onnx(DNNModel *model, DNNData *input, const char *input_name)
188 {
189  ONNXModel *onnx_model = (ONNXModel *)model;
190  DnnContext *ctx = onnx_model->ctx;
191  OrtTypeInfo *type_info = NULL;
192  const OrtTensorTypeAndShapeInfo *tensor_info = NULL;
193  size_t num_dims;
194  size_t input_count = 0;
195  size_t input_index = 0;
196  int found_input = 0;
197  int64_t *dims;
198  ONNXTensorElementDataType tensor_type;
199  OrtStatus *status;
200 
201  if (!input_name || !*input_name) {
202  av_log(ctx, AV_LOG_ERROR, "ONNX input name is not specified\n");
203  return AVERROR(EINVAL);
204  }
205 
206  if (onnx_model->input_resolved) {
207  *input = onnx_model->input_info;
208  return 0;
209  }
210 
211  status = g_ort->SessionGetInputCount(onnx_model->session, &input_count);
212  if (status != NULL) {
213  const char *msg = g_ort->GetErrorMessage(status);
214  av_log(ctx, AV_LOG_ERROR, "Failed to get input count: %s\n", msg);
215  g_ort->ReleaseStatus(status);
216  return AVERROR(EINVAL);
217  }
218 
219  for (size_t i = 0; i < input_count; i++) {
220  char *name = NULL;
221  status = g_ort->SessionGetInputName(onnx_model->session, i,
222  onnx_model->allocator, &name);
223  if (status != NULL) {
224  g_ort->ReleaseStatus(status);
225  continue;
226  }
227  if (!strcmp(name, input_name)) {
228  input_index = i;
229  found_input = 1;
230  }
231  onnx_model->allocator->Free(onnx_model->allocator, name);
232  if (found_input)
233  break;
234  }
235 
236  if (!found_input) {
237  av_log(ctx, AV_LOG_ERROR, "Input name '%s' not found in ONNX model\n",
238  input_name);
239  return AVERROR(EINVAL);
240  }
241 
242  status = g_ort->SessionGetInputTypeInfo(onnx_model->session, input_index,
243  &type_info);
244  if (status != NULL) {
245  const char *msg = g_ort->GetErrorMessage(status);
246  av_log(ctx, AV_LOG_ERROR, "Failed to get input type info: %s\n", msg);
247  g_ort->ReleaseStatus(status);
248  return AVERROR(EINVAL);
249  }
250 
251  status = g_ort->CastTypeInfoToTensorInfo(type_info, &tensor_info);
252  if (status != NULL) {
253  g_ort->ReleaseTypeInfo(type_info);
254  g_ort->ReleaseStatus(status);
255  return AVERROR(EINVAL);
256  }
257 
258  status = g_ort->GetDimensionsCount(tensor_info, &num_dims);
259  if (status != NULL) {
260  g_ort->ReleaseTypeInfo(type_info);
261  g_ort->ReleaseStatus(status);
262  return AVERROR(EINVAL);
263  }
264 
265  if (num_dims != 4) {
266  avpriv_report_missing_feature(ctx, "Support for %zu dimensional input", num_dims);
267  g_ort->ReleaseTypeInfo(type_info);
268  return AVERROR(ENOSYS);
269  }
270 
271  dims = av_malloc(num_dims * sizeof(int64_t));
272  if (!dims) {
273  g_ort->ReleaseTypeInfo(type_info);
274  return AVERROR(ENOMEM);
275  }
276 
277  g_ort->GetDimensions(tensor_info, dims, num_dims);
278  g_ort->GetTensorElementType(tensor_info, &tensor_type);
279 
280  if (dims[0] > 1) {
282  "ONNX model has fixed batch size %"PRId64", but the backend "
283  "only supports a batch size of 1\n", dims[0]);
284  av_free(dims);
285  g_ort->ReleaseTypeInfo(type_info);
286  return AVERROR(ENOSYS);
287  }
288 
289  /*
290  * The ONNX backend assumes a 4-D NCHW input tensor (the rank check
291  * above already rejects anything else).
292  */
293  input->layout = DL_NCHW;
294  input->dims[0] = dims[0] > 0 ? dims[0] : 1;
295  input->dims[1] = dims[1] > 0 ? dims[1] : 3;
296  input->dims[2] = dims[2] > 0 ? dims[2] : -1;
297  input->dims[3] = dims[3] > 0 ? dims[3] : -1;
298 
299  if (tensor_type == ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT) {
300  input->dt = DNN_FLOAT;
301  } else {
302  av_log(ctx, AV_LOG_ERROR, "Unsupported input tensor data type, only float is supported\n");
303  av_free(dims);
304  g_ort->ReleaseTypeInfo(type_info);
305  return AVERROR(ENOSYS);
306  }
307 
308  /*
309  * The DCO_RGB setting below is only consulted by the dnn_detect and dnn_classify;
310  * the dnn_processing path lets the source AVFrame pixel format determine the
311  * tensor channel order, so both RGB24 and BGR24 inputs work transparently
312  * for that flow.
313  */
314  input->order = DCO_RGB;
315  av_free(dims);
316  g_ort->ReleaseTypeInfo(type_info);
317 
318  onnx_model->input_info = *input;
319  onnx_model->input_resolved = 1;
320  return 0;
321 }
322 
323 static int fill_model_input_onnx(ONNXModel *onnx_model, ONNXRequestItem *request)
324 {
325  LastLevelTaskItem *lltask = NULL;
326  TaskItem *task = NULL;
327  ONNXInferRequest *infer_request = NULL;
328  DNNData input = { 0 };
329  DnnContext *ctx = onnx_model->ctx;
330  int ret, width_idx, height_idx, channel_idx;
331  int64_t input_shape[4];
332  size_t input_tensor_size;
333  OrtMemoryInfo *memory_info;
334  OrtStatus *status;
335 
336  lltask = (LastLevelTaskItem *)ff_queue_pop_front(onnx_model->lltask_queue);
337  if (!lltask) {
338  ret = AVERROR(EINVAL);
339  goto err;
340  }
341  request->lltask = lltask;
342  task = lltask->task;
343  infer_request = request->infer_request;
344 
345  ret = get_input_onnx(&onnx_model->model, &input, task->input_name);
346  if (ret != 0) {
347  goto err;
348  }
349 
350  width_idx = dnn_get_width_idx_by_layout(input.layout);
351  height_idx = dnn_get_height_idx_by_layout(input.layout);
352  channel_idx = dnn_get_channel_idx_by_layout(input.layout);
353 
354  input.dims[height_idx] = task->in_frame->height;
355  input.dims[width_idx] = task->in_frame->width;
356 
357  input_shape[0] = input.dims[0];
358  input_shape[1] = input.dims[channel_idx];
359  input_shape[2] = input.dims[height_idx];
360  input_shape[3] = input.dims[width_idx];
361 
362  input_tensor_size = input_shape[0] * input_shape[1] * input_shape[2] * input_shape[3];
363  input_tensor_size *= sizeof(float);
364 
365  input.data = av_malloc(input_tensor_size);
366  if (!input.data) {
367  ret = AVERROR(ENOMEM);
368  goto err;
369  }
370  infer_request->input_data = input.data;
371 
372  switch (onnx_model->model.func_type) {
373  case DFT_PROCESS_FRAME:
374  input.scale = 255;
375  if (task->do_ioproc) {
376  if (onnx_model->model.frame_pre_proc != NULL) {
377  onnx_model->model.frame_pre_proc(task->in_frame, &input, onnx_model->model.filter_ctx);
378  } else {
380  }
381  }
382  break;
385  break;
386  default:
387  avpriv_report_missing_feature(ctx, "model function type %d", onnx_model->model.func_type);
388  ret = AVERROR(ENOSYS);
389  goto err;
390  }
391 
392  status = g_ort->CreateCpuMemoryInfo(OrtArenaAllocator, OrtMemTypeDefault, &memory_info);
393  if (status != NULL) {
394  ret = AVERROR(ENOMEM);
395  goto err;
396  }
397 
398  status = g_ort->CreateTensorWithDataAsOrtValue(
399  memory_info, input.data, input_tensor_size,
400  input_shape, 4, ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT,
401  &infer_request->input_tensor);
402 
403  g_ort->ReleaseMemoryInfo(memory_info);
404 
405  if (status != NULL) {
406  const char *msg = g_ort->GetErrorMessage(status);
407  av_log(ctx, AV_LOG_ERROR, "Failed to create input tensor: %s\n", msg);
408  g_ort->ReleaseStatus(status);
409  ret = AVERROR(ENOMEM);
410  goto err;
411  }
412 
413  return 0;
414 
415 err:
416  onnx_free_request(infer_request);
417  return ret;
418 }
419 
420 static int onnx_start_inference(void *args)
421 {
422  ONNXRequestItem *request = (ONNXRequestItem *)args;
423  ONNXInferRequest *infer_request = NULL;
424  LastLevelTaskItem *lltask = NULL;
425  TaskItem *task = NULL;
426  ONNXModel *onnx_model = NULL;
427  DnnContext *ctx = NULL;
428  OrtStatus *status;
429  const char *input_names[1];
430  const char *output_names[1];
431 
432  if (!request) {
433  av_log(NULL, AV_LOG_ERROR, "ONNXRequestItem is NULL\n");
434  return AVERROR(EINVAL);
435  }
436 
437  infer_request = request->infer_request;
438  lltask = request->lltask;
439  task = lltask->task;
440  onnx_model = (ONNXModel *)task->model;
441  ctx = onnx_model->ctx;
442 
443  if (task->nb_output > 1) {
445  "Multiple output tensors (%u) for ONNX backend", task->nb_output);
446  return AVERROR(ENOSYS);
447  }
448 
449  if (!task->input_name || !task->output_names || !task->output_names[0]) {
451  "ONNX backend: input/output tensor name was not resolved at load time\n");
452  return AVERROR(EINVAL);
453  }
454 
455  if (!infer_request->input_tensor) {
456  av_log(ctx, AV_LOG_ERROR, "Input tensor is NULL\n");
457  return DNN_GENERIC_ERROR;
458  }
459 
460  if (!onnx_model->output_resolved) {
461  size_t output_count = 0;
462  int found_output = 0;
463 
464  status = g_ort->SessionGetOutputCount(onnx_model->session, &output_count);
465  if (status != NULL) {
466  const char *msg = g_ort->GetErrorMessage(status);
467  av_log(ctx, AV_LOG_ERROR, "Failed to get output count: %s\n", msg);
468  g_ort->ReleaseStatus(status);
469  return AVERROR(EINVAL);
470  }
471 
472  for (size_t i = 0; i < output_count; i++) {
473  char *name = NULL;
474  status = g_ort->SessionGetOutputName(onnx_model->session, i,
475  onnx_model->allocator, &name);
476  if (status != NULL) {
477  g_ort->ReleaseStatus(status);
478  continue;
479  }
480  if (!strcmp(name, task->output_names[0]))
481  found_output = 1;
482  onnx_model->allocator->Free(onnx_model->allocator, name);
483  if (found_output)
484  break;
485  }
486 
487  if (!found_output) {
489  "Output name '%s' not found in ONNX model\n",
490  task->output_names[0]);
491  return AVERROR(EINVAL);
492  }
493 
494  onnx_model->output_resolved = 1;
495  }
496 
497  input_names[0] = task->input_name;
498  output_names[0] = task->output_names[0];
499 
500  status = g_ort->Run(onnx_model->session, NULL,
501  input_names, (const OrtValue *const *)&infer_request->input_tensor, 1,
502  output_names, 1, &infer_request->output_tensor);
503 
504  if (status != NULL) {
505  const char *msg = g_ort->GetErrorMessage(status);
506  av_log(ctx, AV_LOG_ERROR, "ONNX inference failed: %s\n", msg);
507  g_ort->ReleaseStatus(status);
508  return DNN_GENERIC_ERROR;
509  }
510 
511  return 0;
512 }
513 
514 static void infer_completion_callback(void *args)
515 {
516  ONNXRequestItem *request = (ONNXRequestItem *)args;
517  LastLevelTaskItem *lltask = request->lltask;
518  TaskItem *task = lltask->task;
519  DNNData outputs = { 0 };
520  ONNXInferRequest *infer_request = request->infer_request;
521  ONNXModel *onnx_model = (ONNXModel *)task->model;
522  DnnContext *ctx = onnx_model->ctx;
523  OrtTensorTypeAndShapeInfo *tensor_info;
524  ONNXTensorElementDataType tensor_type;
525  size_t num_dims;
526  int64_t *dims;
527  void *output_data;
528  OrtStatus *status;
529 
530  if (!infer_request->output_tensor) {
531  av_log(ctx, AV_LOG_ERROR, "Output tensor is NULL\n");
532  goto err;
533  }
534 
535  status = g_ort->GetTensorTypeAndShape(infer_request->output_tensor, &tensor_info);
536  if (status != NULL) {
537  av_log(ctx, AV_LOG_ERROR, "Failed to get output tensor info\n");
538  g_ort->ReleaseStatus(status);
539  goto err;
540  }
541 
542  g_ort->GetDimensionsCount(tensor_info, &num_dims);
543  dims = av_malloc(num_dims * sizeof(int64_t));
544  if (!dims) {
545  av_log(ctx, AV_LOG_ERROR, "Failed to allocate memory for dimensions\n");
546  g_ort->ReleaseTensorTypeAndShapeInfo(tensor_info);
547  goto err;
548  }
549  g_ort->GetDimensions(tensor_info, dims, num_dims);
550 
551  /* Output is interpreted as NCHW, matching the input assumption. */
552  outputs.layout = DL_NCHW;
553  outputs.order = DCO_RGB;
554 
555  g_ort->GetTensorElementType(tensor_info, &tensor_type);
556  if (tensor_type == ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT) {
557  outputs.dt = DNN_FLOAT;
558  } else {
559  av_log(ctx, AV_LOG_ERROR, "Unsupported output tensor data type, only float is supported\n");
560  av_free(dims);
561  g_ort->ReleaseTensorTypeAndShapeInfo(tensor_info);
562  goto err;
563  }
564 
565  if (num_dims == 4) {
566  outputs.dims[0] = dims[0];
567  outputs.dims[1] = dims[1];
568  outputs.dims[2] = dims[2];
569  outputs.dims[3] = dims[3];
570  } else {
571  avpriv_report_missing_feature(ctx, "Support for %zu dimensional output", num_dims);
572  av_free(dims);
573  g_ort->ReleaseTensorTypeAndShapeInfo(tensor_info);
574  goto err;
575  }
576 
577  status = g_ort->GetTensorMutableData(infer_request->output_tensor, &output_data);
578  if (status != NULL) {
579  av_log(ctx, AV_LOG_ERROR, "Failed to get tensor data\n");
580  g_ort->ReleaseStatus(status);
581  av_free(dims);
582  g_ort->ReleaseTensorTypeAndShapeInfo(tensor_info);
583  goto err;
584  }
585 
586  outputs.data = output_data;
587 
588  switch (onnx_model->model.func_type) {
589  case DFT_PROCESS_FRAME:
590  if (task->do_ioproc) {
591  outputs.scale = 255;
592  if (onnx_model->model.frame_post_proc != NULL) {
593  onnx_model->model.frame_post_proc(task->out_frame, &outputs, onnx_model->model.filter_ctx);
594  } else {
596  }
597  } else {
600  }
601  break;
602  default:
603  avpriv_report_missing_feature(ctx, "model function type %d", onnx_model->model.func_type);
604  av_free(dims);
605  g_ort->ReleaseTensorTypeAndShapeInfo(tensor_info);
606  goto err;
607  }
608 
609  av_free(dims);
610  g_ort->ReleaseTensorTypeAndShapeInfo(tensor_info);
611  task->inference_done++;
612 
613 err:
614  av_freep(&request->lltask);
615  onnx_free_request(infer_request);
616  if (ff_safe_queue_push_back(onnx_model->request_queue, request) < 0) {
617  destroy_request_item(&request);
618  av_log(ctx, AV_LOG_ERROR, "Unable to push back request_queue.\n");
619  }
620 }
621 
622 static int execute_model_onnx(ONNXRequestItem *request, Queue *lltask_queue)
623 {
624  ONNXModel *onnx_model = NULL;
625  LastLevelTaskItem *lltask;
626  TaskItem *task = NULL;
627  int ret = 0;
628 
629  if (ff_queue_size(lltask_queue) == 0) {
630  destroy_request_item(&request);
631  return 0;
632  }
633 
634  lltask = (LastLevelTaskItem *)ff_queue_peek_front(lltask_queue);
635  if (lltask == NULL) {
636  av_log(NULL, AV_LOG_ERROR, "Failed to get LastLevelTaskItem\n");
637  destroy_request_item(&request);
638  return AVERROR(EINVAL);
639  }
640  task = lltask->task;
641  onnx_model = (ONNXModel *)task->model;
642 
643  ret = fill_model_input_onnx(onnx_model, request);
644  if (ret != 0) {
645  goto err;
646  }
647 
648  if (task->async) {
649  avpriv_report_missing_feature(onnx_model->ctx, "ONNX async inference");
650  ret = AVERROR(ENOSYS);
651  goto err;
652  } else {
653  ret = onnx_start_inference((void *)request);
654  if (ret != 0) {
655  goto err;
656  }
657  infer_completion_callback(request);
658  return (task->inference_done == task->inference_todo) ? 0 : DNN_GENERIC_ERROR;
659  }
660 
661 err:
662  av_freep(&request->lltask);
664  if (ff_safe_queue_push_back(onnx_model->request_queue, request) < 0) {
665  destroy_request_item(&request);
666  }
667  return ret;
668 }
669 
670 static int get_output_onnx(DNNModel *model, const char *input_name, int input_width, int input_height,
671  const char *output_name, int *output_width, int *output_height)
672 {
673  int ret = 0;
674  ONNXModel *onnx_model = (ONNXModel *)model;
675  DnnContext *ctx = onnx_model->ctx;
676  TaskItem task = { 0 };
677  ONNXRequestItem *request = NULL;
678  DNNExecBaseParams exec_params = {
679  .input_name = input_name,
680  .output_names = &output_name,
681  .nb_output = 1,
682  .in_frame = NULL,
683  .out_frame = NULL,
684  };
685 
686  ret = ff_dnn_fill_gettingoutput_task(&task, &exec_params, onnx_model, input_height, input_width, ctx);
687  if (ret != 0) {
688  goto err;
689  }
690 
691  ret = extract_lltask_from_task(&task, onnx_model->lltask_queue);
692  if (ret != 0) {
693  av_log(ctx, AV_LOG_ERROR, "Unable to extract last level task from task.\n");
694  goto err;
695  }
696 
697  request = (ONNXRequestItem *)ff_safe_queue_pop_front(onnx_model->request_queue);
698  if (!request) {
699  av_log(ctx, AV_LOG_ERROR, "Unable to get infer request.\n");
700  ret = AVERROR(EINVAL);
701  goto err;
702  }
703 
704  ret = execute_model_onnx(request, onnx_model->lltask_queue);
705  *output_width = task.out_frame->width;
706  *output_height = task.out_frame->height;
707 
708 err:
709  av_frame_free(&task.out_frame);
710  av_frame_free(&task.in_frame);
711  return ret;
712 }
713 
715 {
716  ONNXInferRequest *request = av_malloc(sizeof(ONNXInferRequest));
717  if (!request)
718  return NULL;
719  request->input_tensor = NULL;
720  request->output_tensor = NULL;
721  request->input_data = NULL;
722  return request;
723 }
724 
726 {
727  DNNModel *model = NULL;
728  ONNXModel *onnx_model = NULL;
729  ONNXRequestItem *item = NULL;
730  ONNXOptions *options = &ctx->onnx_option;
731  OrtStatus *status;
732 
734  if (!g_ort) {
735  av_log(ctx, AV_LOG_ERROR, "Failed to get ONNX Runtime API\n");
736  return NULL;
737  }
738 
739  onnx_model = av_mallocz(sizeof(ONNXModel));
740  if (!onnx_model)
741  return NULL;
742 
743  model = &onnx_model->model;
744  onnx_model->ctx = ctx;
745 
746  status = g_ort->CreateEnv(ORT_LOGGING_LEVEL_WARNING, "FFmpeg", &onnx_model->env);
747  if (status != NULL) {
748  av_log(ctx, AV_LOG_ERROR, "Failed to create ONNX Runtime environment\n");
749  goto fail;
750  }
751 
752  status = g_ort->CreateSessionOptions(&onnx_model->session_options);
753  if (status != NULL) {
754  av_log(ctx, AV_LOG_ERROR, "Failed to create session options\n");
755  goto fail;
756  }
757 
758  if (options->num_threads > 0 &&
759  (!ctx->device || av_strcasecmp(ctx->device, "cpu") == 0)) {
760  g_ort->SetIntraOpNumThreads(onnx_model->session_options, options->num_threads);
761  }
762  g_ort->SetSessionGraphOptimizationLevel(onnx_model->session_options, ORT_ENABLE_ALL);
763 
764  if (ctx->device && av_strcasecmp(ctx->device, "cpu") != 0) {
765  if (av_strcasecmp(ctx->device, "cuda") == 0) {
766  if (g_ort->SessionOptionsAppendExecutionProvider_CUDA) {
767  OrtCUDAProviderOptions cuda_options;
768  memset(&cuda_options, 0, sizeof(cuda_options));
769  cuda_options.device_id = ctx->device_id;
770 
771  status = g_ort->SessionOptionsAppendExecutionProvider_CUDA(
772  onnx_model->session_options, &cuda_options);
773  if (status != NULL) {
774  const char *msg = g_ort->GetErrorMessage(status);
775  av_log(ctx, AV_LOG_WARNING, "Failed to enable CUDA (device %d): %s. Falling back to CPU\n",
776  ctx->device_id, msg);
777  g_ort->ReleaseStatus(status);
778  } else {
779  av_log(ctx, AV_LOG_INFO, "Using CUDA execution provider on device %d\n", ctx->device_id);
780  }
781  } else {
782  av_log(ctx, AV_LOG_WARNING, "CUDA provider function not available in this ONNX Runtime API version. Falling back to CPU\n");
783  }
784  } else if (av_strcasecmp(ctx->device, "dml") == 0) {
785 #ifdef _WIN32
786  const char* dml_options_keys[] = {"device_id"};
787  const char* dml_options_values[] = {NULL};
788  char device_id_str[32];
789  snprintf(device_id_str, sizeof(device_id_str), "%d", ctx->device_id);
790  dml_options_values[0] = device_id_str;
791 
792  /* DirectML cannot use ORT's memory-pattern optimizer and only
793  * supports sequential execution. */
794  status = g_ort->SetSessionExecutionMode(onnx_model->session_options, ORT_SEQUENTIAL);
795  if (status)
796  g_ort->ReleaseStatus(status);
797  status = g_ort->DisableMemPattern(onnx_model->session_options);
798  if (status)
799  g_ort->ReleaseStatus(status);
800 
801  if (g_ort->SessionOptionsAppendExecutionProvider) {
802  status = g_ort->SessionOptionsAppendExecutionProvider(
803  onnx_model->session_options, "DML",
804  dml_options_keys, dml_options_values, 1);
805  if (status != NULL) {
806  const char *msg = g_ort->GetErrorMessage(status);
807  av_log(ctx, AV_LOG_WARNING, "Failed to enable DirectML (device %d): %s. Falling back to CPU\n",
808  ctx->device_id, msg);
809  g_ort->ReleaseStatus(status);
810  } else {
811  av_log(ctx, AV_LOG_INFO, "Using DirectML execution provider on device %d\n", ctx->device_id);
812  }
813  } else {
814  av_log(ctx, AV_LOG_WARNING, "DirectML provider function not available in this ONNX Runtime API version. Falling back to CPU\n");
815  }
816 #else
817  av_log(ctx, AV_LOG_WARNING, "DirectML is only available on Windows. Falling back to CPU\n");
818 #endif
819  } else if (av_strcasecmp(ctx->device, "vitisai") == 0) {
820  if (g_ort->SessionOptionsAppendExecutionProvider) {
821  status = g_ort->SessionOptionsAppendExecutionProvider(
822  onnx_model->session_options, "VitisAI",
823  NULL, NULL, 0);
824  if (status != NULL) {
825  const char *msg = g_ort->GetErrorMessage(status);
827  "Failed to enable VitisAI EP: %s. Falling back to CPU\n", msg);
828  g_ort->ReleaseStatus(status);
829  } else {
830  av_log(ctx, AV_LOG_INFO, "Using VitisAI execution provider (AMD Ryzen AI NPU)\n");
831  }
832  } else {
834  "VitisAI provider function not available in this ONNX Runtime API version. Falling back to CPU.\n");
835  }
836  } else {
837 #ifdef _WIN32
839  "Unknown device '%s'. Supported: cpu, cuda, dml, vitisai. Using CPU\n",
840  ctx->device);
841 #else
843  "Unknown device '%s'. Supported: cpu, cuda, vitisai. Using CPU\n",
844  ctx->device);
845 #endif
846  }
847  } else {
848  av_log(ctx, AV_LOG_INFO, "Using CPU execution provider\n");
849  }
850 
851 #ifdef _WIN32
852  {
853  wchar_t *wfilename = NULL;
854  if (utf8towchar(ctx->model_filename, &wfilename)) {
855  av_log(ctx, AV_LOG_ERROR, "Failed to convert model filename to UTF-16\n");
856  goto fail;
857  }
858  if (!wfilename) {
859  av_log(ctx, AV_LOG_ERROR, "Failed to convert model filename to UTF-16\n");
860  goto fail;
861  }
862 
863  status = g_ort->CreateSession(onnx_model->env, wfilename,
864  onnx_model->session_options, &onnx_model->session);
865  av_free(wfilename);
866  }
867 #else
868  status = g_ort->CreateSession(onnx_model->env, ctx->model_filename,
869  onnx_model->session_options, &onnx_model->session);
870 #endif
871  if (status != NULL) {
872  const char *msg = g_ort->GetErrorMessage(status);
873  av_log(ctx, AV_LOG_ERROR, "Failed to create ONNX session: %s\n", msg);
874  g_ort->ReleaseStatus(status);
875  goto fail;
876  }
877 
878  status = g_ort->GetAllocatorWithDefaultOptions(&onnx_model->allocator);
879  if (status != NULL) {
880  av_log(ctx, AV_LOG_ERROR, "Failed to get allocator\n");
881  goto fail;
882  }
883 
884  /*
885  * The ONNX backend binds exactly one input tensor to Run(), so only
886  * single-input models are supported.
887  */
888  {
889  size_t input_count = 0;
890  status = g_ort->SessionGetInputCount(onnx_model->session, &input_count);
891  if (status != NULL) {
892  const char *msg = g_ort->GetErrorMessage(status);
893  av_log(ctx, AV_LOG_ERROR, "Failed to get model input count: %s\n", msg);
894  g_ort->ReleaseStatus(status);
895  goto fail;
896  }
897  if (input_count == 0) {
898  av_log(ctx, AV_LOG_ERROR, "ONNX model exposes no input tensors\n");
899  goto fail;
900  }
901  if (input_count > 1) {
903  "ONNX model exposes %zu input tensors; the ONNX backend "
904  "supports single-input models only.\n",
905  input_count);
906  goto fail;
907  }
908  }
909 
910  /* Auto-detect the input tensor name when the user did not pass input=NAME. */
911  if (!ctx->model_inputname || !*ctx->model_inputname) {
912  char *name = NULL;
913  status = g_ort->SessionGetInputName(onnx_model->session, 0,
914  onnx_model->allocator, &name);
915  if (status != NULL) {
916  const char *msg = g_ort->GetErrorMessage(status);
917  av_log(ctx, AV_LOG_ERROR, "Failed to get model input name: %s\n", msg);
918  g_ort->ReleaseStatus(status);
919  goto fail;
920  }
921  av_freep(&ctx->model_inputname);
922  ctx->model_inputname = av_strdup(name);
923  onnx_model->allocator->Free(onnx_model->allocator, name);
924  if (!ctx->model_inputname)
925  goto fail;
926  av_log(ctx, AV_LOG_INFO, "Auto-detected ONNX input tensor '%s'\n",
927  ctx->model_inputname);
928  }
929 
930  /* Auto-detect the output tensor name when the user did not pass output=NAME. */
931  if (!ctx->model_outputnames) {
932  size_t output_count = 0;
933  char *name = NULL;
934  status = g_ort->SessionGetOutputCount(onnx_model->session, &output_count);
935  if (status != NULL) {
936  const char *msg = g_ort->GetErrorMessage(status);
937  av_log(ctx, AV_LOG_ERROR, "Failed to get model output count: %s\n", msg);
938  g_ort->ReleaseStatus(status);
939  goto fail;
940  }
941  if (output_count == 0) {
942  av_log(ctx, AV_LOG_ERROR, "ONNX model exposes no output tensors\n");
943  goto fail;
944  }
945  status = g_ort->SessionGetOutputName(onnx_model->session, 0,
946  onnx_model->allocator, &name);
947  if (status != NULL) {
948  const char *msg = g_ort->GetErrorMessage(status);
949  av_log(ctx, AV_LOG_ERROR, "Failed to get model output name: %s\n", msg);
950  g_ort->ReleaseStatus(status);
951  goto fail;
952  }
953  ctx->model_outputnames = av_calloc(1, sizeof(*ctx->model_outputnames));
954  if (!ctx->model_outputnames) {
955  onnx_model->allocator->Free(onnx_model->allocator, name);
956  goto fail;
957  }
958  ctx->model_outputnames[0] = av_strdup(name);
959  onnx_model->allocator->Free(onnx_model->allocator, name);
960  if (!ctx->model_outputnames[0]) {
961  av_freep(&ctx->model_outputnames);
962  goto fail;
963  }
964  ctx->nb_outputs = 1;
965  if (output_count == 1) {
966  av_log(ctx, AV_LOG_INFO, "Auto-detected ONNX output tensor '%s'\n",
967  ctx->model_outputnames[0]);
968  } else {
970  "ONNX model exposes %zu output tensors; auto-using index 0 ('%s'). "
971  "Specify output=NAME to choose a different one.\n",
972  output_count, ctx->model_outputnames[0]);
973  }
974  }
975 
976  onnx_model->request_queue = ff_safe_queue_create();
977  if (!onnx_model->request_queue) {
978  goto fail;
979  }
980 
981  item = av_mallocz(sizeof(ONNXRequestItem));
982  if (!item) {
983  goto fail;
984  }
985  item->lltask = NULL;
987  if (!item->infer_request) {
988  av_log(ctx, AV_LOG_ERROR, "Failed to allocate memory for ONNX inference request\n");
989  goto fail;
990  }
993  item->exec_module.args = item;
994 
995  if (ff_safe_queue_push_back(onnx_model->request_queue, item) < 0) {
996  goto fail;
997  }
998  item = NULL;
999 
1000  onnx_model->task_queue = ff_queue_create();
1001  if (!onnx_model->task_queue) {
1002  goto fail;
1003  }
1004 
1005  onnx_model->lltask_queue = ff_queue_create();
1006  if (!onnx_model->lltask_queue) {
1007  goto fail;
1008  }
1009 
1010  model->get_input = &get_input_onnx;
1011  model->get_output = &get_output_onnx;
1012  model->filter_ctx = filter_ctx;
1013  model->func_type = func_type;
1014 
1015  return model;
1016 
1017 fail:
1018  if (item) {
1019  destroy_request_item(&item);
1020  }
1021  dnn_free_model_onnx(&model);
1022  return NULL;
1023 }
1024 
1025 static int dnn_execute_model_onnx(const DNNModel *model, DNNExecBaseParams *exec_params)
1026 {
1027  ONNXModel *onnx_model = (ONNXModel *)model;
1028  DnnContext *ctx = onnx_model->ctx;
1029  TaskItem *task;
1030  ONNXRequestItem *request;
1031  int ret = 0;
1032 
1033  ret = ff_check_exec_params(ctx, DNN_ONNX, model->func_type, exec_params);
1034  if (ret != 0) {
1035  av_log(ctx, AV_LOG_ERROR, "Exec parameter checking failed.\n");
1036  return ret;
1037  }
1038 
1039  task = av_malloc(sizeof(TaskItem));
1040  if (!task) {
1041  av_log(ctx, AV_LOG_ERROR, "Unable to alloc memory for task item.\n");
1042  return AVERROR(ENOMEM);
1043  }
1044 
1045  ret = ff_dnn_fill_task(task, exec_params, onnx_model, 0, 1);
1046  if (ret != 0) {
1047  av_freep(&task);
1048  av_log(ctx, AV_LOG_ERROR, "Unable to fill task.\n");
1049  return ret;
1050  }
1051 
1052  ret = ff_queue_push_back(onnx_model->task_queue, task);
1053  if (ret < 0) {
1054  av_freep(&task);
1055  av_log(ctx, AV_LOG_ERROR, "Unable to push back task_queue.\n");
1056  return ret;
1057  }
1058 
1059  ret = extract_lltask_from_task(task, onnx_model->lltask_queue);
1060  if (ret != 0) {
1061  av_log(ctx, AV_LOG_ERROR, "Unable to extract last level task from task.\n");
1062  return ret;
1063  }
1064 
1065  request = (ONNXRequestItem *)ff_safe_queue_pop_front(onnx_model->request_queue);
1066  if (!request) {
1067  av_log(ctx, AV_LOG_ERROR, "Unable to get infer request.\n");
1068  return AVERROR(EINVAL);
1069  }
1070 
1071  return execute_model_onnx(request, onnx_model->lltask_queue);
1072 }
1073 
1075 {
1076  ONNXModel *onnx_model = (ONNXModel *)model;
1077  return ff_dnn_get_result_common(onnx_model->task_queue, in, out);
1078 }
1079 
1080 static int dnn_flush_onnx(const DNNModel *model)
1081 {
1082  ONNXModel *onnx_model = (ONNXModel *)model;
1083  ONNXRequestItem *request;
1084 
1085  if (ff_queue_size(onnx_model->lltask_queue) == 0)
1086  return 0;
1087 
1088  request = (ONNXRequestItem *)ff_safe_queue_pop_front(onnx_model->request_queue);
1089  if (!request) {
1090  av_log(onnx_model->ctx, AV_LOG_ERROR, "Unable to get infer request.\n");
1091  return AVERROR(EINVAL);
1092  }
1093 
1094  return execute_model_onnx(request, onnx_model->lltask_queue);
1095 }
1096 
1098  .clazz = DNN_DEFINE_CLASS(dnn_onnx),
1099  .type = DNN_ONNX,
1100  .load_model = dnn_load_model_onnx,
1101  .execute_model = dnn_execute_model_onnx,
1102  .get_result = dnn_get_result_onnx,
1103  .flush = dnn_flush_onnx,
1104  .free_model = dnn_free_model_onnx,
1105 };
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:66
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:31
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:58
onnx_start_inference
static int onnx_start_inference(void *args)
Definition: dnn_backend_onnx.c:420
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:323
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:428
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:44
DNNAsyncExecModule::callback
void(* callback)(void *args)
Completion Callback for the backend.
Definition: dnn_backend_common.h:78
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:1080
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:45
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:622
ONNXModel::session
OrtSession * session
Definition: dnn_backend_onnx.c:46
ff_dnn_wait_requests
void ff_dnn_wait_requests(SafeQueue *request_queue, int nireq)
Wait for all inference requests to complete before teardown.
Definition: dnn_backend_common.c:106
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:514
float
float
Definition: af_crystalizer.c:122
LastLevelTaskItem::task
TaskItem * task
Definition: dnn_backend_common.h:59
ff_dnn_backend_onnx
const DNNModule ff_dnn_backend_onnx
Definition: dnn_backend_onnx.c:1097
dnn_execute_model_onnx
static int dnn_execute_model_onnx(const DNNModel *model, DNNExecBaseParams *exec_params)
Definition: dnn_backend_onnx.c:1025
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:165
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:53
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:187
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:87
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:725
TaskItem::in_frame
AVFrame * in_frame
Definition: dnn_backend_common.h:46
ONNXInferRequest
Definition: dnn_backend_onnx.c:57
AVOnce
#define AVOnce
Definition: thread.h:202
DnnContext::nireq
int nireq
Definition: dnn_interface.h:167
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:50
TaskItem::inference_done
uint32_t inference_done
Definition: dnn_backend_common.h:54
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:51
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:40
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:670
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:71
OFFSET
#define OFFSET(x)
Definition: dnn_backend_onnx.c:69
DNNAsyncExecModule::args
void * args
Argument for the execution functions.
Definition: dnn_backend_common.h:84
safe_queue.h
TaskItem::output_names
const char ** output_names
Definition: dnn_backend_common.h:49
onnx_create_inference_request
static ONNXInferRequest * onnx_create_inference_request(void)
Definition: dnn_backend_onnx.c:714
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:47
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:258
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:145
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:273
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:48
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:51
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:1074
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:52
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