libxcoder 5.9.0
Loading...
Searching...
No Matches
ni_filter_utils.c
Go to the documentation of this file.
1/*******************************************************************************
2 *
3 * Copyright (C) 2022 NETINT Technologies
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
17 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
18 * SOFTWARE.
19 *
20 ******************************************************************************/
21
22/*!*****************************************************************************
23 * \file filter_utils.c
24 *
25 * \brief Video filtering utility functions shared by Libxcoder API examples
26 ******************************************************************************/
27
28#include "ni_generic_utils.h"
29#include "ni_filter_utils.h"
30#include "ni_log.h"
31#include "ni_util.h"
32
33int ni_scaler_params_set_value(ni_scale_params_t *params, const char *name, const char *value)
34{
35 if (!params || !name || !value)
36 {
37 ni_log(NI_LOG_ERROR, "Error: Null pointer received in ni_scaler_params_set_value\n");
38 return -1;
39 }
40
41 if (!strcmp("width", name))
42 {
43 if (ni_strtoi(value, &params->width) != NI_RETCODE_SUCCESS)
44 {
45 ni_log(NI_LOG_ERROR, "ERROR: %s invalid value for %s: %s\n", __func__, name, value);
46 return -1;
47 }
48 } else if (!strcmp("height", name))
49 {
50 if (ni_strtoi(value, &params->height) != NI_RETCODE_SUCCESS)
51 {
52 ni_log(NI_LOG_ERROR, "ERROR: %s invalid value for %s: %s\n", __func__, name, value);
53 return -1;
54 }
55 } else if (!strcmp("format", name))
56 {
57 if (!strcmp(value, "yuv420p"))
58 {
59 params->format = GC620_I420;
60 } else if (!strcmp(value, "yuv420p10le"))
61 {
62 params->format = GC620_I010;
63 } else if (!strcmp(value, "nv12"))
64 {
65 params->format = GC620_NV12;
66 } else if (!strcmp(value, "p010le"))
67 {
68 params->format = GC620_P010_MSB;
69 } else
70 {
71 ni_log(NI_LOG_ERROR, "Error: pixel format %s not supported in scale\n", value);
72 return -1;
73 }
74 } else
75 {
76 ni_log(NI_LOG_ERROR, "Error: invalid scale param name %s\n", name);
77 return -1;
78 }
79
80 return 0;
81}
82
83int ni_drawbox_params_set_value(ni_drawbox_params_t *params, const char *name, const char *value)
84{
85 if (!params || !name || !value)
86 {
87 ni_log(NI_LOG_ERROR, "Error: Null pointer received in ni_drawbox_params_set_value\n");
88 return -1;
89 }
90
91 if (!strcmp("width", name))
92 {
93 if (ni_strtoi(value, &params->box_w) != NI_RETCODE_SUCCESS)
94 {
95 ni_log(NI_LOG_ERROR, "ERROR: %s invalid value for %s: %s\n", __func__, name, value);
96 return -1;
97 }
98 } else if (!strcmp("height", name))
99 {
100 if (ni_strtoi(value, &params->box_h) != NI_RETCODE_SUCCESS)
101 {
102 ni_log(NI_LOG_ERROR, "ERROR: %s invalid value for %s: %s\n", __func__, name, value);
103 return -1;
104 }
105 } else if (!strcmp("x", name))
106 {
107 if (ni_strtoi(value, &params->box_x) != NI_RETCODE_SUCCESS)
108 {
109 ni_log(NI_LOG_ERROR, "ERROR: %s invalid value for %s: %s\n", __func__, name, value);
110 return -1;
111 }
112 } else if (!strcmp("y", name))
113 {
114 if (ni_strtoi(value, &params->box_y) != NI_RETCODE_SUCCESS)
115 {
116 ni_log(NI_LOG_ERROR, "ERROR: %s invalid value for %s: %s\n", __func__, name, value);
117 return -1;
118 }
119 } else
120 {
121 ni_log(NI_LOG_ERROR, "Error: invalid drawbox param name %s\n", name);
122 return -1;
123 }
124
125 return 0;
126}
127
128int ni_ai_pre_params_set_value(ni_ai_pre_params_t *params, const char *name, const char *value)
129{
130 if (!params || !name || !value)
131 {
132 ni_log(NI_LOG_ERROR, "Error: Null pointer received in ni_ai_pre_params_set_value\n");
133 return -1;
134 }
135
136 if (!strcmp("nb", name))
137 {
138 ni_strcpy(params->nb_file, sizeof(params->nb_file), value);
139 } else if (!strcmp("width", name))
140 {
141 if (ni_strtoi(value, &params->out_width) != NI_RETCODE_SUCCESS)
142 {
143 ni_log(NI_LOG_ERROR, "ERROR: %s invalid value for %s: %s\n", __func__, name, value);
144 return -1;
145 }
146 } else if (!strcmp("height", name))
147 {
148 if (ni_strtoi(value, &params->out_height) != NI_RETCODE_SUCCESS)
149 {
150 ni_log(NI_LOG_ERROR, "ERROR: %s invalid value for %s: %s\n", __func__, name, value);
151 return -1;
152 }
153 } else
154 {
155 ni_log(NI_LOG_ERROR, "Error: invalid ai_pre param name %s\n", name);
156 return -1;
157 }
158
159 return 0;
160}
161
162int retrieve_filter_params(char filter_params[], ni_scale_params_t *scale_params,
163 ni_drawbox_params_t *drawbox_params, ni_ai_pre_params_t *ai_pre_params)
164{
165 char key[256], value[256];
166 char *curr = filter_params, *colon_pos;
167 int ret = 0;
168
169 //reset all params to default values first
170 memset(scale_params, 0, sizeof(ni_scale_params_t));
171 memset(drawbox_params, 0, sizeof(ni_drawbox_params_t));
172 memset(ai_pre_params, 0, sizeof(ni_ai_pre_params_t));
173 scale_params->format = GC620_I420;
174
175 if (strncmp("ni_quadra_scale", curr, 15) == 0)
176 {
177 scale_params->enabled = 1;
178 curr += 16;
179 }
180 else if (strncmp("ni_quadra_drawbox", curr, 17) == 0)
181 {
182 drawbox_params->enabled = 1;
183 curr += 18;
184 }
185 else if (strncmp("ni_quadra_ai_pre", curr, 16) == 0)
186 {
187 ai_pre_params->enabled = 1;
188 curr += 17;
189 }
190 else
191 {
192 ni_log(NI_LOG_ERROR, "Error: invalid filter, must be one of [ni_quadra_scale, ni_quadra_drawbox, ni_quadra_ai_pre]");
193 return -1;
194 }
195
196 while (*curr)
197 {
198 colon_pos = strchr(curr, ':');
199
200 if (colon_pos)
201 {
202 *colon_pos = '\0';
203 }
204
205 if (strlen(curr) > sizeof(key) + sizeof(value) - 1 ||
206 ni_param_get_key_value(curr, key, value))
207 {
208 ni_log(NI_LOG_ERROR, "Error: cannot retrieve key/value from filter param: %s\n", curr);
209 ret = -1;
210 break;
211 }
212
213 if (scale_params->enabled)
214 {
215 ret = ni_scaler_params_set_value(scale_params, key, value);
216 } else if (ai_pre_params->enabled)
217 {
218 ret = ni_ai_pre_params_set_value(ai_pre_params, key, value);
219 } else
220 {
221 ret = ni_drawbox_params_set_value(drawbox_params, key, value);
222 }
223 if (ret != 0)
224 {
225 break;
226 }
227
228 if (colon_pos)
229 {
230 curr = colon_pos + 1;
231 } else
232 {
233 curr += strlen(curr);
234 }
235 }
236 return ret;
237}
238
239/*!*****************************************************************************
240 * \brief Init scaler params here - both user setting params and fixed params.
241 *
242 * \param
243 *
244 * \return 0 if successful, < 0 otherwise
245 ******************************************************************************/
246void init_scaler_params(ni_scaler_input_params_t *p_scaler_params, ni_scaler_opcode_t op, int in_rec_width,
247 int in_rec_height, int in_rec_x, int in_rec_y, int out_rec_x, int out_rec_y)
248{
249 p_scaler_params->op = op;
250 // input_format/width/height, output_format/width/height should be assigned by users for all ops
251 if (op == NI_SCALER_OPCODE_CROP)
252 {
253 // fixed numbers
254 p_scaler_params->out_rec_width = 0;
255 p_scaler_params->out_rec_height = 0;
256 p_scaler_params->out_rec_x = 0;
257 p_scaler_params->out_rec_y = 0;
258 p_scaler_params->rgba_color = 0;
259
260 // params set by user
261 p_scaler_params->in_rec_width = in_rec_width;
262 p_scaler_params->in_rec_height = in_rec_height;
263 p_scaler_params->in_rec_x = in_rec_x;
264 p_scaler_params->in_rec_y = in_rec_y;
265 } else if (op == NI_SCALER_OPCODE_SCALE)
266 {
267 // fixed params
268 p_scaler_params->in_rec_width = 0;
269 p_scaler_params->in_rec_height = 0;
270 p_scaler_params->in_rec_x = 0;
271 p_scaler_params->in_rec_y = 0;
272
273 p_scaler_params->out_rec_width = 0;
274 p_scaler_params->out_rec_height = 0;
275 p_scaler_params->out_rec_x = 0;
276 p_scaler_params->out_rec_y = 0;
277
278 p_scaler_params->rgba_color = 0;
279 } else if (op == NI_SCALER_OPCODE_PAD)
280 {
281 // fixed params
282 p_scaler_params->in_rec_width = p_scaler_params->input_width;
283 p_scaler_params->in_rec_height = p_scaler_params->input_height;
284 p_scaler_params->in_rec_x = 0;
285 p_scaler_params->in_rec_y = 0;
286
287 p_scaler_params->out_rec_width = p_scaler_params->input_width;
288 p_scaler_params->out_rec_height = p_scaler_params->input_height;
289
290 /*
291 Scaler uses BGRA color, or ARGB in little-endian
292 ui32RgbaColor = (s->rgba_color[3] << 24) | (s->rgba_color[0] << 16) |
293 (s->rgba_color[1] << 8) | s->rgba_color[2];
294 here p_scaler_params->rgba_color = ui32RgbaColor;
295 */
296 p_scaler_params->rgba_color =
297 4278190080; // now padding color is black
298
299 // params set by user
300 p_scaler_params->out_rec_x = out_rec_x;
301 p_scaler_params->out_rec_y = out_rec_y;
302 } else if (op == NI_SCALER_OPCODE_OVERLAY)
303 {
304 // fixed params
305 // set the in_rec params to the w/h of overlay(the upper) frames
306 p_scaler_params->in_rec_width = p_scaler_params->input_width;
307 p_scaler_params->in_rec_height = p_scaler_params->input_height;
308
309 // the output w/h is the main frame's w/h (main frame is the lower/background frame)
310 p_scaler_params->out_rec_width = p_scaler_params->output_width;
311 p_scaler_params->out_rec_height = p_scaler_params->output_height;
312 p_scaler_params->out_rec_x = 0;
313 p_scaler_params->out_rec_y = 0;
314 p_scaler_params->rgba_color = 0;
315
316 // params set by user
317 p_scaler_params->in_rec_x = in_rec_x;
318 p_scaler_params->in_rec_y = in_rec_y;
319 }
320}
321
322/*!*****************************************************************************
323 * \brief open scaler session
324 *
325 * \param
326 *
327 * \return 0 if successful, < 0 otherwise
328 ******************************************************************************/
329int scaler_session_open(ni_session_context_t *p_scaler_ctx, int iXcoderGUID, ni_scaler_opcode_t op)
330{
331 int ret = 0;
332
333 p_scaler_ctx->session_id = NI_INVALID_SESSION_ID;
334
335 p_scaler_ctx->device_handle = NI_INVALID_DEVICE_HANDLE;
336 p_scaler_ctx->blk_io_handle = NI_INVALID_DEVICE_HANDLE;
337 p_scaler_ctx->hw_id = iXcoderGUID;
338 p_scaler_ctx->device_type = NI_DEVICE_TYPE_SCALER;
339 p_scaler_ctx->scaler_operation = op;
341
343
344 if (ret != NI_RETCODE_SUCCESS)
345 {
346 ni_log(NI_LOG_ERROR, "Error: ni_scaler_session_open() failure!\n");
347 return -1;
348 } else
349 {
350#ifdef _WIN32
351 ni_log(NI_LOG_INFO, "Scaler session open: device_handle %p, session_id %u.\n",
352 p_scaler_ctx->device_handle, p_scaler_ctx->session_id);
353#else
354 ni_log(NI_LOG_INFO, "Scaler session open: device_handle %d, session_id %u.\n",
355 p_scaler_ctx->device_handle, p_scaler_ctx->session_id);
356#endif
357 return 0;
358 }
359}
360
361/*!*****************************************************************************
362 * \brief Launch scaler operation and get the result hw frame
363 *
364 * \param
365 *
366 * \return 0 if successful, < 0 otherwise
367 ******************************************************************************/
368int launch_scaler_operation(ni_session_context_t *p_scaler_ctx, int iXcoderGUID,
369 ni_frame_t *p_frame_in_up, ni_frame_t *p_frame_in_bg,
370 ni_session_data_io_t *p_data_out, ni_scaler_input_params_t scaler_params)
371{
372 int ret = 0;
373 niFrameSurface1_t *frame_surface_up;
374 niFrameSurface1_t *frame_surface_bg;
375 niFrameSurface1_t *frame_surface_output;
376
377 if (p_scaler_ctx->session_id == NI_INVALID_SESSION_ID)
378 {
379 // Open scaler session
380 if (0 != scaler_session_open(p_scaler_ctx, iXcoderGUID, scaler_params.op))
381 {
382 ni_log(NI_LOG_ERROR, "Error: scaler open session error\n");
383 return -1;
384 }
385
386 // init scaler hwframe pool
387 if (0 != ni_scaler_frame_pool_alloc(p_scaler_ctx, scaler_params))
388 {
389 ni_log(NI_LOG_ERROR, "Error: init filter hwframe pool\n");
390 return -1;
391 }
392 }
393
394 // allocate a ni_frame_t structure on the host PC
395 ret = ni_frame_buffer_alloc_hwenc(&p_data_out->data.frame,
396 scaler_params.output_width,
397 scaler_params.output_height, 0);
398 if (ret != 0)
399 {
400 return -1;
401 }
402
403 // out_frame retrieved from decoder
404 frame_surface_up = (niFrameSurface1_t *)(p_frame_in_up->p_data[3]);
405 frame_surface_bg = (niFrameSurface1_t *)(p_frame_in_bg->p_data[3]);
406
407 // Allocate scaler input frame
408 ret = ni_scaler_input_frame_alloc(p_scaler_ctx, scaler_params, frame_surface_up);
409 if (ret != 0)
410 {
411 return -1;
412 }
413
414 // Allocate scaler destination frame.
415 ret = ni_scaler_dest_frame_alloc(p_scaler_ctx, scaler_params, frame_surface_bg);
416 if (ret != 0)
417 {
418 return -1;
419 }
420
421 // Retrieve hardware frame info from 2D engine and put it in the ni_frame_t structure.
422 ret = ni_device_session_read_hwdesc(p_scaler_ctx, p_data_out, NI_DEVICE_TYPE_SCALER);
423 frame_surface_output = (niFrameSurface1_t *)(p_data_out->data.frame.p_data[3]);
424 ni_log(NI_LOG_DEBUG, "%s: output FID %u \n", __func__,
425 frame_surface_output->ui16FrameIdx);
426 if (ret < 0)
427 {
428 ni_frame_buffer_free(p_frame_in_up);
429 ni_frame_buffer_free(p_frame_in_bg);
430 ni_frame_buffer_free(&p_data_out->data.frame);
431 }
432
433 return ret;
434}
435
436/*!*****************************************************************************
437 * \brief Use crop->pad->overlay to simulate a drawbox filter.
438 *
439 * \param
440 *
441 * \return 0 if successful, < 0 otherwise
442 ******************************************************************************/
444 ni_session_context_t *p_overlay_ctx, ni_session_context_t *p_fmt_ctx,
445 ni_frame_t *p_frame_in, ni_session_data_io_t *p_data_out, ni_drawbox_params_t *p_box_params,
446 int iXcoderGUID, int input_format, int output_format)
447{
448 // set default box params
449 int box_width = 80;
450 int box_height = 60;
451 int box_x = 160;
452 int box_y = 100;
453 int line_width = 4;
454 if (p_box_params)
455 {
456 box_width = ((int)((p_box_params->box_w + 1) / 2) * 2);
457 box_height = ((int)((p_box_params->box_h + 1) / 2) * 2);
458 box_x = p_box_params->box_x;
459 box_y = p_box_params->box_y;
460 }
461
462 /*
463 To simulate a drawbox filter, we need to
464 1. Crop at the box set position
465 2. Padding the crop output frame for fixed fixels (depends on the line_width of the box)
466 Recycle the crop hwFrame
467 3. Overlay the padding result on the original frame
468 Recycle the padding hwFrame
469 4. if format-change is needed, launch a scale operation and do format change
470 Recycle the overlay hwFrame
471 */
472
473 int ret = 0;
474 niFrameSurface1_t *p_surface_in;
475 p_surface_in = (niFrameSurface1_t *)(p_frame_in->p_data[3]);
476
477 ni_scaler_input_params_t crop_params = {0};
478 crop_params.input_format = input_format;
479 crop_params.input_width = p_surface_in->ui16width;
480 crop_params.input_height = p_surface_in->ui16height;
481 crop_params.output_format = GC620_I420;
482 crop_params.output_width = box_width;
483 crop_params.output_height = box_height;
484 init_scaler_params(&crop_params, NI_SCALER_OPCODE_CROP, box_width,
485 box_height, box_x, box_y, 0, 0);
486 ni_session_data_io_t crop_data = {0};
487 ret = launch_scaler_operation(p_crop_ctx, iXcoderGUID, p_frame_in,
488 p_frame_in, &crop_data, crop_params);
489 if (ret != 0)
490 {
491 ni_log(NI_LOG_ERROR, "Failed to lauch scaler operation %d\n", crop_params.op);
492 return -1;
493 }
494 niFrameSurface1_t *crop_frame_surface =
495 (niFrameSurface1_t *)(crop_data.data.frame.p_data[3]);
496 ni_hw_frame_ref(crop_frame_surface);
497
498 ni_scaler_input_params_t pad_params = {0};
499 pad_params.input_format = input_format;
500 pad_params.input_width = crop_params.output_width;
501 pad_params.input_height = crop_params.output_height;
502 pad_params.output_format = GC620_I420;
503 pad_params.output_width = crop_params.output_width + line_width * 2;
504 pad_params.output_height = crop_params.output_height + line_width * 2;
505 init_scaler_params(&pad_params, NI_SCALER_OPCODE_PAD, 0, 0, 0, 0,
506 line_width, line_width);
507 ni_session_data_io_t pad_data = {0};
508 ret = launch_scaler_operation(p_pad_ctx, iXcoderGUID, &crop_data.data.frame,
509 &crop_data.data.frame, &pad_data, pad_params);
510 // recycle HwFrameIdx first, then free the frame
511 ni_hw_frame_unref(crop_frame_surface->ui16FrameIdx);
512 ni_frame_buffer_free(&(crop_data.data.frame));
513 if (ret != 0)
514 {
515 ni_log(NI_LOG_ERROR, "Failed to lauch scaler operation %d\n", pad_params.op);
516 return -1;
517 }
518 niFrameSurface1_t *pad_frame_surface =
519 (niFrameSurface1_t *)(pad_data.data.frame.p_data[3]);
520 ni_hw_frame_ref(pad_frame_surface);
521
522 ni_scaler_input_params_t overlay_params = {0};
523 overlay_params.input_format = input_format;
524 overlay_params.input_width = pad_params.output_width;
525 overlay_params.input_height = pad_params.output_height;
526 overlay_params.output_format = GC620_I420;
527 overlay_params.output_width = p_surface_in->ui16width;
528 overlay_params.output_height = p_surface_in->ui16height;
529 int overlay_x = box_x - line_width;
530 int overlay_y = box_y - line_width;
531 init_scaler_params(&overlay_params, NI_SCALER_OPCODE_OVERLAY, 0, 0,
532 overlay_x, overlay_y, 0, 0);
533 ni_session_data_io_t ovly_data = {0};
534 if (output_format == GC620_I420)
535 ret = launch_scaler_operation(p_overlay_ctx, iXcoderGUID,
536 &pad_data.data.frame, p_frame_in,
537 p_data_out, overlay_params);
538 else
539 ret = launch_scaler_operation(p_overlay_ctx, iXcoderGUID,
540 &pad_data.data.frame, p_frame_in,
541 &ovly_data, overlay_params);
542 // recycle HwFrameIdx first, then free the frame
543 ni_hw_frame_unref(pad_frame_surface->ui16FrameIdx);
544 ni_frame_buffer_free(&(pad_data.data.frame));
545 if (ret != 0)
546 {
547 ni_log(NI_LOG_ERROR, "Failed to lauch scaler operation %d\n", overlay_params.op);
548 return -1;
549 }
550
551 if (output_format != GC620_I420) // use scale filter to do format change
552 {
553 niFrameSurface1_t *ovly_frame_surface =
554 (niFrameSurface1_t *)(ovly_data.data.frame.p_data[3]);
555 ni_hw_frame_ref(ovly_frame_surface);
556 ovly_frame_surface->ui16width = overlay_params.output_width;
557 ovly_frame_surface->ui16height = overlay_params.output_height;
558 ret = scale_filter(p_fmt_ctx, &(ovly_data.data.frame), p_data_out,
559 iXcoderGUID, overlay_params.output_width,
560 overlay_params.output_height, GC620_I420,
561 output_format);
562 ni_hw_frame_unref(ovly_frame_surface->ui16FrameIdx);
563 ni_frame_buffer_free(&ovly_data.data.frame);
564 if (ret != 0)
565 {
566 ni_log(NI_LOG_ERROR, "Failed to lauch scaler operation 0\n");
567 return -1;
568 }
569 }
570
571 return 0;
572}
573
574/*!*****************************************************************************
575 * \brief Do a scale and/or format-change operation.
576 *
577 * \param
578 *
579 * \return 0 if successful, < 0 otherwise
580 ******************************************************************************/
582 ni_session_data_io_t *p_data_out, int iXcoderGUID,
583 int scale_width, int scale_height, int in_format, int out_format)
584{
585 int ret;
586 niFrameSurface1_t *p_surface_in;
587 ni_scaler_input_params_t scale_params = {0};
588
589 p_surface_in = (niFrameSurface1_t *)p_frame_in->p_data[3];
590 scale_params.output_format = out_format; // rgba or bgrp or yuv420p;
591 scale_params.output_width = scale_width;
592 scale_params.output_height = scale_height;
593 scale_params.input_format = in_format;
594 scale_params.input_width = p_surface_in ? p_surface_in->ui16width : 0;
595 scale_params.input_height = p_surface_in ? p_surface_in->ui16height : 0;
596 init_scaler_params(&scale_params, NI_SCALER_OPCODE_SCALE, 0, 0, 0, 0, 0, 0);
597
598 ret = launch_scaler_operation(p_ctx, iXcoderGUID, p_frame_in, p_frame_in,
599 p_data_out, scale_params);
600 if (ret != 0)
601 {
602 ni_log(NI_LOG_ERROR, "Failed to lauch scaler operation %d\n", scale_params.op);
603 return -1;
604 }
605
606 return ret;
607}
608
609/*!*****************************************************************************
610 * \brief Open an AI session, configure the network binary and create the
611 * hardware output frame pool used by the ai_pre filter.
612 *
613 * The ai_pre engine preserves the input pixel format (the input/output
614 * format pairing is decided by the loaded .nb model).
615 *
616 * \return 0 if successful, < 0 otherwise
617 ******************************************************************************/
619 int iXcoderGUID, ni_ai_pre_params_t *params,
620 int in_width, int in_height, int in_gc620_format)
621{
622 int ret = 0;
623
624 if (params->out_width <= 0)
625 {
626 params->out_width = in_width;
627 }
628 if (params->out_height <= 0)
629 {
630 params->out_height = in_height;
631 }
632
634 p_ai_ctx->device_handle = NI_INVALID_DEVICE_HANDLE;
635 p_ai_ctx->blk_io_handle = NI_INVALID_DEVICE_HANDLE;
636 p_ai_ctx->hw_id = iXcoderGUID;
637 p_ai_ctx->hw_action = NI_CODEC_HW_ENABLE;
638 p_ai_ctx->device_type = NI_DEVICE_TYPE_AI;
640
642 if (ret != NI_RETCODE_SUCCESS)
643 {
644 ni_log(NI_LOG_ERROR, "Error: ai_pre session open failed %d\n", ret);
645 return -1;
646 }
647
648 ret = ni_ai_config_network_binary(p_ai_ctx, p_network, params->nb_file);
649 if (ret != NI_RETCODE_SUCCESS)
650 {
651 ni_log(NI_LOG_ERROR, "Error: ai_pre config network binary '%s' failed %d\n",
652 params->nb_file, ret);
653 return -1;
654 }
655
656 // Create a pool (size 8) of AI output hardware frames.
657 ret = ni_device_alloc_frame(p_ai_ctx, NI_VPU_CEIL(params->out_width, 2),
658 NI_VPU_CEIL(params->out_height, 2), in_gc620_format,
660 0, 0, 0, 0, 8, 0, NI_DEVICE_TYPE_AI);
661 if (ret != NI_RETCODE_SUCCESS)
662 {
663 ni_log(NI_LOG_ERROR, "Error: ai_pre failed to create frame pool %d\n", ret);
664 return -1;
665 }
666
667 params->initialized = 1;
668 ni_log(NI_LOG_INFO, "ai_pre session opened: nb=%s, out %dx%d, gc620 fmt %d\n",
669 params->nb_file, params->out_width, params->out_height, in_gc620_format);
670 return 0;
671}
672
673/*!*****************************************************************************
674 * \brief Run one AI preprocess operation on a hardware frame. The output is a
675 * new hardware frame preserving the input pixel format.
676 *
677 * \return 0 if successful, < 0 otherwise
678 ******************************************************************************/
680 ni_frame_t *p_frame_in, ni_session_data_io_t *p_data_out,
681 ni_ai_pre_params_t *params, int in_gc620_format)
682{
683 int ret = 0;
684 niFrameSurface1_t *p_surface_in;
685 niFrameSurface1_t *p_surface_out;
686 uint64_t start_ns;
687 // ai frame acquire can be asynchronous; bound the wait by keep-alive timeout
688 const uint64_t timeout_ns = (uint64_t)NI_DEFAULT_KEEP_ALIVE_TIMEOUT * 1000000000ULL;
689
690 p_surface_in = (niFrameSurface1_t *)p_frame_in->p_data[3];
691 if (!p_surface_in)
692 {
693 ni_log(NI_LOG_ERROR, "Error: ai_pre input is not a hardware frame\n");
694 return -1;
695 }
696
697 // Allocate the host-side ni_frame_t that receives the output hw descriptor.
698 ret = ni_frame_buffer_alloc_hwenc(&p_data_out->data.frame,
699 NI_VPU_CEIL(params->out_width, 2),
700 NI_VPU_CEIL(params->out_height, 2), 0);
701 if (ret != 0)
702 {
703 ni_log(NI_LOG_ERROR, "Error: ai_pre failed to alloc output frame\n");
704 return -1;
705 }
706
707 // Acquire the AI destination (output) hardware frame from the pool.
708 start_ns = ni_gettime_ns();
709 do {
710 ret = ni_device_alloc_frame(p_ai_ctx, NI_VPU_CEIL(params->out_width, 2),
711 NI_VPU_CEIL(params->out_height, 2), in_gc620_format,
712 NI_AI_FLAG_IO, 0, 0, 0, 0, 0, -1,
714 if (ret < NI_RETCODE_SUCCESS)
715 {
716 ni_log(NI_LOG_ERROR, "Error: ai_pre failed to alloc AI dst frame %d\n", ret);
717 ni_frame_buffer_free(&p_data_out->data.frame);
718 return -1;
719 }
720 if (ni_gettime_ns() - start_ns > timeout_ns)
721 {
722 ni_log(NI_LOG_ERROR, "Error: ai_pre alloc AI dst frame timeout\n");
723 ni_frame_buffer_free(&p_data_out->data.frame);
724 return -1;
725 }
726 } while (ret != NI_RETCODE_SUCCESS);
727
728 // Provide the AI source (input) hardware frame.
729 ret = ni_device_alloc_frame(p_ai_ctx, 0, 0, 0, 0, 0, 0, 0, 0,
730 p_surface_in->ui32nodeAddress,
731 p_surface_in->ui16FrameIdx,
733 if (ret != NI_RETCODE_SUCCESS)
734 {
735 ni_log(NI_LOG_ERROR, "Error: ai_pre failed to alloc AI src frame %d\n", ret);
736 ni_frame_buffer_free(&p_data_out->data.frame);
737 return -1;
738 }
739
740 // Read the output hardware descriptor (new frame index).
741 start_ns = ni_gettime_ns();
742 do {
743 ret = ni_device_session_read_hwdesc(p_ai_ctx, p_data_out, NI_DEVICE_TYPE_AI);
744 if (ret < NI_RETCODE_SUCCESS)
745 {
746 ni_log(NI_LOG_ERROR, "Error: ai_pre failed to read hwdesc %d\n", ret);
747 ni_frame_buffer_free(&p_data_out->data.frame);
748 return -1;
749 }
750 if (ni_gettime_ns() - start_ns > timeout_ns)
751 {
752 ni_log(NI_LOG_ERROR, "Error: ai_pre read hwdesc timeout\n");
753 ni_frame_buffer_free(&p_data_out->data.frame);
754 return -1;
755 }
756 } while (ret != NI_RETCODE_SUCCESS);
757
758 p_surface_out = (niFrameSurface1_t *)p_data_out->data.frame.p_data[3];
759 p_surface_out->ui16width = params->out_width;
760 p_surface_out->ui16height = params->out_height;
761 ni_log(NI_LOG_DEBUG, "ai_pre in FID %u -> out FID %u\n",
762 p_surface_in->ui16FrameIdx, p_surface_out->ui16FrameIdx);
763
764 return 0;
765}
@ NI_DEVICE_TYPE_SCALER
Definition ni_defs.h:362
@ NI_DEVICE_TYPE_AI
Definition ni_defs.h:363
@ NI_SCALER_OPCODE_PAD
Definition ni_defs.h:597
@ NI_SCALER_OPCODE_OVERLAY
Definition ni_defs.h:598
@ NI_SCALER_OPCODE_CROP
Definition ni_defs.h:595
@ NI_SCALER_OPCODE_SCALE
Definition ni_defs.h:594
enum _ni_scaler_opcode ni_scaler_opcode_t
@ NI_RETCODE_SUCCESS
Definition ni_defs.h:448
ni_retcode_t ni_ai_config_network_binary(ni_session_context_t *p_ctx, ni_network_data_t *p_network, const char *file)
configure a network context based with the network binary
ni_retcode_t ni_frame_buffer_free(ni_frame_t *p_frame)
Free frame buffer that was previously allocated with either ni_frame_buffer_alloc or ni_encoder_frame...
ni_retcode_t ni_scaler_frame_pool_alloc(ni_session_context_t *p_ctx, ni_scaler_input_params_t scaler_params)
init output pool of scaler frames
ni_retcode_t ni_device_session_open(ni_session_context_t *p_ctx, ni_device_type_t device_type)
Open a new device session depending on the device_type parameter If device_type is NI_DEVICE_TYPE_DEC...
ni_retcode_t ni_scaler_dest_frame_alloc(ni_session_context_t *p_ctx, ni_scaler_input_params_t scaler_params, niFrameSurface1_t *p_surface)
allocate device destination frame from scaler hwframe pool
ni_retcode_t ni_scaler_input_frame_alloc(ni_session_context_t *p_ctx, ni_scaler_input_params_t scaler_params, niFrameSurface1_t *p_src_surface)
allocate device input frame by hw descriptor. This call won't actually allocate a frame but sends the...
ni_retcode_t ni_device_alloc_frame(ni_session_context_t *p_ctx, int width, int height, int format, int options, int rectangle_width, int rectangle_height, int rectangle_x, int rectangle_y, int rgba_color, int frame_index, ni_device_type_t device_type)
Allocate a frame on the device for 2D engine or AI engine to work on based on provided parameters.
ni_retcode_t ni_frame_buffer_alloc_hwenc(ni_frame_t *p_frame, int video_width, int video_height, int extra_len)
Allocate memory for the hwDescriptor buffer based on provided parameters taking into account pic size...
int ni_device_session_read_hwdesc(ni_session_context_t *p_ctx, ni_session_data_io_t *p_data, ni_device_type_t device_type)
Read data from the device If device_type is NI_DEVICE_TYPE_DECODER reads data hwdesc from decoder If ...
#define GC620_I420
#define NI_AI_FLAG_PC
#define GC620_NV12
#define GC620_P010_MSB
#define NI_INVALID_SESSION_ID
#define NI_AI_FLAG_IO
@ NI_CODEC_HW_ENABLE
#define NI_DEFAULT_KEEP_ALIVE_TIMEOUT
#define GC620_I010
#define NI_VPU_CEIL(_data, _align)
void init_scaler_params(ni_scaler_input_params_t *p_scaler_params, ni_scaler_opcode_t op, int in_rec_width, int in_rec_height, int in_rec_x, int in_rec_y, int out_rec_x, int out_rec_y)
Init scaler params here - both user setting params and fixed params.
int scale_filter(ni_session_context_t *p_ctx, ni_frame_t *p_frame_in, ni_session_data_io_t *p_data_out, int iXcoderGUID, int scale_width, int scale_height, int in_format, int out_format)
Do a scale and/or format-change operation.
int ni_scaler_params_set_value(ni_scale_params_t *params, const char *name, const char *value)
int drawbox_filter(ni_session_context_t *p_crop_ctx, ni_session_context_t *p_pad_ctx, ni_session_context_t *p_overlay_ctx, ni_session_context_t *p_fmt_ctx, ni_frame_t *p_frame_in, ni_session_data_io_t *p_data_out, ni_drawbox_params_t *p_box_params, int iXcoderGUID, int input_format, int output_format)
Use crop->pad->overlay to simulate a drawbox filter.
int ni_ai_pre_params_set_value(ni_ai_pre_params_t *params, const char *name, const char *value)
int ai_pre_filter(ni_session_context_t *p_ai_ctx, ni_network_data_t *p_network, ni_frame_t *p_frame_in, ni_session_data_io_t *p_data_out, ni_ai_pre_params_t *params, int in_gc620_format)
Run one AI preprocess operation on a hardware frame. The output is a new hardware frame preserving th...
int launch_scaler_operation(ni_session_context_t *p_scaler_ctx, int iXcoderGUID, ni_frame_t *p_frame_in_up, ni_frame_t *p_frame_in_bg, ni_session_data_io_t *p_data_out, ni_scaler_input_params_t scaler_params)
Launch scaler operation and get the result hw frame.
int retrieve_filter_params(char filter_params[], ni_scale_params_t *scale_params, ni_drawbox_params_t *drawbox_params, ni_ai_pre_params_t *ai_pre_params)
int scaler_session_open(ni_session_context_t *p_scaler_ctx, int iXcoderGUID, ni_scaler_opcode_t op)
open scaler session
int ai_pre_filter_init(ni_session_context_t *p_ai_ctx, ni_network_data_t *p_network, int iXcoderGUID, ni_ai_pre_params_t *params, int in_width, int in_height, int in_gc620_format)
Open an AI session, configure the network binary and create the hardware output frame pool used by th...
int ni_drawbox_params_set_value(ni_drawbox_params_t *params, const char *name, const char *value)
void ni_hw_frame_unref(uint16_t hwframe_index)
void ni_hw_frame_ref(const niFrameSurface1_t *p_surface)
void ni_log(ni_log_level_t level, const char *fmt,...)
print log message using ni_log_callback
Definition ni_log.c:183
Logging definitions.
@ NI_LOG_DEBUG
Definition ni_log.h:64
@ NI_LOG_ERROR
Definition ni_log.h:62
@ NI_LOG_INFO
Definition ni_log.h:63
int ni_param_get_key_value(char *p_str, char *key, char *value)
retrieve key and value from 'key=value' pair
Definition ni_util.c:4468
ni_retcode_t ni_strcpy(char *dest, size_t dmax, const char *src)
Definition ni_util.c:460
uint64_t ni_gettime_ns(void)
Definition ni_util.c:2701
ni_retcode_t ni_strtoi(const char *str, int32_t *out_val)
Safely convert a decimal string to a 32-bit integer with full validation. Trailing whitespace is tole...
Definition ni_util.c:2577
Utility definitions.
char nb_file[FILE_NAME_LEN]
uint8_t * p_data[NI_MAX_NUM_DATA_POINTERS]
ni_device_handle_t device_handle
ni_device_handle_t blk_io_handle
union _ni_session_data_io::@19 data