libxcoder 5.8.0
Loading...
Searching...
No Matches
ni_util.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 ni_util.c
24 *
25 * \brief Utility definitions
26 ******************************************************************************/
27
28#if __linux__ || __APPLE__
29#include <sys/ioctl.h>
30#include <sys/stat.h>
31#include <sys/ioctl.h>
32#include <sys/mman.h>
33#include <stddef.h>
34#include <sys/types.h>
35#include <sys/stat.h>
36#include <fcntl.h>
37#include <unistd.h>
38#endif
39
40#if __linux__
41#include <linux/fs.h>
42#endif
43
44#include <ctype.h>
45#include <errno.h>
46#include <limits.h>
47#include "ni_nvme.h"
48#include "ni_util.h"
49
55
56static const ni_err_rc_txt_entry_t ni_err_rc_description[] = {
57 {NI_RETCODE_SUCCESS, "SUCCESS"},
58 {NI_RETCODE_FAILURE, "FAILURE"},
59 {NI_RETCODE_INVALID_PARAM, "INVALID_PARAM"},
60 {NI_RETCODE_ERROR_MEM_ALOC, "ERROR_MEM_ALOC"},
61 {NI_RETCODE_ERROR_NVME_CMD_FAILED, "ERROR_NVME_CMD_FAILED"},
62 {NI_RETCODE_ERROR_INVALID_SESSION, "ERROR_INVALID_SESSION"},
63 {NI_RETCODE_ERROR_RESOURCE_UNAVAILABLE, "ERROR_RESOURCE_UNAVAILABLE"},
64 {NI_RETCODE_PARAM_INVALID_NAME, "PARAM_INVALID_NAME"},
65 {NI_RETCODE_PARAM_INVALID_VALUE, "PARAM_INVALID_VALUE"},
66 {NI_RETCODE_PARAM_ERROR_FRATE, "PARAM_ERROR_FRATE"},
67 {NI_RETCODE_PARAM_ERROR_BRATE, "PARAM_ERROR_BRATE"},
68 {NI_RETCODE_PARAM_ERROR_TRATE, "PARAM_ERROR_TRATE"},
69 {NI_RETCODE_PARAM_ERROR_VBV_BUFFER_SIZE, "PARAM_ERROR_VBV_BUFFER_SIZE"},
70 {NI_RETCODE_PARAM_ERROR_INTRA_PERIOD, "PARAM_ERROR_INTRA_PERIOD"},
71 {NI_RETCODE_PARAM_ERROR_INTRA_QP, "PARAM_ERROR_INTRA_QP"},
72 {NI_RETCODE_PARAM_ERROR_GOP_PRESET, "PARAM_ERROR_GOP_PRESET"},
73 {NI_RETCODE_PARAM_ERROR_CU_SIZE_MODE, "PARAM_ERROR_CU_SIZE_MODE"},
74 {NI_RETCODE_PARAM_ERROR_MX_NUM_MERGE, "PARAM_ERROR_MX_NUM_MERGE"},
75 {NI_RETCODE_PARAM_ERROR_DY_MERGE_8X8_EN, "PARAM_ERROR_DY_MERGE_8X8_EN"},
76 {NI_RETCODE_PARAM_ERROR_DY_MERGE_16X16_EN, "PARAM_ERROR_DY_MERGE_16X16_EN"},
77 {NI_RETCODE_PARAM_ERROR_DY_MERGE_32X32_EN, "PARAM_ERROR_DY_MERGE_32X32_EN"},
78 {NI_RETCODE_PARAM_ERROR_CU_LVL_RC_EN, "PARAM_ERROR_CU_LVL_RC_EN"},
79 {NI_RETCODE_PARAM_ERROR_HVS_QP_EN, "PARAM_ERROR_HVS_QP_EN"},
80 {NI_RETCODE_PARAM_ERROR_HVS_QP_SCL, "PARAM_ERROR_HVS_QP_SCL"},
81 {NI_RETCODE_PARAM_ERROR_MN_QP, "PARAM_ERROR_MN_QP"},
82 {NI_RETCODE_PARAM_ERROR_MX_QP, "PARAM_ERROR_MX_QP"},
83 {NI_RETCODE_PARAM_ERROR_MX_DELTA_QP, "PARAM_ERROR_MX_DELTA_QP"},
84 {NI_RETCODE_PARAM_ERROR_CONF_WIN_TOP, "PARAM_ERROR_CONF_WIN_TOP"},
85 {NI_RETCODE_PARAM_ERROR_CONF_WIN_BOT, "PARAM_ERROR_CONF_WIN_BOT"},
86 {NI_RETCODE_PARAM_ERROR_CONF_WIN_L, "PARAM_ERROR_CONF_WIN_L"},
87 {NI_RETCODE_PARAM_ERROR_CONF_WIN_R, "PARAM_ERROR_CONF_WIN_R"},
88 {NI_RETCODE_PARAM_ERROR_USR_RMD_ENC_PARAM, "PARAM_ERROR_USR_RMD_ENC_PARAM"},
89 {NI_RETCODE_PARAM_ERROR_BRATE_LT_TRATE, "PARAM_ERROR_BRATE_LT_TRATE"},
90 {NI_RETCODE_PARAM_ERROR_RCENABLE, "PARAM_ERROR_RCENABLE"},
91 {NI_RETCODE_PARAM_ERROR_MAXNUMMERGE, "PARAM_ERROR_MAXNUMMERGE"},
92 {NI_RETCODE_PARAM_ERROR_CUSTOM_GOP, "PARAM_ERROR_CUSTOM_GOP"},
93 {NI_RETCODE_PARAM_ERROR_PIC_WIDTH, "PARAM_ERROR_PIC_WIDTH"},
94 {NI_RETCODE_PARAM_ERROR_PIC_HEIGHT, "PARAM_ERROR_PIC_HEIGHT"},
95 {NI_RETCODE_PARAM_ERROR_DECODING_REFRESH_TYPE, "PARAM_ERROR_DECODING_REFRESH_TYPE"},
96 {NI_RETCODE_PARAM_ERROR_CUSIZE_MODE_8X8_EN, "PARAM_ERROR_CUSIZE_MODE_8X8_EN"},
97 {NI_RETCODE_PARAM_ERROR_CUSIZE_MODE_16X16_EN, "PARAM_ERROR_CUSIZE_MODE_16X16_EN"},
98 {NI_RETCODE_PARAM_ERROR_CUSIZE_MODE_32X32_EN, "PARAM_ERROR_CUSIZE_MODE_32X32_EN"},
99 {NI_RETCODE_PARAM_ERROR_TOO_BIG, "PARAM_ERROR_TOO_BIG"},
100 {NI_RETCODE_PARAM_ERROR_TOO_SMALL, "PARAM_ERROR_TOO_SMALL"},
101 {NI_RETCODE_PARAM_ERROR_ZERO, "PARAM_ERROR_ZERO"},
102 {NI_RETCODE_PARAM_ERROR_OOR, "PARAM_ERROR_OOR"},
103 {NI_RETCODE_PARAM_ERROR_WIDTH_TOO_BIG, "PARAM_ERROR_WIDTH_TOO_BIG"},
104 {NI_RETCODE_PARAM_ERROR_WIDTH_TOO_SMALL, "PARAM_ERROR_WIDTH_TOO_SMALL"},
105 {NI_RETCODE_PARAM_ERROR_HEIGHT_TOO_BIG, "PARAM_ERROR_HEIGHT_TOO_BIG"},
106 {NI_RETCODE_PARAM_ERROR_HEIGHT_TOO_SMALL, "PARAM_ERROR_HEIGHT_TOO_SMALL"},
107 {NI_RETCODE_PARAM_ERROR_AREA_TOO_BIG, "PARAM_ERROR_AREA_TOO_BIG"},
108 {NI_RETCODE_ERROR_EXCEED_MAX_NUM_SESSIONS, "ERROR_EXCEED_MAX_NUM_SESSIONS"},
109 {NI_RETCODE_ERROR_GET_DEVICE_POOL, "ERROR_GET_DEVICE_POOL"},
110 {NI_RETCODE_ERROR_LOCK_DOWN_DEVICE, "ERROR_LOCK_DOWN_DEVICE"},
111 {NI_RETCODE_ERROR_UNLOCK_DEVICE, "ERROR_UNLOCK_DEVICE"},
112 {NI_RETCODE_ERROR_OPEN_DEVICE, "ERROR_OPEN_DEVICE"},
113 {NI_RETCODE_ERROR_INVALID_HANDLE, "ERROR_INVALID_HANDLE"},
114 {NI_RETCODE_ERROR_INVALID_ALLOCATION_METHOD, "ERROR_INVALID_ALLOCATION_METHOD"},
115 {NI_RETCODE_ERROR_VPU_RECOVERY, "ERROR_VPU_RECOVERY"},
116 {NI_RETCODE_ERROR_STREAM_ERROR, "ERROR_STREAM_ERROR"},
117
118 {NI_RETCODE_PARAM_WARNING_DEPRECATED, "PARAM_WARNING_DEPRECATED"},
119 {NI_RETCODE_PARAM_ERROR_LOOK_AHEAD_DEPTH, "PARAM_ERROR_LOOK_AHEAD_DEPTH"},
120 {NI_RETCODE_PARAM_ERROR_FILLER, "PARAM_ERROR_FILLER"},
121 {NI_RETCODE_PARAM_ERROR_PICSKIP, "PARAM_ERROR_PICSKIP"},
122
123 {NI_RETCODE_PARAM_WARN, "PARAM_WARN"},
124
125 {NI_RETCODE_NVME_SC_WRITE_BUFFER_FULL, "NVME_SC_WRITE_BUFFER_FULL"},
126 {NI_RETCODE_NVME_SC_RESOURCE_UNAVAILABLE, "NVME_SC_RESOURCE_UNAVAILABLE"},
127 {NI_RETCODE_NVME_SC_RESOURCE_IS_EMPTY, "NVME_SC_RESOURCE_IS_EMPTY"},
128 {NI_RETCODE_NVME_SC_RESOURCE_NOT_FOUND, "NVME_SC_RESOURCE_NOT_FOUND"},
129 {NI_RETCODE_NVME_SC_REQUEST_NOT_COMPLETED, "NVME_SC_REQUEST_NOT_COMPLETED"},
130 {NI_RETCODE_NVME_SC_REQUEST_IN_PROGRESS, "NVME_SC_REQUEST_IN_PROGRESS"},
131 {NI_RETCODE_NVME_SC_INVALID_PARAMETER, "NVME_SC_INVALID_PARAMETER"},
132 {NI_RETCODE_NVME_SC_STREAM_ERROR, "NVME_SC_STREAM_ERROR"},
133 {NI_RETCODE_NVME_SC_INTERLACED_NOT_SUPPORTED, "NVME_SC_INTERLACED_NOT_SUPPORTED"},
134 {NI_RETCODE_NVME_SC_VPU_RECOVERY, "NVME_SC_VPU_RECOVERY"},
135 {NI_RETCODE_NVME_SC_VPU_RSRC_INSUFFICIENT, "NVME_SC_VPU_RSRC_INSUFFICIENT"},
136 {NI_RETCODE_NVME_SC_VPU_GENERAL_ERROR, "NVME_SC_VPU_GENERAL_ERROR"},
137};
138
139/*!*****************************************************************************
140 * \brief Get time for logs with microsecond timestamps
141 *
142 * \param[in/out] p_tp timeval struct
143 * \param[in] p_tzp void *
144 *
145 * \return return 0 for success, -1 for error
146 ******************************************************************************/
147int32_t ni_gettimeofday(struct timeval *p_tp, void *p_tzp)
148{
149#ifdef _WIN32
150 FILETIME file_time;
151 SYSTEMTIME system_time;
152 ULARGE_INTEGER ularge;
154 static const unsigned __int64 epoch =
155 ((unsigned __int64)116444736000000000ULL);
156
157 // timezone information is stored outside the kernel so tzp isn't used
158 (void *)p_tzp;
160 // Note: this function is not a precision timer. See elapsed_time().
161 GetSystemTime(&system_time);
162 SystemTimeToFileTime(&system_time, &file_time);
163 ularge.LowPart = file_time.dwLowDateTime;
164 ularge.HighPart = file_time.dwHighDateTime;
165 // Surpress cppcheck
166 (void)ularge.LowPart;
167 (void)ularge.HighPart;
168 p_tp->tv_sec = (long)((ularge.QuadPart - epoch) / 10000000L);
169 p_tp->tv_usec = (long)(system_time.wMilliseconds * 1000);
170
171 return 0;
172#else
173 return gettimeofday(p_tp, p_tzp);
174#endif
175}
176
177uint32_t ni_round_up(uint32_t number_to_round, uint32_t multiple)
178{
179 if (0 == multiple)
180 {
181 return number_to_round;
182 }
183
184 uint32_t remainder = number_to_round % multiple;
185 if (0 == remainder)
186 {
187 return number_to_round;
188 }
189
190 return (number_to_round + multiple - remainder);
191}
192
193/*!*****************************************************************************
194 * \brief Allocate aligned memory
195 *
196 * \param[in/out] memptr The address of the allocated memory will be a
197 * multiple of alignment, which must be a power of two
198 * and a multiple of sizeof(void *). If size is 0, then
199 * the value placed is either NULL, or a unique pointer
200 * value that can later be successfully passed to free.
201 * \param[in] alignment The alignment value of the allocated value.
202 * \param[in] size The allocated memory size.
203 *
204 * \return 0 for success, ENOMEM for error
205 ******************************************************************************/
206int ni_posix_memalign(void **memptr, size_t alignment, size_t size)
207{
208#ifdef _WIN32
209 *memptr = _aligned_malloc(size, alignment);
210 if (NULL == *memptr)
211 {
212 return ENOMEM;
213 } else
214 {
215 ZeroMemory(*memptr, size);
216 return 0;
217 }
218#else
219 return posix_memalign(memptr, alignment, size);
220#endif
221}
222
223#ifdef __linux__
224/*!******************************************************************************
225 * \brief Get max io transfer size from the kernel
226 *
227 * \param
228 *
229 * \return
230 *******************************************************************************/
231uint32_t ni_get_kernel_max_io_size(const char * p_dev)
232{
233 FILE *p_file = NULL; /* file pointer*/
234 char file_name[KERNEL_NVME_FILE_NAME_MAX_SZ];
235 int max_segments = 0, min_io_size = 0, max_hw_sectors_kb = 0;
236 uint32_t io_size = DEFAULT_IO_TRANSFER_SIZE;
237 size_t len = 0;
238 int err = 0;
239
240 memset(file_name, 0, KERNEL_NVME_FILE_NAME_MAX_SZ);
241
242 if (!p_dev)
243 {
244 ni_log(NI_LOG_ERROR, "Invalid Arguments\n");
245 LRETURN;
246 }
247
248 len = strlen(p_dev) - 5;
249 if (len < MIN_NVME_DEV_NAME_LEN)
250 {
251 ni_log(NI_LOG_DEBUG, "p_dev length is %zu\n", len);
252 LRETURN;
253 }
254
255 // Get Max number of segments from /sys
256 memset(file_name, 0, sizeof(file_name));
257 ni_strcpy(file_name, KERNEL_NVME_FILE_NAME_MAX_SZ, SYS_PARAMS_PREFIX_PATH);
258#if defined(_ANDROID) || defined(__OPENHARMONY__)
259 //start from 11 chars ahead to not copy the "/dev/block/" since we only need whats after it
260 ni_strncat(file_name, KERNEL_NVME_FILE_NAME_MAX_SZ, (char *)(p_dev + 11), sizeof(file_name) - SYS_PREFIX_SZ);
261#else
262 //start from 5 chars ahead to not copy the "/dev/" since we only need whats after it
263 ni_strncat(file_name, KERNEL_NVME_FILE_NAME_MAX_SZ, (char *)(p_dev + 5), sizeof(file_name) - SYS_PREFIX_SZ);
264#endif
265 ni_strncat(file_name, KERNEL_NVME_FILE_NAME_MAX_SZ, KERNEL_NVME_MAX_SEG_PATH,
266 sizeof(file_name) - SYS_PREFIX_SZ - len);
267 ni_log(NI_LOG_DEBUG, "file_name is %s\n", file_name);
268 ni_fopen(&p_file, file_name, "r");
269 if (!p_file)
270 {
271 ni_log(NI_LOG_ERROR, "file_name failed to open: %s\n", file_name);
272 LRETURN;
273 }
274
275 err = ni_fscanf(p_file, "%d", &max_segments);
276 if (EOF == err)
277 {
278 ni_log(NI_LOG_ERROR, "fscanf failed on: %s max_segments\n", file_name);
279 LRETURN;
280 }
281
282 (void)fclose(p_file);
283 p_file = NULL;
284 // Get Max segment size from /sys
285 memset(file_name, 0, sizeof(file_name));
286 ni_strcpy(file_name, KERNEL_NVME_FILE_NAME_MAX_SZ, SYS_PARAMS_PREFIX_PATH);
287#if defined(_ANDROID) || defined(__OPENHARMONY__)
288 //start from 11 chars ahead to not copy the "/dev/block/" since we only need whats after it
289 ni_strncat(file_name, KERNEL_NVME_FILE_NAME_MAX_SZ, (char *)(p_dev + 11), sizeof(file_name) - SYS_PREFIX_SZ);
290#else
291 //start from 5 chars ahead to not copy the "/dev/" since we only need whats after it
292 ni_strncat(file_name, KERNEL_NVME_FILE_NAME_MAX_SZ, (char *)(p_dev + 5), sizeof(file_name) - SYS_PREFIX_SZ);
293#endif
294 ni_strncat(file_name, KERNEL_NVME_FILE_NAME_MAX_SZ, KERNEL_NVME_MIN_IO_SZ_PATH,
295 sizeof(file_name) - SYS_PREFIX_SZ - len);
296 ni_log(NI_LOG_DEBUG, "file_name is %s\n", file_name);
297 ni_fopen(&p_file, file_name, "r");
298 if (!p_file)
299 {
300 ni_log(NI_LOG_ERROR, "file_name failed to open: %s\n", file_name);
301 LRETURN;
302 }
303
304 err = ni_fscanf(p_file, "%d", &min_io_size);
305 if (EOF == err)
306 {
307 ni_log(NI_LOG_ERROR, "fscanf failed on: %s min_io_size\n", file_name);
308 LRETURN;
309 }
310
311 (void)fclose(p_file);
312 p_file = NULL;
313 //Now get max_hw_sectors_kb
314 memset(file_name, 0, sizeof(file_name));
315 ni_strcpy(file_name, KERNEL_NVME_FILE_NAME_MAX_SZ, SYS_PARAMS_PREFIX_PATH);
316#if defined(_ANDROID) || defined(__OPENHARMONY__)
317 //start from 11 chars ahead to not copy the "/dev/block/" since we only need whats after it
318 ni_strncat(file_name, KERNEL_NVME_FILE_NAME_MAX_SZ, (char *)(p_dev + 11), sizeof(file_name) - SYS_PREFIX_SZ);
319#else
320 //start from 5 chars ahead to not copy the "/dev/" since we only need whats after it
321 ni_strncat(file_name, KERNEL_NVME_FILE_NAME_MAX_SZ, (char *)(p_dev + 5), sizeof(file_name) - SYS_PREFIX_SZ);
322#endif
323 ni_strncat(file_name, KERNEL_NVME_FILE_NAME_MAX_SZ, KERNEL_NVME_MAX_HW_SEC_KB_PATH,
324 sizeof(file_name) - SYS_PREFIX_SZ - len);
325 ni_log(NI_LOG_DEBUG, "file_name is %s\n", file_name);
326 ni_fopen(&p_file, file_name, "r");
327 if (!p_file)
328 {
329 ni_log(NI_LOG_ERROR, "file_name failed to open: %s\n", file_name);
330 LRETURN;
331 }
332
333 err = ni_fscanf(p_file, "%d", &max_hw_sectors_kb);
334 if (EOF == err)
335 {
336 ni_log(NI_LOG_ERROR, "fscanf failed on: %s min_io_size\n", file_name);
337 LRETURN;
338 }
339
340 if (ni_min(min_io_size * max_segments, max_hw_sectors_kb * 1024) >
341 MAX_IO_TRANSFER_SIZE)
342 {
343 io_size = MAX_IO_TRANSFER_SIZE;
344 //ni_log(NI_LOG_INFO, "max_io_size is set to: %d because its bigger than maximum limit of: %d\n",io_size, MAX_IO_TRANSFER_SIZE);
345 } else
346 {
347 io_size = ni_min(min_io_size * max_segments, max_hw_sectors_kb * 1024);
348 }
349
350 // ni_log(NI_LOG_INFO, "\nMAX NVMe IO Size of %d was calculated for this platform and will
351 // be used unless overwritten by user settings\n",io_size);
352 (void)fflush(stdout);
353
354END:
355
356 if (p_file)
357 {
358 (void)fclose(p_file);
359 }
360
361 return io_size;
362}
363
364#endif
365
366void ni_usleep(int64_t usec)
367{
368#ifdef _WIN32
369 if (usec < 5000) //this will be more accurate when less than 5000
370 {
371 LARGE_INTEGER StartCount;
372 LARGE_INTEGER StopCount;
373 LARGE_INTEGER Frequency;
374 QueryPerformanceCounter(&StartCount);
375 QueryPerformanceFrequency(&Frequency);
376 StopCount.QuadPart =
377 StartCount.QuadPart + usec * (Frequency.QuadPart / 1000000);
378 do
379 {
380 QueryPerformanceCounter(&StartCount);
381 } while (StartCount.QuadPart < StopCount.QuadPart);
382 } else
383 {
384 HANDLE timer = NULL;
385 LARGE_INTEGER ft = {0};
386 BOOL retval;
387
388 ft.QuadPart = -(
389 10 *
390 usec); // Convert to 100 nanosecond interval, negative value indicates relative time
391
392 timer = CreateWaitableTimer(NULL, TRUE, NULL);
393 if (NULL != timer)
394 {
395 retval = SetWaitableTimer(timer, &ft, 0, NULL, NULL, 0);
396 if (retval)
397 {
398 WaitForSingleObject(timer, INFINITE);
399 }
400 CloseHandle(timer);
401 } else
402 {
403 ni_log(NI_LOG_ERROR, "failed to create waitable timer\n");
404 LARGE_INTEGER StartCount;
405 LARGE_INTEGER StopCount;
406 LARGE_INTEGER Frequency;
407 QueryPerformanceCounter(&StartCount);
408 QueryPerformanceFrequency(&Frequency);
409 StopCount.QuadPart =
410 StartCount.QuadPart + usec * (Frequency.QuadPart / 1000000);
411 do
412 {
413 QueryPerformanceCounter(&StartCount);
414 } while (StartCount.QuadPart < StopCount.QuadPart);
415 }
416 }
417#else
418 if (usec < 0xFFFFFFFF) // to avoid overflow
419 {
420 usleep(usec);
421 } else
422 {
423 struct timespec ts = {(time_t)(usec >> 32), 0};
424 nanosleep(&ts, NULL);
425 }
426#endif
427}
428
429char *ni_strtok(char *s, const char *delim, char **saveptr)
430{
431 char *tok;
432
433 if (!s)
434 s = *saveptr;
435 if (!s)
436 return NULL;
437
438 /* skip leading delimiters */
439 s += strspn(s, delim);
440
441 /* s now points to the first non delimiter char, or to the end of the string */
442 if (!*s) {
443 *saveptr = NULL;
444 return NULL;
445 }
446 tok = s++;
447
448 /* skip non delimiters */
449 s += strcspn(s, delim);
450 if (*s) {
451 *s = '\0';
452 *saveptr = s+1;
453 } else {
454 *saveptr = NULL;
455 }
456
457 return tok;
458}
459
460ni_retcode_t ni_strcpy(char *dest, size_t dmax, const char *src)
461{
462#if defined(_WIN32)
463 if(strcpy_s(dest, dmax, src))
464 return NI_RETCODE_FAILURE;
465 else
466 return NI_RETCODE_SUCCESS;
467#else
468 if (!dest || !dmax || !src)
470
471 if (dest == src)
472 return NI_RETCODE_SUCCESS;
473
474 size_t orig_dmax;
475 char *orig_dest;
476 const char *overlap_bumper;
477 /* hold base of dest in case src was not copied */
478 orig_dmax = dmax;
479 orig_dest = dest;
480
481 if (dest < src) {
482 overlap_bumper = src;
483 while (dmax > 0) {
484 if (dest == overlap_bumper) {
485 (void)orig_dmax;
486 *orig_dest = '\0';
487 return NI_RETCODE_FAILURE;
488 }
489 *dest = *src;
490 if (*dest == '\0') {
491 return NI_RETCODE_SUCCESS;
492 }
493 dmax--;
494 dest++;
495 src++;
496 }
497 } else {
498 overlap_bumper = dest;
499 while (dmax > 0) {
500 if (src == overlap_bumper) {
501 (void)orig_dmax;
502 *orig_dest = '\0';
503 return NI_RETCODE_FAILURE;
504 }
505 *dest = *src;
506 if (*dest == '\0') {
507 return NI_RETCODE_SUCCESS;
508 }
509 dmax--;
510 dest++;
511 src++;
512 }
513 }
514
515 /*
516 * the entire src must have been copied, if not reset dest
517 * to null the string.
518 */
519 (void)orig_dmax;
520 *orig_dest = '\0';
521 return NI_RETCODE_FAILURE;
522#endif
523}
524
525ni_retcode_t ni_strncpy(char *dest, size_t dmax,
526 const char *src, size_t slen)
527{
528#if defined(_MSC_VER)
529 if(strncpy_s(dest, dmax, src, slen))
530 return NI_RETCODE_FAILURE;
531 else
532 return NI_RETCODE_SUCCESS;
533#else
534 if (slen == 0 && dest && dmax) {
535 *dest = '\0';
536 return NI_RETCODE_SUCCESS;
537 }
538
539 if (!dest || !dmax || !src)
541 size_t orig_dmax;
542 char *orig_dest;
543 const char *overlap_bumper;
544 /* hold base in case src was not copied */
545 orig_dmax = dmax;
546 orig_dest = dest;
547
548 if (dest < src) {
549 overlap_bumper = src;
550
551 while (dmax > 0) {
552 if (dest == overlap_bumper) {
553 (void)orig_dmax;
554 *orig_dest = '\0';
555 return NI_RETCODE_FAILURE;
556 }
557
558 if (slen == 0) {
559 /*
560 * Copying truncated to slen chars. Note that the TR says to
561 * copy slen chars plus the NUL char. We zero the slack.
562 */
563#ifdef SAFECLIB_STR_NULL_SLACK
564 if (dmax > 0x20)
565 memset(dest, 0, dmax);
566 else {
567 while (dmax) {
568 *dest = '\0';
569 dmax--;
570 dest++;
571 }
572 }
573#else
574 *dest = '\0';
575#endif
576 return NI_RETCODE_SUCCESS;
577 }
578
579 *dest = *src;
580 if (*dest == '\0') {
581#ifdef SAFECLIB_STR_NULL_SLACK
582 if (dmax > 0x20)
583 memset(dest, 0, dmax);
584 else {
585 while (dmax) {
586 *dest = '\0';
587 dmax--;
588 dest++;
589 }
590 }
591#endif
592 return NI_RETCODE_SUCCESS;
593 }
594
595 dmax--;
596 slen--;
597 dest++;
598 src++;
599 }
600 } else {
601 overlap_bumper = dest;
602
603 while (dmax > 0) {
604 if (src == overlap_bumper) {
605 (void)orig_dmax;
606 *orig_dest = '\0';
607 return NI_RETCODE_FAILURE;
608 }
609
610 if (slen == 0) {
611 /*
612 * Copying truncated to slen chars. Note that the TR says to
613 * copy slen chars plus the NUL char. We zero the slack.
614 */
615#ifdef SAFECLIB_STR_NULL_SLACK
616 if (dmax > 0x20)
617 memset(dest, 0, dmax);
618 else {
619 while (dmax) {
620 *dest = '\0';
621 dmax--;
622 dest++;
623 }
624 }
625#else
626 *dest = '\0';
627#endif
628 return NI_RETCODE_SUCCESS;
629 }
630
631 *dest = *src;
632 if (*dest == '\0') {
633#ifdef SAFECLIB_STR_NULL_SLACK
634 if (dmax > 0x20)
635 memset(dest, 0, dmax);
636 else {
637 while (dmax) {
638 *dest = '\0';
639 dmax--;
640 dest++;
641 }
642 }
643#endif
644 return NI_RETCODE_SUCCESS;
645 }
646
647 dmax--;
648 slen--;
649 dest++;
650 src++;
651 }
652 }
653
654 /*
655 * the entire src was not copied, so zero the string
656 */
657 (void)orig_dmax;
658 *orig_dest = '\0';
659 return NI_RETCODE_FAILURE;
660#endif
661}
662
663ni_retcode_t ni_strerror(char *dest, size_t dmax, int errnum)
664{
665#if defined(_WIN32)
666 if(strerror_s(dest, dmax, errnum))
667 return NI_RETCODE_FAILURE;
668 else
669 return NI_RETCODE_SUCCESS;
670#else
671 if (!dest || !dmax || (dmax >= (size_t)(-1)))
673#if 1
674 char strerr_buf[256];
675#if defined(_GNU_SOURCE)
676 /* GNU strerror_r returns char* which may point to a static string, not buf */
677 const char *strerr_str = strerror_r(errnum, strerr_buf, sizeof(strerr_buf));
678 ni_strcpy(dest, dmax, strerr_str);
679#else
680 /* POSIX strerror_r fills buf in-place and returns int */
681 (void)strerror_r(errnum, strerr_buf, sizeof(strerr_buf));
682 ni_strcpy(dest, dmax, strerr_buf);
683#endif
684#else
685 /* strerrorlen_s is supported since c11 */
686 size_t len;
687 len = strerrorlen_s(errnum);
688 if (len < dmax) {
689 const char *tmpbuf = strerror(errnum);
690 ni_strcpy(dest, dmax, tmpbuf);
691 } else if (dmax > 3) { /* truncate */
692 const char *tmpbuf = strerror(errnum);
693 ni_strncpy(dest, dmax, tmpbuf, dmax - 4);
694 ni_strcat(dest, dmax, "...");
695 } else {
697 }
698#endif
699
700 return NI_RETCODE_SUCCESS;
701#endif
702}
703
704ni_retcode_t ni_strcat(char *dest, size_t dmax, const char *src)
705{
706#if defined(_MSC_VER)
707 if(strcat_s(dest, dmax, src))
708 return NI_RETCODE_FAILURE;
709 else
710 return NI_RETCODE_SUCCESS;
711#else
712 if (!dest || !dmax || !src)
714
715 size_t orig_dmax;
716 char *orig_dest;
717 const char *overlap_bumper;
718 /* hold base of dest in case src was not copied */
719 orig_dmax = dmax;
720 orig_dest = dest;
721
722 if (dest < src) {
723 overlap_bumper = src;
724 /* Find the end of dest */
725 while (*dest != '\0') {
726 if (dest == overlap_bumper) {
727 (void)orig_dmax;
728 *orig_dest = '\0';
729 return NI_RETCODE_FAILURE;
730 }
731 dest++;
732 dmax--;
733 if (dmax == 0) {
734 (void)orig_dmax;
735 *orig_dest = '\0';
736 return NI_RETCODE_FAILURE;
737 }
738 }
739
740 while (dmax > 0) {
741 if (dest == overlap_bumper) {
742 (void)orig_dmax;
743 *orig_dest = '\0';
744 return NI_RETCODE_FAILURE;
745 }
746
747 *dest = *src;
748 if (*dest == '\0') {
749#ifdef SAFECLIB_STR_NULL_SLACK
750 if (dmax > 0x20)
751 memset(dest, 0, dmax);
752 else {
753 while (dmax) {
754 *dest = '\0';
755 dmax--;
756 dest++;
757 }
758 }
759#endif
760 return NI_RETCODE_SUCCESS;
761 }
762
763 dmax--;
764 dest++;
765 src++;
766 }
767 } else {
768 overlap_bumper = dest;
769
770 /* Find the end of dest */
771 while (*dest != '\0') {
772 /*
773 * NOTE: no need to check for overlap here since src comes first
774 * in memory and we're not incrementing src here.
775 */
776 dest++;
777 dmax--;
778 if (dmax == 0) {
779 (void)orig_dmax;
780 *orig_dest = '\0';
781 return NI_RETCODE_FAILURE;
782 }
783 }
784
785 while (dmax > 0) {
786 if (src == overlap_bumper) {
787 (void)orig_dmax;
788 *orig_dest = '\0';
789 return NI_RETCODE_FAILURE;
790 }
791
792 *dest = *src;
793 if (*dest == '\0') {
794 /* null slack to clear any data */
795#ifdef SAFECLIB_STR_NULL_SLACK
796 if (dmax > 0x20)
797 memset(dest, 0, dmax);
798 else {
799 while (dmax) {
800 *dest = '\0';
801 dmax--;
802 dest++;
803 }
804 }
805#endif
806 return NI_RETCODE_SUCCESS;
807 }
808
809 dmax--;
810 dest++;
811 src++;
812 }
813 }
814
815 /* the entire src was not copied, so null the string */
816 (void)orig_dmax;
817 *orig_dest = '\0';
818 return NI_RETCODE_FAILURE;
819#endif
820}
821
822ni_retcode_t ni_strncat(char *dest, size_t dmax,
823 const char *src, size_t slen)
824{
825 size_t orig_dmax;
826 char *orig_dest;
827 const char *overlap_bumper;
828
829 if (slen == 0 && !dest && !dmax) {
830 /* silent ok as in the msvcrt */
831 return NI_RETCODE_SUCCESS;
832 }
833 if (!dest || !dmax || !src)
835 else if (slen == 0) {
836 /* Special case, analog to msvcrt: when dest is big enough
837 return OK, but clear dest. */
838 (void)dmax;
839 *dest = '\0';
840 return NI_RETCODE_SUCCESS;
841 }
842
843 /* hold base of dest in case src was not copied */
844 orig_dmax = dmax;
845 orig_dest = dest;
846
847 if (dest < src) {
848 overlap_bumper = src;
849
850 /* Find the end of dest */
851 while (*dest != '\0') {
852
853 if (dest == overlap_bumper) {
854 (void)orig_dmax;
855 *orig_dest = '\0';
856 return NI_RETCODE_FAILURE;
857 }
858
859 dest++;
860 dmax--;
861 if (dmax == 0) {
862 (void)orig_dmax;
863 *orig_dest = '\0';
864 return NI_RETCODE_FAILURE;
865 }
866 }
867
868 while (dmax > 0) {
869 if (dest == overlap_bumper) {
870 (void)orig_dmax;
871 *orig_dest = '\0';
872 return NI_RETCODE_FAILURE;
873 }
874
875 /*
876 * Copying truncated before the source null is encountered
877 */
878 if (slen == 0) {
879#ifdef SAFECLIB_STR_NULL_SLACK
880 /* null remaining string */
881 if (dmax > 0x20)
882 memset(dest, 0, dmax);
883 else {
884 while (dmax) {
885 *dest = '\0';
886 dmax--;
887 dest++;
888 }
889 }
890#else
891 *dest = '\0';
892#endif
893 return NI_RETCODE_SUCCESS;
894 }
895
896 *dest = *src;
897 if (*dest == '\0') {
898#ifdef SAFECLIB_STR_NULL_SLACK
899 /* null slack to clear data */
900 if (dmax > 0x20)
901 memset(dest, 0, dmax);
902 else {
903 while (dmax) {
904 *dest = '\0';
905 dmax--;
906 dest++;
907 }
908 }
909#endif
910 return NI_RETCODE_SUCCESS;
911 }
912
913 dmax--;
914 slen--;
915 dest++;
916 src++;
917 }
918 } else {
919 overlap_bumper = dest;
920
921 /* Find the end of dest */
922 while (*dest != '\0') {
923
924 /*
925 * NOTE: no need to check for overlap here since src comes first
926 * in memory and we're not incrementing src here.
927 */
928 dest++;
929 dmax--;
930 if (dmax == 0) {
931 (void)orig_dmax;
932 *orig_dest = '\0';
933 return NI_RETCODE_FAILURE;
934 }
935 }
936
937 while (dmax > 0) {
938 if (src == overlap_bumper) {
939 (void)orig_dmax;
940 *orig_dest = '\0';
941 return NI_RETCODE_FAILURE;
942 }
943
944 /*
945 * Copying truncated
946 */
947 if (slen == 0) {
948#ifdef SAFECLIB_STR_NULL_SLACK
949 /* null remaining string */
950 if (dmax > 0x20)
951 memset(dest, 0, dmax);
952 else {
953 while (dmax) {
954 *dest = '\0';
955 dmax--;
956 dest++;
957 }
958 }
959#else
960 *dest = '\0';
961#endif
962 return NI_RETCODE_SUCCESS;
963 }
964
965 *dest = *src;
966 if (*dest == '\0') {
967#ifdef SAFECLIB_STR_NULL_SLACK
968 /* null slack to clear any data */
969 if (dmax > 0x20)
970 memset(dest, 0, dmax);
971 else {
972 while (dmax) {
973 *dest = '\0';
974 dmax--;
975 dest++;
976 }
977 }
978#endif
979 return NI_RETCODE_SUCCESS;
980 }
981
982 dmax--;
983 slen--;
984 dest++;
985 src++;
986 }
987 }
988
989 /*
990 * the entire src was not copied, so the string will be nulled.
991 */
992
993 (void)orig_dmax;
994 *orig_dest = '\0';
995 return NI_RETCODE_FAILURE;
996}
997
998ni_retcode_t ni_fopen(FILE **fp, const char *filename, const char *mode)
999{
1000#if defined(_MSC_VER)
1001 if(fopen_s(fp, filename, mode))
1002 return NI_RETCODE_FAILURE;
1003 else
1004 return NI_RETCODE_SUCCESS;
1005#else
1006 if (!fp || !filename || !mode)
1008
1009 *fp = fopen(filename, mode);
1010 if (!*fp) {
1011 ni_log(NI_LOG_ERROR, "Failed to open file %s with mode %s\n", filename, mode);
1012 return NI_RETCODE_FAILURE;
1013 }
1014 return NI_RETCODE_SUCCESS;
1015#endif
1016}
1017
1018struct tm* ni_localtime(struct tm *dest, const time_t *src)
1019{
1020#if defined(_WIN32)
1021 if (localtime_s(dest, src))
1022 return NULL;
1023 else
1024 return dest;
1025#else
1026 if (!dest || !src)
1027 return NULL;
1028 if (*src < 0) {
1029 return NULL;
1030 }
1031 return localtime_r(src, dest);
1032#endif
1033}
1034
1035int ni_fscanf(FILE *stream, const char *fmt, ...)
1036{
1037 int ret;
1038#if defined(_MSC_VER)
1039 va_list args;
1040 va_start(args, fmt);
1041 ret = vfscanf_s(stream, fmt, args);
1042 va_end(args);
1043#else
1044 if (!stream || !fmt)
1045 return EOF;
1046 va_list args;
1047 va_start(args, fmt);
1048 ret = vfscanf(stream, fmt, args); // NOLINT(clang-analyzer-valist.Uninitialized) - false positive
1049 va_end(args);
1050#endif
1051 return ret;
1052}
1053
1054int ni_vsprintf(char *dest, const size_t dmax, const char *fmt, va_list args)
1055{
1056#if defined(_MSC_VER)
1057 int ret = vsprintf_s(dest, dmax, fmt, args);
1058 return ret;
1059#else
1060 if (!dest || !dmax || !fmt)
1061 return -1;
1062 // Use vsnprintf on Linux/macOS (which is safe if used correctly)
1063 int ret = vsnprintf(dest, dmax, fmt, args); // NOLINT(clang-analyzer-valist.Uninitialized) - false positive
1064 if (ret < 0) {
1065 // Encoding error occurred
1066 return -1;
1067 } else if ((size_t)ret >= dmax) {
1068 // Buffer was too small (truncation occurred)
1069 char *overrun = dest + dmax - 1; // Point to the last character
1070 *overrun = '\0'; // Ensure null-termination
1071 return -1;
1072 }
1073 return ret;
1074#endif
1075}
1076
1077int ni_sprintf(char *dest, size_t dmax, const char *fmt, ...)
1078{
1079 va_list args;
1080 va_start(args, fmt);
1081 int ret = ni_vsprintf(dest, dmax, fmt, args);
1082 va_end(args);
1083 return ret;
1084}
1085
1086// memory buffer pool operations (one use is for decoder frame buffer pool)
1087// expand buffer pool by a pre-defined size
1089{
1090 int32_t i;
1091 for (i = 0; i < NI_DEC_FRAME_BUF_POOL_SIZE_EXPAND; i++)
1092 {
1093 if( NULL == ni_buf_pool_allocate_buffer(pool, (int)pool->buf_size) )
1094 {
1095 ni_log(NI_LOG_FATAL, "FATAL: Failed to expand ni_buf_pool buffer: %p, "
1096 "current size: %u\n", pool, pool->number_of_buffers);
1097 return NULL;
1098 }
1099 }
1101 return pool->p_free_head;
1102}
1103
1104// get a free memory buffer from the pool
1106{
1107 ni_buf_t *buf = NULL;
1108
1109 if (NULL == p_buffer_pool)
1110 {
1111 return NULL;
1112 }
1113
1114 ni_pthread_mutex_lock(&p_buffer_pool->mutex);
1115 buf = p_buffer_pool->p_free_head;
1116
1117 // find and return a free buffer
1118 if (NULL == buf)
1119 {
1120 ni_log(NI_LOG_INFO, "Expanding dec fme buffer_pool from %u to %u\n",
1121 p_buffer_pool->number_of_buffers,
1122 p_buffer_pool->number_of_buffers +
1124
1125 buf = ni_buf_pool_expand(p_buffer_pool);
1126 if (NULL == buf)
1127 {
1128 ni_pthread_mutex_unlock(&p_buffer_pool->mutex);
1129 return NULL;
1130 }
1131 }
1132
1133 // remove it from free list head; reconnect the linked list, the p_next
1134 // will become the new head now
1135 p_buffer_pool->p_free_head = buf->p_next_buffer;
1136
1137 if (NULL != buf->p_next_buffer)
1138 {
1139 buf->p_next_buffer->p_previous_buffer = NULL;
1140 } else
1141 {
1142 p_buffer_pool->p_free_tail = NULL;
1143 }
1144
1145 // add it to the used list tail
1146 buf->p_previous_buffer = p_buffer_pool->p_used_tail;
1147 buf->p_next_buffer = NULL;
1148
1149 if (NULL != p_buffer_pool->p_used_tail)
1150 {
1151 p_buffer_pool->p_used_tail->p_next_buffer = buf;
1152 } else
1153 {
1154 p_buffer_pool->p_used_head = buf;
1155 }
1156
1157 p_buffer_pool->p_used_tail = buf;
1158
1159 ni_pthread_mutex_unlock(&p_buffer_pool->mutex);
1160
1161 ni_log(NI_LOG_DEBUG, "%s ptr %p buf %p\n", __func__, buf->buf, buf);
1162 return buf;
1163}
1164
1165// return a used memory buffer to the pool
1167{
1168 // p_buffer_pool could be null in case of delayed buffer return after pool
1169 // has been freed
1170 if (!buf)
1171 {
1172 return;
1173 }
1174
1175 ni_log(NI_LOG_DEBUG, "%s ptr %p buf %p\n", __func__, buf->buf, buf);
1176
1177 if (!p_buffer_pool)
1178 {
1179 ni_log(NI_LOG_DEBUG, "%s: pool already freed, self destroy\n", __func__);
1180 ni_aligned_free(buf->buf);
1181 free(buf);
1182 return;
1183 }
1184
1185 ni_pthread_mutex_lock(&p_buffer_pool->mutex);
1186
1187 // remove buf from the used list
1188 if (NULL != buf->p_previous_buffer)
1189 {
1191 } else
1192 {
1193 p_buffer_pool->p_used_head = buf->p_next_buffer;
1194 }
1195
1196 if (NULL != buf->p_next_buffer)
1197 {
1199 } else
1200 {
1201 p_buffer_pool->p_used_tail = buf->p_previous_buffer;
1202 }
1203
1204 // put it on the tail of free buffers list
1205 buf->p_previous_buffer = p_buffer_pool->p_free_tail;
1206 buf->p_next_buffer = NULL;
1207
1208 if (NULL != p_buffer_pool->p_free_tail)
1209 {
1210 p_buffer_pool->p_free_tail->p_next_buffer = buf;
1211 } else
1212 {
1213 p_buffer_pool->p_free_head = buf;
1214 }
1215
1216 p_buffer_pool->p_free_tail = buf;
1217
1218 ni_pthread_mutex_unlock(&p_buffer_pool->mutex);
1219}
1220
1221// allocate a memory buffer and place it in the pool
1223 int buffer_size)
1224{
1225 ni_buf_t *p_buffer = NULL;
1226 void *p_buf = NULL;
1227
1228 if (NULL != p_buffer_pool)
1229 p_buffer = (ni_buf_t *)malloc(sizeof(ni_buf_t));
1230 if (NULL != p_buffer_pool && p_buffer != NULL)
1231 {
1232 // init the struct
1233 memset(p_buffer, 0, sizeof(ni_buf_t));
1234
1235 if (ni_posix_memalign(&p_buf, sysconf(_SC_PAGESIZE), buffer_size))
1236 {
1237 ni_aligned_free(p_buffer);
1238 return NULL;
1239 }
1240 ni_log(NI_LOG_DEBUG, "%s ptr %p buf %p\n", __func__, p_buf, p_buffer);
1241 p_buffer->buf = p_buf;
1242 p_buffer->pool = p_buffer_pool;
1243
1244 // add buffer to the buf pool list
1245 p_buffer->p_prev = NULL;
1246 p_buffer->p_next = NULL;
1247 p_buffer->p_previous_buffer = p_buffer_pool->p_free_tail;
1248
1249 if (p_buffer_pool->p_free_tail != NULL)
1250 {
1251 p_buffer_pool->p_free_tail->p_next_buffer = p_buffer;
1252 } else
1253 {
1254 p_buffer_pool->p_free_head = p_buffer;
1255 }
1256
1257 p_buffer_pool->p_free_tail = p_buffer;
1258 }
1259
1260 return p_buffer;
1261}
1262
1263// decoder frame buffer pool init & free
1265 int32_t number_of_buffers,
1266 int width, int height,
1267 int height_align, int factor)
1268{
1269 int32_t i;
1270 int width_aligned;
1271 int height_aligned;
1272
1273 ni_log2(p_ctx, NI_LOG_TRACE, "%s: enter\n", __func__);
1274
1275 if (QUADRA)
1276 {
1277 width_aligned = ((((width * factor) + 127) / 128) * 128) / factor;
1278 height_aligned = height;
1279 } else
1280 {
1281 width_aligned = ((width + 31) / 32) * 32;
1282 height_aligned = ((height + 7) / 8) * 8;
1283 if (height_align)
1284 {
1285 height_aligned = ((height + 15) / 16) * 16;
1286 }
1287 }
1288
1289 int luma_size = width_aligned * height_aligned * factor;
1290 int chroma_b_size;
1291 int chroma_r_size;
1292 if (QUADRA)
1293 {
1294 int chroma_width_aligned =
1295 ((((width / 2 * factor) + 127) / 128) * 128) / factor;
1296 int chroma_height_aligned = height_aligned / 2;
1297 chroma_b_size = chroma_r_size =
1298 chroma_width_aligned * chroma_height_aligned * factor;
1299 } else
1300 {
1301 chroma_b_size = luma_size / 4;
1302 chroma_r_size = chroma_b_size;
1303 }
1304 uint32_t buffer_size = luma_size + chroma_b_size + chroma_r_size +
1306
1307 // added 2 blocks of 512 bytes buffer space to handle any extra metadata
1308 // retrieval from fw
1309 buffer_size =
1310 ((buffer_size + (NI_MEM_PAGE_ALIGNMENT - 1)) / NI_MEM_PAGE_ALIGNMENT) *
1313
1314 if (p_ctx->dec_fme_buf_pool != NULL)
1315 {
1316 ni_log2(p_ctx, NI_LOG_DEBUG,
1317 "Warning init dec_fme Buf pool already with size %u\n",
1319
1320 if (buffer_size > p_ctx->dec_fme_buf_pool->buf_size)
1321 {
1323 "Warning resolution %dx%d memory buffer size %u "
1324 "> %u (existing buffer size), re-allocating !\n",
1325 width, height, buffer_size,
1326 p_ctx->dec_fme_buf_pool->buf_size);
1327
1329 } else
1330 {
1332 "INFO resolution %dx%d memory buffer size %u <= "
1333 "%u (existing buffer size), continue !\n",
1334 width, height, buffer_size,
1335 p_ctx->dec_fme_buf_pool->buf_size);
1336 return 0;
1337 }
1338 }
1339
1340 p_ctx->dec_fme_buf_pool = (ni_buf_pool_t *)malloc(sizeof(ni_buf_pool_t));
1341 if (p_ctx->dec_fme_buf_pool == NULL)
1342 {
1343 ni_log2(p_ctx, NI_LOG_ERROR, "Error alloc for dec fme buf pool\n");
1344 return -1;
1345 }
1346
1347 // init the struct
1348 memset(p_ctx->dec_fme_buf_pool, 0, sizeof(ni_buf_pool_t));
1350 p_ctx->dec_fme_buf_pool->number_of_buffers = number_of_buffers;
1351
1352 ni_log2(p_ctx, NI_LOG_DEBUG,
1353 "ni_dec_fme_buffer_pool_initialize: entries %d entry size "
1354 "%d\n",
1355 number_of_buffers, buffer_size);
1356
1357 p_ctx->dec_fme_buf_pool->buf_size = buffer_size;
1358 for (i = 0; i < number_of_buffers; i++)
1359 {
1360 if (NULL ==
1361 ni_buf_pool_allocate_buffer(p_ctx->dec_fme_buf_pool, (int)buffer_size))
1362 {
1363 // release everything we have allocated so far and exit
1365 return -1;
1366 }
1367 }
1368
1369 ni_log2(p_ctx, NI_LOG_TRACE, "%s: exit\n", __func__);
1370 return 0;
1371}
1372
1374{
1375 ni_buf_t *buf, *p_next;
1376
1377 if (p_buffer_pool)
1378 {
1379 ni_log(NI_LOG_TRACE, "%s: enter.\n", __func__);
1380
1381 // mark used buf not returned at pool free time by setting pool ptr in used
1382 // buf to NULL, so they will self-destroy when time is due eventually
1383 ni_pthread_mutex_lock(&p_buffer_pool->mutex);
1384 buf = p_buffer_pool->p_used_head;
1385 if (buf)
1386 {
1387 while (buf)
1388 {
1389 p_next = buf->p_next_buffer;
1390 ni_log(NI_LOG_DEBUG, "Release ownership of ptr %p buf %p\n",
1391 buf->buf, buf);
1392 buf->pool = NULL;
1393 buf = p_next;
1394 }
1395 }
1396 ni_pthread_mutex_unlock(&p_buffer_pool->mutex);
1397
1398 buf = p_buffer_pool->p_free_head;
1399 // free all the buffers in the free list
1400 int32_t count_free = 0;
1401 while (buf)
1402 {
1403 p_next = buf->p_next_buffer;
1404 ni_aligned_free(buf->buf);
1405 free(buf);
1406 buf = p_next;
1407 count_free++;
1408 }
1409 if (count_free != p_buffer_pool->number_of_buffers)
1410 {
1411 ni_log(NI_LOG_DEBUG, "%s freed %d != number_of_buffers %u\n",
1412 __func__, count_free, p_buffer_pool->number_of_buffers);
1413 }
1414 else
1415 {
1416 ni_log(NI_LOG_DEBUG, "%s freed all %d buffers\n", __func__,
1417 count_free);
1418 }
1419 free(p_buffer_pool);
1420 }
1421 else
1422 {
1423 ni_log(NI_LOG_INFO, "%s: NOT allocated\n", __func__);
1424 }
1425}
1426
1428{
1429 ni_queue_node_t *buf, *p_next;
1430
1431 ni_log(NI_LOG_TRACE, "%s: enter.\n", __func__);
1432
1433 if (p_buffer_pool)
1434 {
1435 buf = p_buffer_pool->p_free_head;
1436 // free all the buffers in the free and used list
1437 int32_t count = 0;
1438 while (buf)
1439 {
1440 p_next = buf->p_next_buffer;
1441 free(buf);
1442 buf = p_next;
1443 count++;
1444 }
1445
1446 buf = p_buffer_pool->p_used_head;
1447 while (buf)
1448 {
1449 p_next = buf->p_next_buffer;
1450 free(buf);
1451 buf = p_next;
1452 count++;
1453 }
1454
1455 if (count != p_buffer_pool->number_of_buffers)
1456 {
1457 ni_log(NI_LOG_ERROR, "??? freed %d != number_of_buffers %u\n",
1458 count, p_buffer_pool->number_of_buffers);
1459 } else
1460 {
1461 ni_log(NI_LOG_DEBUG, "p_buffer_pool freed %d buffers.\n", count);
1462 }
1463 free(p_buffer_pool);
1464 }
1465 else
1466 {
1467 ni_log(NI_LOG_INFO, "%s: NOT allocated\n", __func__);
1468 }
1469}
1470
1472{
1473 ni_queue_node_t *p_buffer = NULL;
1474
1475 if (NULL != p_buffer_pool)
1476 p_buffer = (ni_queue_node_t *)malloc(sizeof(ni_queue_node_t));
1477 if (NULL != p_buffer_pool && p_buffer != NULL)
1478 {
1479 //Inititalise the struct
1480 memset(p_buffer, 0, sizeof(ni_queue_node_t));
1481 // add buffer to the buf pool list
1482 p_buffer->p_prev = NULL;
1483 p_buffer->p_next = NULL;
1484 p_buffer->p_previous_buffer = p_buffer_pool->p_free_tail;
1485
1486 if (p_buffer_pool->p_free_tail != NULL)
1487 {
1488 p_buffer_pool->p_free_tail->p_next_buffer = p_buffer;
1489 } else
1490 {
1491 p_buffer_pool->p_free_head = p_buffer;
1492 }
1493
1494 p_buffer_pool->p_free_tail = p_buffer;
1495 }
1496
1497 return p_buffer;
1498}
1499
1500int32_t ni_buffer_pool_initialize(ni_session_context_t* p_ctx, int32_t number_of_buffers)
1501{
1502 int i;
1503
1504 ni_log2(p_ctx, NI_LOG_TRACE, "%s: enter\n", __func__);
1505
1506 if (p_ctx->buffer_pool != NULL)
1507 {
1508 ni_log2(p_ctx, NI_LOG_DEBUG, "Warn init Buf pool already with size %u\n",
1510 return -1;
1511 }
1512
1513 p_ctx->buffer_pool = (ni_queue_buffer_pool_t *)malloc(
1514 sizeof(ni_queue_buffer_pool_t));
1515 if (p_ctx->buffer_pool == NULL)
1516 {
1517 ni_log(NI_LOG_ERROR, "Error alloc for pool\n");
1518 return -1;
1519 }
1520
1521 //initialise the struct
1522 memset(p_ctx->buffer_pool, 0, sizeof(ni_queue_buffer_pool_t));
1523 p_ctx->buffer_pool->number_of_buffers = number_of_buffers;
1524 //p_buffer_pool->p_free_head = NULL;
1525 //p_buffer_pool->p_free_tail = NULL;
1526 //p_buffer_pool->p_used_head = NULL;
1527 //p_buffer_pool->p_used_tail = NULL;
1528
1529 for (i = 0; i < number_of_buffers; i++)
1530 {
1531 if (NULL == ni_buffer_pool_allocate_buffer(p_ctx->buffer_pool))
1532 {
1533 //Release everything we have allocated so far and exit
1535 return -1;
1536 }
1537 }
1538
1539 return 0;
1540}
1541
1543{
1544 int i;
1545
1546 for (i = 0; i < 200; i++)
1547 {
1548 if (NULL == ni_buffer_pool_allocate_buffer(pool))
1549 {
1551 "FATAL ERROR: Failed to allocate pool buffer for pool :%p\n",
1552 pool);
1553 return NULL;
1554 }
1555 }
1556 pool->number_of_buffers += 200;
1557 return pool->p_free_head;
1558}
1559
1561{
1562 ni_queue_node_t *buf = NULL;
1563
1564 if (NULL == p_buffer_pool)
1565 {
1566 return NULL;
1567 }
1568
1569 // find and return a free buffer
1570 buf = p_buffer_pool->p_free_head;
1571 if (NULL == buf)
1572 {
1573 ni_log(NI_LOG_INFO, "Expanding p_buffer_pool from %u to %u \n",
1574 p_buffer_pool->number_of_buffers,
1575 p_buffer_pool->number_of_buffers + 200);
1576 buf = ni_buffer_pool_expand(p_buffer_pool);
1577 if (NULL == buf)
1578 {
1579 return NULL; //return null otherwise there will be null derefferencing later
1580 }
1581 }
1582
1583 buf->checkout_timestamp = time(NULL);
1584 // remove it from free list head; reconnect the linked list, the p_next
1585 // will become the new head now
1586 p_buffer_pool->p_free_head = buf->p_next_buffer;
1587
1588 if (NULL != buf->p_next_buffer)
1589 {
1590 buf->p_next_buffer->p_previous_buffer = NULL;
1591 } else
1592 {
1593 p_buffer_pool->p_free_tail = NULL;
1594 }
1595
1596 // add it to the used list tail
1597 buf->p_previous_buffer = p_buffer_pool->p_used_tail;
1598 buf->p_next_buffer = NULL;
1599
1600 if (NULL != p_buffer_pool->p_used_tail)
1601 {
1602 p_buffer_pool->p_used_tail->p_next_buffer = buf;
1603 } else
1604 {
1605 p_buffer_pool->p_used_head = buf;
1606 }
1607
1608 p_buffer_pool->p_used_tail = buf;
1609
1610 return buf;
1611}
1612
1614 ni_queue_buffer_pool_t *p_buffer_pool)
1615{
1616 if (!buf || !p_buffer_pool)
1617 {
1618 return;
1619 }
1620
1621 // remove buf from the used list
1622 if (NULL != buf->p_previous_buffer)
1623 {
1625 } else
1626 {
1627 p_buffer_pool->p_used_head = buf->p_next_buffer;
1628 }
1629
1630 if (NULL != buf->p_next_buffer)
1631 {
1633 } else
1634 {
1635 p_buffer_pool->p_used_tail = buf->p_previous_buffer;
1636 }
1637
1638 // put it on the tail of free buffers list
1639 buf->p_previous_buffer = p_buffer_pool->p_free_tail;
1640 buf->p_next_buffer = NULL;
1641
1642 if (NULL != p_buffer_pool->p_free_tail)
1643 {
1644 p_buffer_pool->p_free_tail->p_next_buffer = buf;
1645 } else
1646 {
1647 p_buffer_pool->p_free_head = buf;
1648 }
1649
1650 p_buffer_pool->p_free_tail = buf;
1651}
1652
1653/*!******************************************************************************
1654 * \brief Get xcoder instance id
1655 *
1656 * \param
1657 *
1658 * \return
1659 *******************************************************************************/
1660int32_t ni_get_frame_index(uint32_t *value)
1661{
1664
1665 return (int32_t)p_value->frame_index;
1666}
1667
1668#ifdef _ANDROID
1669/*!******************************************************************************
1670 * \brief use cmd to search nvme block file
1671 *
1672 * \param[in] p_dev Device name represented as c string. ex: "/dev/nvme0"
1673 * \param[in] search cmd
1674 * \param[in] cmd_ret length
1675 * \param[out] cmd_ret search result for nvme block file
1676 *
1677 * \return On success returns NI_RETCODE_SUCCESS
1678 * On failure returns NI_RETCODE_FAILURE
1679 * On failure returns NI_RETCODE_INVALID_PARAM
1680 *******************************************************************************/
1681static ni_retcode_t ni_search_file(const char *p_dev, char *cmd, char *cmd_ret,
1682 int cmd_ret_len)
1683{
1684 FILE *cmd_fp;
1686
1687 if (access(p_dev, F_OK) == -1)
1688 {
1689 return NI_RETCODE_FAILURE;
1690 }
1691
1692 // look for child block in sysfs mapping tree
1693 cmd_fp = popen(cmd, "r");
1694 if (!cmd_fp)
1695 {
1696 return NI_RETCODE_FAILURE;
1697 }
1698
1699 if (fgets(cmd_ret, cmd_ret_len, cmd_fp) == 0)
1700 {
1702 }
1703
1704 pclose(cmd_fp);
1705 return ret;
1706}
1707#endif
1708/*!******************************************************************************
1709* \brief Remove a string-pattern from a string in-place.
1710*
1711* \param[in,out] main_str Null terminated array of characters to operate upon in-place.
1712* \param[in] pattern Null terminated array of characters to remove from main_str.
1713* Supports special characters '#' and '+' for digit matching and
1714* repeated matching respectively. Note, there is no way to \a escape
1715* the special characters.
1716* \b Example:
1717* char a_str[10] = "aaa123qwe";
1718* char b_str[5] = "a+#+";
1719* remove_substring_pattern(a_str, b_str);
1720* printf("%s\n", a_str);
1721* \b Output:
1722* qwe
1723*
1724* \return If characters removed, returns 1
1725* If no characters removed, returns 0
1726*******************************************************************************/
1727NI_UNUSED static uint32_t remove_substring_pattern(char *main_str, const char *pattern)
1728{
1729 uint32_t i, j; // for loop counters
1730 uint32_t match_length; // length of matching substring
1731 uint32_t matched_chr; // boolean flag for when match is found for a character in the pattern
1732 char char_match_pattern[11] = ""; // what characters to look for when evaluating a character in main_str
1733 uint32_t pattern_matched = 0; // boolean flag for when who pattern match is found
1734 uint32_t pattern_start = 0; // starting index in main_str of substring matching pattern
1735 const char digit_match_pattern[11] = "0123456789"; // set of numeric digits for expansion of special character '#'
1736
1737 // do not accept zero length main_str or pattern
1738 if (!main_str || !pattern || !*main_str || !*pattern)
1739 {
1740 return 0;
1741 }
1742
1743 // iterate over all characters in main_str looking for starting index of matching pattern
1744 for (i = 0; i < strlen(main_str) && !pattern_matched; i++)
1745 {
1746 pattern_matched = 0;
1747 match_length = 0;
1748 // iterate over the characters of the pattern
1749 for (j = 0; j < strlen(pattern); j++)
1750 {
1751 matched_chr = 0;
1752 // set which characters to look for, special cases for special control characters
1753 if (pattern[j] == '+')
1754 {
1755 // immediately fail as entering this branch means either the first character is a '+', or a '+" following a "+'
1756 return 0;
1757 }
1758 else if (pattern[j] == '#')
1759 {
1760 memcpy(char_match_pattern, digit_match_pattern, strlen(digit_match_pattern) + 1);
1761 }
1762 else
1763 {
1764 memcpy(char_match_pattern, pattern + j, 1);
1765 memset(char_match_pattern + 1, 0, 1);
1766 }
1767 // check if char is in match_pattern
1768 if (pattern[j+1] == '+')
1769 {
1770 while (main_str[i + match_length] && strchr(char_match_pattern, (int) main_str[i + match_length]))
1771 {
1772 match_length++;
1773 matched_chr = 1;
1774 }
1775 j++;
1776 }
1777 else if (main_str[i + match_length] && strchr(char_match_pattern, (int) main_str[i + match_length]))
1778 {
1779 match_length++;
1780 matched_chr = 1;
1781 }
1782 // if no matches were found, then this segment is not the sought pattern
1783 if (!matched_chr)
1784 {
1785 break;
1786 }
1787 // if all of pattern has been processed and matched, mark sucessful whole pattern match
1788 else if ((j + 1) >= strlen(pattern))
1789 {
1790 pattern_matched = 1;
1791 pattern_start = i;
1792 }
1793 }
1794 }
1795
1796 // remove sub-string if its pattern was found in main_str
1797 if (pattern_matched)
1798 {
1799 uint32_t orig_main_str_len = (uint32_t)strlen(main_str);
1800 memmove(main_str + pattern_start, main_str + pattern_start + match_length,
1801 strlen(main_str + pattern_start + match_length));
1802 main_str[orig_main_str_len - match_length] = 0;
1803 return 1;
1804 }
1805 else
1806 {
1807 return 0;
1808 }
1809}
1810
1811/*!******************************************************************************
1812 * \brief Find NVMe name space block from device name
1813 * If none is found, assume nvme multi-pathing is disabled and return /dev/nvmeXn1
1814 *
1815 * \param[in] p_dev Device name represented as c string. ex: "/dev/nvme0"
1816 * \param[in] out_buf Output buffer to put NVMe name space block. Must be at least length 21
1817 *
1818 * \return On success returns NI_RETCODE_SUCCESS
1819 * On failure returns NI_RETCODE_FAILURE
1820 *******************************************************************************/
1821ni_retcode_t ni_find_blk_name(const char *p_dev, char *p_out_buf, int out_buf_len)
1822{
1823 if (!p_dev || !p_out_buf)
1824 {
1826 }
1827
1828#ifdef _WIN32
1830 "Automatic namespaceID discovery not supported in Windows. Using "
1831 "guess.\n");
1832 snprintf(p_out_buf, out_buf_len, "%s", p_dev);
1833 return NI_RETCODE_SUCCESS;
1834#elif __APPLE__
1835 /*
1836 Using smartctl /dev/rdisk4 -i | grep 'PCI Vendor' command check if output
1837 contains Quadra. Model number could be duplicated in other devices so
1838 should use PCI Vendor instead but smartctl is not preinstalled on mac
1839 snprintf(command, sizeof(command) - 1,
1840 "smartctl %s -i | grep 'PCI Vendor'", p_dev);
1841 */
1842 FILE *cmd_fp;
1843 char cmd_ret[60] = {0};
1844 char command[128] = {0};
1845 snprintf(command, sizeof(command) - 1,
1846 "diskutil info %s | grep 'Media Name'", p_dev);
1847 ni_log(NI_LOG_TRACE, "Using %s to find quadra device\n", command);
1848 cmd_fp = popen(command, "r");
1849 if (cmd_fp == NULL)
1850 {
1851 ni_log(NI_LOG_ERROR, "Failed to execute %s\n", command);
1852 return NI_RETCODE_FAILURE;
1853 }
1854 if (fgets(cmd_ret, sizeof(cmd_ret) - 1, cmd_fp) == NULL)
1855 {
1856 ni_log(NI_LOG_ERROR, "Failed to read %s output.\n", command);
1857 pclose(cmd_fp);
1858 return NI_RETCODE_FAILURE;
1859 }
1860 pclose(cmd_fp);
1861 ni_log(NI_LOG_TRACE, "Got '%s' from the command\n", cmd_ret);
1862 // if (strcasestr(cmd_ret, "0x1d82") != NULL)
1863 if (strcasestr(cmd_ret, "Quadra") != NULL)
1864 {
1865 snprintf(p_out_buf, out_buf_len, "%s", p_dev);
1866 return NI_RETCODE_SUCCESS;
1867 } else
1868 {
1869 //This is a soft error so trace level is fine
1870 ni_log(NI_LOG_TRACE, "%s is not a quadra device\n", p_dev);
1872 }
1873#elif defined(XCODER_LINUX_VIRTIO_DRIVER_ENABLED)
1874 ni_log(NI_LOG_TRACE, "The device is already considered as a block divice in Linux virtual machine with VirtIO driver.\n");
1875 snprintf(p_out_buf, out_buf_len, "%s", p_dev);
1876 return NI_RETCODE_SUCCESS;
1877#else
1878 ni_log(NI_LOG_DEBUG, "Set NVMe device name equal to NVMe block name\n");
1879 (void)snprintf(p_out_buf, out_buf_len, "%s", p_dev);
1880 return NI_RETCODE_SUCCESS;
1881#endif
1882}
1883
1884/*!******************************************************************************
1885 * \brief check dev name
1886 *
1887 * \param[in] p_dev Device name represented as c string. ex: "/dev/nvmeXnY"
1888 *
1889 * \return On success returns NI_RETCODE_SUCCESS
1890 * On failure returns NI_RETCODE_FAILURE or NI_RETCODE_INVALID_PARAM
1891 *******************************************************************************/
1893{
1894 if (!p_dev)
1895 {
1897 }
1898
1899#ifdef __APPLE__
1900 /*
1901 Using smartctl /dev/rdisk4 -i | grep 'PCI Vendor' command check if output
1902 contains Quadra. Model number could be duplicated in other devices so
1903 should use PCI Vendor instead but smartctl is not preinstalled on mac
1904 snprintf(command, sizeof(command) - 1,
1905 "smartctl %s -i | grep 'PCI Vendor'", p_dev);
1906 */
1907 FILE *cmd_fp;
1908 char cmd_ret[60] = {0};
1909 char command[128] = {0};
1910 snprintf(command, sizeof(command) - 1,
1911 "diskutil info %s | grep 'Media Name'", p_dev);
1912 ni_log(NI_LOG_TRACE, "Using %s to find quadra device\n", command);
1913 cmd_fp = popen(command, "r");
1914 if (cmd_fp == NULL)
1915 {
1916 ni_log(NI_LOG_ERROR, "Failed to execute %s\n", command);
1917 return NI_RETCODE_FAILURE;
1918 }
1919 if (fgets(cmd_ret, sizeof(cmd_ret) - 1, cmd_fp) == NULL)
1920 {
1921 ni_log(NI_LOG_ERROR, "Failed to read %s output.\n", command);
1922 pclose(cmd_fp);
1923 return NI_RETCODE_FAILURE;
1924 }
1925 pclose(cmd_fp);
1926 ni_log(NI_LOG_TRACE, "Got '%s' from the command\n", cmd_ret);
1927 // if (strcasestr(cmd_ret, "0x1d82") != NULL)
1928 if (strcasestr(cmd_ret, "Quadra") != NULL)
1929 {
1930 return NI_RETCODE_SUCCESS;
1931 } else
1932 {
1933 //This is a soft error so trace level is fine
1934 ni_log(NI_LOG_TRACE, "%s is not a quadra device\n", p_dev);
1936 }
1937#endif
1938 return NI_RETCODE_SUCCESS;
1939}
1940
1941/*!******************************************************************************
1942 * \brief Initialize timestamp handling
1943 *
1944 * \param
1945 *
1946 * \return
1947 *******************************************************************************/
1949{
1950 ni_timestamp_table_t *ptemp;
1951
1952 ni_log2(p_ctx, NI_LOG_TRACE, "%s: enter\n", __func__);
1953
1954 if (*pp_table != NULL)
1955 {
1956 ni_log2(p_ctx, NI_LOG_DEBUG, "%s: previously allocated, reallocating now\n",
1957 __func__);
1958 ni_queue_free(&(*pp_table)->list, p_ctx->buffer_pool);
1959 free(*pp_table);
1960 }
1961 ni_log2(p_ctx, NI_LOG_DEBUG, "%s: Malloc\n", __func__);
1962 ptemp = (ni_timestamp_table_t *)malloc(sizeof(ni_timestamp_table_t));
1963 if (!ptemp)
1964 {
1966 }
1967
1968 //initialise the struct
1969 memset(ptemp, 0, sizeof(ni_timestamp_table_t));
1970
1971 ni_queue_init(p_ctx, &ptemp->list,
1972 name); //buffer_pool_initialize runs in here
1973
1974 *pp_table = ptemp;
1975
1976 ni_log2(p_ctx, NI_LOG_DEBUG, "%s: success\n", __func__);
1977
1978 return NI_RETCODE_SUCCESS;
1979}
1980
1981/*!******************************************************************************
1982 * \brief Clean up timestamp handling
1983 *
1984 * \param
1985 *
1986 * \return
1987 *******************************************************************************/
1989 ni_queue_buffer_pool_t *p_buffer_pool)
1990{
1991 ni_log(NI_LOG_TRACE, "%s: enter\n", __func__);
1992
1993 if (!p_table)
1994 {
1995 ni_log(NI_LOG_DEBUG, "%s: no pts table to free\n", __func__);
1996 return NI_RETCODE_SUCCESS;
1997 }
1998 ni_queue_free(&p_table->list, p_buffer_pool);
1999
2000 free(p_table);
2001 ni_log(NI_LOG_DEBUG, "%s: success\n", __func__);
2002
2003 return NI_RETCODE_SUCCESS;
2004}
2005
2006/*!******************************************************************************
2007 * \brief Register timestamp in timestamp/frameoffset table
2008 *
2009 * \param
2010 *
2011 * \return
2012 *******************************************************************************/
2014 ni_timestamp_table_t *p_table,
2015 int64_t timestamp, uint64_t data_info)
2016{
2018
2019 err = ni_queue_push(p_buffer_pool, &p_table->list, data_info, timestamp);
2020
2021 if (NI_RETCODE_SUCCESS == err)
2022 {
2023 ni_log(NI_LOG_DEBUG, "%s: success\n", __func__);
2024 }
2025 else
2026 {
2027 ni_log(NI_LOG_ERROR, "ERROR: %s: FAILED with code %d\n", __func__, err);
2028 }
2029
2030 return err;
2031}
2032
2033/*!******************************************************************************
2034 * \brief Retrieve timestamp from table based on frameoffset info
2035 *
2036 * \param
2037 *
2038 * \return
2039 *******************************************************************************/
2041 uint64_t frame_info, int64_t *p_timestamp,
2042 int32_t threshold, int32_t print,
2043 ni_queue_buffer_pool_t *p_buffer_pool)
2044{
2046
2047 ni_log(NI_LOG_DEBUG, "%s: getting timestamp with frame_info=%" PRId64 "\n",
2048 __func__, frame_info);
2049
2050 err = ni_queue_pop(&p_table->list, frame_info, p_timestamp, threshold,
2051 print, p_buffer_pool);
2052 if (NI_RETCODE_SUCCESS != err)
2053 {
2054 ni_log(NI_LOG_ERROR, "%s: error getting timestamp\n", __func__);
2055 }
2056
2058 "%s: timestamp=%" PRId64 ", frame_info=%" PRId64 ", err=%d\n",
2059 __func__, *p_timestamp, frame_info, err);
2060
2061 return err;
2062}
2063
2065 ni_timestamp_table_t *p_table, uint64_t frame_info, int64_t *p_timestamp,
2066 int32_t threshold, int32_t print, ni_queue_buffer_pool_t *p_buffer_pool)
2067{
2068 return ni_queue_pop_threshold(&p_table->list, frame_info, p_timestamp,
2069 threshold, print, p_buffer_pool);
2070}
2071
2073 ni_timestamp_table_t *dts_list,
2074 ni_queue_buffer_pool_t *p_buffer_pool)
2075{
2076 if (!pts_list || !dts_list)
2077 {
2078 return;
2079 }
2080
2081 // currently, only have dts list.
2082 // if pts list is added back, this should be modified.
2083 ni_queue_t *p_queue = &dts_list->list;
2084 ni_queue_node_t *p = p_queue->p_first;
2085 time_t now = time(NULL);
2086
2087 while (p)
2088 {
2089 if (now - p->checkout_timestamp <= 30)
2090 {
2091 break;
2092 }
2093 if (p_queue->p_first == p_queue->p_last)
2094 {
2095 ni_buffer_pool_return_buffer(p_queue->p_first, p_buffer_pool);
2096 p = p_queue->p_first = p_queue->p_last = NULL;
2097 } else
2098 {
2099 p_queue->p_first = p->p_next;
2100 p->p_next->p_prev = NULL;
2101 ni_buffer_pool_return_buffer(p, p_buffer_pool);
2102
2103 p = p_queue->p_first;
2104 }
2105 p_queue->count--;
2106 }
2107}
2108
2109/*!******************************************************************************
2110 * \brief Retrieve timestamp from table based on frameoffset info
2111 *
2112 * \param
2113 *
2114 * \return
2115 *******************************************************************************/
2117 uint64_t frame_offset, int64_t *p_timestamp,
2118 int32_t threshold,
2119 ni_queue_buffer_pool_t *p_buffer_pool)
2120{
2122
2123 if (!p_table || !p_timestamp || !p_buffer_pool)
2124 {
2126 LRETURN;
2127 }
2128
2129 ni_log(NI_LOG_DEBUG, "%s: getting timestamp with frame_offset=%" PRId64 "\n",
2130 __func__, frame_offset);
2131
2132 err = ni_queue_pop(&p_table->list, frame_offset, p_timestamp, threshold, 0, p_buffer_pool);
2133 if( NI_RETCODE_SUCCESS != err)
2134 {
2135 ni_log(NI_LOG_ERROR, "%s: error getting timestamp\n", __func__);
2136 }
2137
2139 "%s: timestamp=%" PRId64 ", frame_offset=%" PRId64 ", err=%d\n",
2140 __func__, *p_timestamp, frame_offset, err);
2141
2142END:
2143
2144 return err;
2145}
2146
2147/*!******************************************************************************
2148 * \brief Initialize xcoder queue
2149 *
2150 * \param
2151 *
2152 * \return
2153 *******************************************************************************/
2155{
2156 ni_log2(p_ctx, NI_LOG_TRACE, "%s: enter\n", __func__);
2157
2158 if (!p_queue || !name)
2159 {
2161 }
2162 ni_strcpy(p_queue->name, sizeof(p_queue->name), name);
2164
2165 p_queue->p_first = NULL;
2166 p_queue->p_last = NULL;
2167 p_queue->count = 0;
2168
2169 ni_log2(p_ctx, NI_LOG_TRACE, "%s: exit\n", __func__);
2170
2171 return NI_RETCODE_SUCCESS;
2172}
2173
2174/*!******************************************************************************
2175 * \brief Push into xcoder queue
2176 *
2177 * \param
2178 *
2179 * \return
2180 *******************************************************************************/
2182 ni_queue_t *p_queue, uint64_t frame_info,
2183 int64_t timestamp)
2184{
2186 ni_queue_node_t *temp = NULL;
2187
2188 if (!p_queue)
2189 {
2190 ni_log(NI_LOG_ERROR, "%s: error, null pointer parameters passed\n",
2191 __func__);
2193 LRETURN;
2194 }
2195
2196 temp = ni_buffer_pool_get_queue_buffer(p_buffer_pool);
2197
2198 if (!temp)
2199 {
2200 ni_log(NI_LOG_ERROR, "%s: error, cannot allocate memory\n", __func__);
2202 LRETURN;
2203 }
2204
2205 //ni_log(NI_LOG_TRACE, "%s enter: p_first=%"PRId64", p_last=%"PRId64", count=%d\n", __func__, p_queue->p_first, p_queue->p_last, p_queue->count);
2206
2207 temp->timestamp = timestamp;
2208 temp->frame_info = frame_info;
2209
2210 temp->p_next = NULL;
2211
2212 if (!p_queue->p_first)
2213 {
2214 p_queue->p_first = p_queue->p_last = temp;
2215 p_queue->p_first->p_prev = NULL;
2216 p_queue->count++;
2217 } else
2218 {
2219 p_queue->p_last->p_next = temp;
2220 temp->p_prev = p_queue->p_last;
2221 p_queue->p_last = temp;
2222 p_queue->count++;
2223
2224 // Assume the oldest one is useless when reaching this situation.
2225 if (p_queue->count > XCODER_MAX_NUM_QUEUE_ENTRIES)
2226 {
2228 "%s: queue overflow, remove oldest entry, count=%u\n",
2229 __func__, p_queue->count);
2230 //Remove oldest one
2231 temp = p_queue->p_first->p_next;
2232 // free(p_queue->p_first);
2233 ni_buffer_pool_return_buffer(p_queue->p_first, p_buffer_pool);
2234 p_queue->p_first = temp;
2235 p_queue->p_first->p_prev = NULL;
2236 p_queue->count--;
2237 }
2238 }
2239
2240END:
2241
2242 return err;
2243}
2244
2245/*!******************************************************************************
2246 * \brief Pop from the xcoder queue
2247 *
2248 * \param
2249 *
2250 * \return
2251 *******************************************************************************/
2252ni_retcode_t ni_queue_pop(ni_queue_t *p_queue, uint64_t frame_info,
2253 int64_t *p_timestamp, int32_t threshold,
2254 int32_t print, ni_queue_buffer_pool_t *p_buffer_pool)
2255{
2256 (void)threshold;
2257 ni_queue_node_t *temp;
2258 ni_queue_node_t *temp_prev = NULL;
2259 int32_t found = 0;
2260 int32_t count = 0;
2262
2263 if (!p_queue || !p_timestamp)
2264 {
2265 ni_log(NI_LOG_ERROR, "%s: error, null pointer parameters passed\n",
2266 __func__);
2267 retval = NI_RETCODE_INVALID_PARAM;
2268 LRETURN;
2269 }
2270
2271 if (NULL == p_queue->p_first)
2272 {
2273 ni_log(NI_LOG_DEBUG, "%s: queue is empty...\n", __func__);
2274 retval = NI_RETCODE_FAILURE;
2275 LRETURN;
2276 }
2277
2278 if (p_queue->p_first == p_queue->p_last)
2279 {
2281 *p_timestamp = (int64_t)p_queue->p_first->timestamp;
2282 // free(p_queue->p_first);
2283 ni_buffer_pool_return_buffer(p_queue->p_first, p_buffer_pool);
2284
2285 p_queue->p_first = NULL;
2286 p_queue->p_last = NULL;
2287 p_queue->count--;
2288 ni_assert(p_queue->count == 0);
2289 found = 1;
2290 } else
2291 {
2292 temp = p_queue->p_first;
2293 while (temp && !found)
2294 {
2295 if (frame_info < temp->frame_info)
2296 {
2297 if (!temp->p_prev)
2298 {
2299 ni_log(NI_LOG_DEBUG, "First in ts list, return it\n");
2300 *p_timestamp = (int64_t)temp->timestamp;
2301
2302 p_queue->p_first = temp->p_next;
2303 temp->p_next->p_prev = NULL;
2304
2305 ni_buffer_pool_return_buffer(temp, p_buffer_pool);
2306 p_queue->count--;
2307 found = 1;
2308 break;
2309 }
2310
2311 // retrieve from p_prev and delete p_prev !
2312 *p_timestamp = (int64_t)temp->p_prev->timestamp;
2313 temp = temp->p_prev;
2314 temp_prev = temp->p_prev;
2315
2316 if (temp_prev)
2317 {
2318 temp_prev->p_next = temp->p_next;
2319 if (temp->p_next)
2320 {
2321 temp->p_next->p_prev = temp_prev;
2322 } else
2323 {
2324 p_queue->p_last = temp_prev;
2325 }
2326 } else
2327 {
2328 p_queue->p_first = temp->p_next;
2329 temp->p_next->p_prev = NULL;
2330 }
2331 //free(temp);
2332 ni_buffer_pool_return_buffer(temp, p_buffer_pool);
2333 p_queue->count--;
2334 found = 1;
2335 break;
2336 }
2337 temp = temp->p_next;
2338 count++;
2339 }
2340 }
2341
2342 if (print)
2343 {
2344 ni_log(NI_LOG_DEBUG, "%s %s %d iterations ..\n", __func__,
2345 p_queue->name, count);
2346 }
2347
2348 if (!found)
2349 {
2350 retval = NI_RETCODE_FAILURE;
2351 }
2352
2353END:
2354
2355 return retval;
2356}
2357
2358ni_retcode_t ni_queue_pop_threshold(ni_queue_t *p_queue, uint64_t frame_info,
2359 int64_t *p_timestamp, int32_t threshold,
2360 int32_t print,
2361 ni_queue_buffer_pool_t *p_buffer_pool)
2362{
2363 ni_queue_node_t *temp;
2364 ni_queue_node_t *temp_prev = NULL;
2365 int32_t found = 0;
2366 int32_t count = 0;
2368
2369 if (!p_queue || !p_timestamp)
2370 {
2371 ni_log(NI_LOG_ERROR, "%s: error, null pointer parameters passed\n",
2372 __func__);
2373 retval = NI_RETCODE_INVALID_PARAM;
2374 LRETURN;
2375 }
2376
2377 if (p_queue->p_first == NULL)
2378 {
2379 ni_log(NI_LOG_DEBUG, "%s: queue is empty...\n", __func__);
2380 retval = NI_RETCODE_FAILURE;
2381 LRETURN;
2382 }
2383
2384 if (p_queue->p_first == p_queue->p_last)
2385 {
2387 *p_timestamp = (int64_t)p_queue->p_first->timestamp;
2388 // free(p_queue->p_first);
2389 ni_buffer_pool_return_buffer(p_queue->p_first, p_buffer_pool);
2390
2391 p_queue->p_first = NULL;
2392 p_queue->p_last = NULL;
2393 p_queue->count--;
2394 found = 1;
2395 } else
2396 {
2397 temp = p_queue->p_first;
2398 while ((temp) && (!found))
2399 {
2400 if (llabs((int)frame_info - (int)temp->frame_info) <= threshold)
2401 {
2402 *p_timestamp = (int64_t)temp->timestamp;
2403 if (temp_prev)
2404 {
2405 temp_prev->p_next = temp->p_next;
2406 if (temp->p_next)
2407 {
2408 temp->p_next->p_prev = temp_prev;
2409 } else
2410 {
2411 p_queue->p_last = temp_prev;
2412 }
2413 } else
2414 {
2415 p_queue->p_first = temp->p_next;
2416 temp->p_next->p_prev = NULL;
2417 }
2418 // free(temp);
2419 ni_buffer_pool_return_buffer(temp, p_buffer_pool);
2420 p_queue->count--;
2421 found = 1;
2422 break;
2423 }
2424 temp_prev = temp;
2425 temp = temp->p_next;
2426 count++;
2427 }
2428 }
2429
2430 if (print)
2431 {
2432 ni_log(NI_LOG_DEBUG, "%s %s %d iterations ..\n", __func__,
2433 p_queue->name, count);
2434 }
2435
2436 if (!found)
2437 {
2438 retval = NI_RETCODE_FAILURE;
2439 }
2440
2441END:
2442
2443 return retval;
2444}
2445
2446/*!******************************************************************************
2447 * \brief Free xcoder queue
2448 *
2449 * \param
2450 *
2451 * \return
2452 *******************************************************************************/
2454{
2455 ni_queue_node_t *temp = NULL;
2456 ni_queue_node_t *temp_next;
2457 int32_t left = 0;
2458
2459 if (!p_queue)
2460 {
2461 return NI_RETCODE_SUCCESS;
2462 }
2463
2464 ni_log(NI_LOG_DEBUG, "Entries before clean up: \n");
2465 ni_queue_print(p_queue);
2466
2467 temp = p_queue->p_first;
2468 while (temp)
2469 {
2470 temp_next = temp->p_next;
2471 //free(temp);
2472 ni_buffer_pool_return_buffer(temp, p_buffer_pool);
2473 temp = temp_next;
2474 left++;
2475 }
2476 ni_log(NI_LOG_DEBUG, "Entries cleaned up at ni_queue_free: %d, count: %u\n",
2477 left, p_queue->count);
2478
2479 //ni_queue_print(p_queue);
2480
2481 p_queue->count = 0;
2482
2483 return NI_RETCODE_SUCCESS;
2484}
2485
2486/*!******************************************************************************
2487 * \brief Print xcoder queue info
2488 *
2489 * \param
2490 *
2491 * \return
2492 *******************************************************************************/
2494{
2495 ni_queue_node_t *temp = NULL;
2496 char buff[20] = {0};
2497
2498 if (!p_queue)
2499 {
2500 return NI_RETCODE_SUCCESS;
2501 }
2502
2503 ni_log(NI_LOG_DEBUG, "Queue [%s] Count: %u\n", p_queue->name,
2504 p_queue->count);
2505
2506 ni_log(NI_LOG_DEBUG, "\nForward:\n");
2507
2508 temp = p_queue->p_first;
2509
2510 ni_log(NI_LOG_DEBUG, "%s enter: p_first=%p, p_last=%p, count=%u, temp=%p\n",
2511 __func__, p_queue->p_first, p_queue->p_last, p_queue->count, temp);
2512
2513 // ni_log(NI_LOG_TRACE, "%s enter: p_first=%" PRId64 ", p_last=%" PRId64 ", count=%d, temp=%" PRId64 "\n", __func__, p_queue->p_first, p_queue->p_last, p_queue->count, temp);
2514
2515 struct tm *ltime = NULL;
2516 struct tm temp_time;
2517 while (temp)
2518 {
2519 ltime = ni_localtime(&temp_time, &temp->checkout_timestamp);
2520 if (ltime)
2521 {
2522 (void)strftime(buff, 20, "%Y-%m-%d %H:%M:%S", ltime);
2523 ni_log(NI_LOG_TRACE, " %s [%" PRId64 ", %" PRId64 "]", buff,
2524 temp->timestamp, temp->frame_info);
2525 }
2526 temp = temp->p_next;
2527 }
2528
2529 ni_log(NI_LOG_DEBUG, "\nBackward:");
2530
2531 temp = p_queue->p_last;
2532 while (temp)
2533 {
2534 ni_log(NI_LOG_TRACE, " [%" PRId64 ", %" PRId64 "]\n", temp->timestamp,
2535 temp->frame_info);
2536 temp = temp->p_prev;
2537 }
2538 ni_log(NI_LOG_DEBUG, "\n");
2539
2540 return NI_RETCODE_SUCCESS;
2541}
2542
2543/*!******************************************************************************
2544 * \brief Convert string to boolean
2545 *
2546 * \param
2547 *
2548 * \return
2549 *******************************************************************************/
2550int32_t ni_atobool(const char *p_str, bool *b_error)
2551{
2552 if (!strcmp(p_str, "1") || !strcmp(p_str, "true") || !strcmp(p_str, "yes"))
2553 {
2554 return 1;
2555 }
2556
2557 if (!strcmp(p_str, "0") || !strcmp(p_str, "false") || !strcmp(p_str, "no"))
2558 {
2559 return 0;
2560 }
2561
2562 *b_error = true;
2563 return 0;
2564}
2565
2566/*!******************************************************************************
2567 * \brief Safely convert a decimal string to a 32-bit integer with full
2568 * validation. Trailing whitespace is tolerated.
2569 *
2570 * \param str Null-terminated string to convert (base 10)
2571 * \param out_val Pointer to store the converted value on success
2572 *
2573 * \return NI_RETCODE_SUCCESS on success,
2574 * NI_RETCODE_INVALID_PARAM if str is NULL/empty, contains
2575 * non-numeric characters, or the value overflows int32_t
2576 *******************************************************************************/
2577ni_retcode_t ni_strtoi(const char *str, int32_t *out_val)
2578{
2579 char *end;
2580 long v;
2581
2582 if (!str || !out_val || *str == '\0')
2584
2585 errno = 0;
2586 v = strtol(str, &end, 10);
2587
2588 if (end == str || errno == ERANGE ||
2589 v < INT32_MIN || v > INT32_MAX)
2591
2592 while (*end != '\0' && isspace((unsigned char)*end))
2593 end++;
2594 if (*end != '\0')
2596
2597 *out_val = (int32_t)v;
2598 return NI_RETCODE_SUCCESS;
2599}
2600
2601/*!******************************************************************************
2602 * \brief Safely convert a decimal string to a double with full validation.
2603 * Trailing whitespace is tolerated.
2604 *
2605 * \param str Null-terminated string to convert
2606 * \param out_val Pointer to store the converted value on success
2607 *
2608 * \return NI_RETCODE_SUCCESS on success,
2609 * NI_RETCODE_INVALID_PARAM if str is NULL/empty, contains
2610 * non-numeric characters, or the value overflows double range
2611 *******************************************************************************/
2612ni_retcode_t ni_strtod_val(const char *str, double *out_val)
2613{
2614 char *end;
2615
2616 if (!str || !out_val || *str == '\0')
2618
2619 errno = 0;
2620 *out_val = strtod(str, &end);
2621
2622 if (end == str || errno == ERANGE)
2624
2625 while (*end != '\0' && isspace((unsigned char)*end))
2626 end++;
2627 if (*end != '\0')
2629
2630 return NI_RETCODE_SUCCESS;
2631}
2632
2633int32_t ni_atoi(const char *p_str, bool *b_error)
2634{
2635 char *end;
2636 int32_t v = (int32_t)strtol(p_str, &end, 0);
2637
2638 if (end == p_str || *end != '\0')
2639 {
2640 *b_error = true;
2641 }
2642
2643 return v;
2644}
2645
2646/*!******************************************************************************
2647 * \brief Convert string to floating
2648 *
2649 * \param
2650 *
2651 * \return
2652 *******************************************************************************/
2653double ni_atof(const char *p_str, bool *b_error)
2654{
2655 char *end;
2656 double v = strtod(p_str, &end);
2657
2658 if (end == p_str || *end != '\0')
2659 {
2660 *b_error = true;
2661 }
2662
2663 return v;
2664}
2665
2666/*!******************************************************************************
2667 * \brief Parse name
2668 *
2669 * \param
2670 *
2671 * \return
2672 *******************************************************************************/
2673int32_t ni_parse_name(const char *arg, const char *const *names, bool *b_error)
2674{
2675 int32_t i;
2676 for (i = 0; names[i]; i++)
2677 {
2678 if (!strcmp(arg, names[i]))
2679 {
2680 return i;
2681 }
2682 }
2683
2684 return ni_atoi(arg, b_error);
2685}
2686
2687/*!******************************************************************************
2688 * \brief Get system time for log
2689 *
2690 * \param
2691 *
2692 * \return
2693 *******************************************************************************/
2694uint64_t ni_get_utime(void)
2695{
2696 struct timeval tv;
2697 (void)ni_gettimeofday(&tv, NULL);
2698 return (tv.tv_sec * 1000000LL + tv.tv_usec);
2699}
2700
2701uint64_t ni_gettime_ns(void)
2702{
2703#ifdef _WIN32
2704 LARGE_INTEGER frequency;
2705 LARGE_INTEGER count;
2706 uint64_t time_sec, time_nsec;
2707
2708 // Get frequency firstly
2709 QueryPerformanceFrequency(&frequency);
2710
2711 QueryPerformanceCounter(&count);
2712
2713 time_sec = count.QuadPart / frequency.QuadPart;
2714 time_nsec = (count.QuadPart - time_sec * frequency.QuadPart) *
2715 1000000000LL / frequency.QuadPart;
2716
2717 return (time_sec * 1000000000LL + time_nsec);
2718#else
2719 struct timespec ts;
2720 clock_gettime(CLOCK_REALTIME, &ts);
2721 return ts.tv_sec * 1000000000LL + ts.tv_nsec;
2722#endif
2723}
2724
2725// Netint HW YUV420p data layout related utility functions
2726
2727/*!*****************************************************************************
2728 * \brief Get dimension information of Netint HW YUV420p frame to be sent
2729 * to encoder for encoding. Caller usually retrieves this info and
2730 * uses it in the call to ni_encoder_frame_buffer_alloc for buffer
2731 * allocation.
2732 *
2733 * \param[in] width source YUV frame width
2734 * \param[in] height source YUV frame height
2735 * \param[in] factor 1 for 8 bit, 2 for 10 bit
2736 * \param[in] is_semiplanar 1 for semiplanar frame, 0 otherwise
2737 * \param[out] plane_stride size (in bytes) of each plane width
2738 * \param[out] plane_height size of each plane height
2739 *
2740 * \return Y/Cb/Cr stride and height info
2741 *
2742 ******************************************************************************/
2743void ni_get_hw_yuv420p_dim(int width, int height, int factor,
2744 int is_semiplanar,
2745 int plane_stride[NI_MAX_NUM_DATA_POINTERS],
2746 int plane_height[NI_MAX_NUM_DATA_POINTERS])
2747{
2748 // strides are multiples of 128
2749 if (width < NI_MIN_WIDTH)
2750 {
2751 plane_stride[0] = ((NI_MIN_WIDTH * factor + 127) / 128) * 128;
2752 plane_stride[1] =
2753 (((NI_MIN_WIDTH / (is_semiplanar ? 1 : 2) * factor) + 127) /
2754 128) *
2755 128;
2756 plane_stride[2] = (is_semiplanar ? 0 : plane_stride[1]);
2757 } else
2758 {
2759 width = ((width + 1) / 2) * 2; // pad odd resolution
2760 plane_stride[0] = ((width * factor + 127) / 128) * 128;
2761 plane_stride[1] =
2762 (((width / (is_semiplanar ? 1 : 2) * factor) + 127) / 128) *
2763 128;
2764 plane_stride[2] = (is_semiplanar ? 0 : plane_stride[1]);
2765 }
2766
2767 // height (in lines) just needs to be even number
2768 if (height < NI_MIN_HEIGHT)
2769 {
2770 plane_height[0] = NI_MIN_HEIGHT;
2771 } else
2772 {
2773 plane_height[0] = ((height + 1) / 2) * 2;
2774 }
2775 plane_height[1] = plane_height[2] = plane_height[0] / 2;
2776}
2777
2778/*!*****************************************************************************
2779 * \brief Get dimension information of frame to be sent
2780 * to encoder for encoding. Caller usually retrieves this info and
2781 * uses it in the call to ni_encoder_frame_buffer_alloc for buffer
2782 * allocation.
2783 * The returned stride and height info will take alignment
2784 * requirements into account.
2785 *
2786 * \param[in] width source frame width
2787 * \param[in] height source frame height
2788 * \param[in] pix_fmt ni pixel format
2789 * \param[out] plane_stride size (in bytes) of each plane width
2790 * \param[out] plane_height size of each plane height
2791 *
2792 * \return stride and height info
2793 *
2794 ******************************************************************************/
2795void ni_get_frame_dim(int width, int height,
2796 ni_pix_fmt_t pix_fmt,
2797 int plane_stride[NI_MAX_NUM_DATA_POINTERS],
2798 int plane_height[NI_MAX_NUM_DATA_POINTERS])
2799{
2800 plane_height[0] = ((height + 1) / 2) * 2;
2801 plane_height[1] = plane_height[2] = plane_height[0] / 2;
2802
2803 switch (pix_fmt)
2804 {
2805 /* 8-bit YUV420 planar */
2806 case NI_PIX_FMT_YUV420P:
2807 plane_stride[0] = NI_VPU_ALIGN128(width);
2808 plane_stride[1] = NI_VPU_ALIGN128((width / 2));
2809 plane_stride[2] = plane_stride[1];
2810 plane_stride[3] = 0;
2811 break;
2812 /* 10-bit YUV420 planar, little-endian, least significant bits */
2814 plane_stride[0] = NI_VPU_ALIGN128(width * 2);
2815 plane_stride[1] = NI_VPU_ALIGN128(width);
2816 plane_stride[2] = plane_stride[1];
2817 plane_stride[3] = 0;
2818 break;
2819 /* 8-bit YUV420 semi-planar */
2820 case NI_PIX_FMT_NV12:
2821 plane_stride[0] = NI_VPU_ALIGN128(width);
2822 plane_stride[1] = plane_stride[0];
2823 plane_stride[2] = 0;
2824 plane_stride[3] = 0;
2825 break;
2826 /* 8-bit yuv422 semi-planar */
2827 case NI_PIX_FMT_NV16:
2828 plane_stride[0] = NI_VPU_ALIGN64(width);
2829 plane_stride[1] = plane_stride[0];
2830 plane_stride[2] = 0;
2831 plane_stride[3] = 0;
2832 break;
2833 /*8-bit yuv422 planar */
2834 case NI_PIX_FMT_YUYV422:
2835 case NI_PIX_FMT_UYVY422:
2836 plane_stride[0] = NI_VPU_ALIGN16(width) * 2;
2837 plane_stride[1] = 0;
2838 plane_stride[2] = 0;
2839 plane_stride[3] = 0;
2840 break;
2841 /* 10-bit YUV420 semi-planar, little endian, most significant bits */
2842 case NI_PIX_FMT_P010LE:
2843 plane_stride[0] = NI_VPU_ALIGN128(width * 2);
2844 plane_stride[1] = plane_stride[0];
2845 plane_stride[2] = 0;
2846 plane_stride[3] = 0;
2847 break;
2848 /* 32-bit RGBA packed */
2849 case NI_PIX_FMT_ARGB:
2850 case NI_PIX_FMT_ABGR:
2851 case NI_PIX_FMT_RGBA:
2852 case NI_PIX_FMT_BGRA:
2853 case NI_PIX_FMT_BGR0:
2854 plane_height[1] = plane_height[2] = 0;
2855
2856 plane_stride[0] = NI_VPU_ALIGN16(width) * 4;
2857 plane_stride[1] = 0;
2858 plane_stride[2] = 0;
2859 plane_stride[3] = 0;
2860 break;
2861 default:
2862 break;
2863 }
2864
2865}
2866
2867/*!*****************************************************************************
2868 * \brief Get dimension information of frame to be sent
2869 * to encoder for encoding. Caller usually retrieves this info and
2870 * uses it in the call to ni_encoder_frame_buffer_alloc for buffer
2871 * allocation.
2872 * The returned stride and height info will take into account both min
2873 * resolution and alignment requirements.
2874 *
2875 * \param[in] width source frame width
2876 * \param[in] height source frame height
2877 * \param[in] pix_fmt ni pixel format
2878 * \param[out] plane_stride size (in bytes) of each plane width
2879 * \param[out] plane_height size of each plane height
2880 *
2881 * \return stride and height info
2882 *
2883 ******************************************************************************/
2884void ni_get_min_frame_dim(int width, int height,
2885 ni_pix_fmt_t pix_fmt,
2886 int plane_stride[NI_MAX_NUM_DATA_POINTERS],
2887 int plane_height[NI_MAX_NUM_DATA_POINTERS])
2888{
2889
2890 if (height < NI_MIN_HEIGHT)
2891 {
2892 height = NI_MIN_HEIGHT;
2893 }
2894 if (width < NI_MIN_WIDTH)
2895 {
2896 width = NI_MIN_WIDTH;
2897 }
2898 else
2899 {
2900 width = ((width + 1) / 2) * 2; // pad odd resolution
2901 }
2902
2903 ni_get_frame_dim(width, height, pix_fmt, plane_stride, plane_height);
2904
2906 "%s dst_stride %d/%d/%d height %d/%d/%d pix_fmt %d\n",
2907 __func__, plane_stride[0], plane_stride[1], plane_stride[2],
2908 plane_height[0], plane_height[1], plane_height[2], pix_fmt);
2909}
2910
2911/*!*****************************************************************************
2912 * \brief Copy RGBA or YUV data to Netint HW frame layout to be sent
2913 * to encoder for encoding. Data buffer (dst) is usually allocated by
2914 * ni_encoder_frame_buffer_alloc.
2915 *
2916 * \param[out] p_dst pointers to which data is copied
2917 * \param[in] p_src pointers from which data is copied
2918 * \param[in] width source frame width
2919 * \param[in] height source frame height
2920 * \param[in] factor 1 for 8 bit, 2 for 10 bit
2921 * \param[in] is_semiplanar non-0 for semiplanar frame, 0 otherwise
2922 * \param[in] conf_win_right right offset of conformance window
2923 * \param[in] dst_stride size (in bytes) of each plane width in destination
2924 * \param[in] dst_height size of each plane height in destination
2925 * \param[in] src_stride size (in bytes) of each plane width in source
2926 * \param[in] src_height size of each plane height in source
2927 * \param[in] i index to plane to be copied
2928 *
2929 * \return copied data
2930 *
2931 ******************************************************************************/
2933 uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS],
2934 int frame_width, int frame_height, int factor,
2935 int is_semiplanar, int conf_win_right,
2936 int dst_stride[NI_MAX_NUM_DATA_POINTERS],
2937 int dst_height[NI_MAX_NUM_DATA_POINTERS],
2938 int src_stride[NI_MAX_NUM_DATA_POINTERS],
2939 int src_height[NI_MAX_NUM_DATA_POINTERS],
2940 int i)
2941{
2942 (void)frame_height;
2943 if (i >= NI_MAX_NUM_DATA_POINTERS)
2944 {
2945 ni_log(NI_LOG_ERROR, "%s: error, invalid plane index %d\n", __func__,
2946 i);
2947 return;
2948 }
2949 if (p_dst[i] == p_src[i])
2950 {
2951 ni_log(NI_LOG_DEBUG, "%s: src and dst identical, return\n", __func__);
2952 return;
2953 }
2954
2955 int height =
2956 (src_height[i] < dst_height[i] ? src_height[i] : dst_height[i]);
2957 uint8_t *dst = p_dst[i];
2958 const uint8_t *src = (const uint8_t *)p_src[i];
2959
2960 // width padding length in bytes, if needed
2961 int pad_len_bytes;
2962
2963 if (0 == i || is_semiplanar) // Y
2964 {
2965 pad_len_bytes = dst_stride[i] - frame_width * factor;
2966 }
2967 else
2968 {
2969 // U/V share the same padding length
2970 pad_len_bytes = dst_stride[i] - frame_width / 2 * factor;
2971 }
2972
2973 if (0 == pad_len_bytes && conf_win_right > 0)
2974 {
2975 if (0 == i) // Y
2976 {
2977 pad_len_bytes = conf_win_right * factor;
2978 }
2979 else
2980 {
2981 // U/V share the same padding length
2982 pad_len_bytes = conf_win_right * factor / 2;
2983 }
2984 }
2985
2987 "%s plane %d stride padding: %d pixel (%d bytes), copy height: "
2988 "%d.\n",
2989 __func__, i, pad_len_bytes / factor, pad_len_bytes,
2990 height);
2991
2992 for (; height > 0; height--)
2993 {
2994 memcpy(dst, src,
2995 (src_stride[i] < dst_stride[i] ? src_stride[i] : dst_stride[i]));
2996 dst += dst_stride[i];
2997
2998 // dst is now at the line end
2999 if (pad_len_bytes)
3000 {
3001 // repeat last pixel
3002 if (factor > 1)
3003 {
3004 // for 10 bit it's 2 bytes
3005 int j;
3006 uint8_t *tmp_dst = dst - pad_len_bytes;
3007 for (j = 0; j < pad_len_bytes / factor; j++)
3008 {
3009 memcpy(tmp_dst, dst - pad_len_bytes - factor, factor);
3010 tmp_dst += factor;
3011 }
3012 }
3013 else
3014 {
3015 memset(dst - pad_len_bytes, *(dst - pad_len_bytes - 1),
3016 pad_len_bytes);
3017 }
3018 }
3019 src += src_stride[i];
3020 }
3021
3022 // height padding/cropping if needed
3023 int padding_height = dst_height[i] - src_height[i];
3024 if (padding_height > 0)
3025 {
3026 ni_log(NI_LOG_DEBUG, "%s plane %d padding height: %d\n", __func__,
3027 i, padding_height);
3028 src = dst - dst_stride[i];
3029 for (; padding_height > 0; padding_height--)
3030 {
3031 memcpy(dst, src, dst_stride[i]);
3032 dst += dst_stride[i];
3033 }
3034 }
3035}
3036/*!*****************************************************************************
3037 * \brief Copy YUV data to Netint HW YUV420p frame layout to be sent
3038 * to encoder for encoding. Data buffer (dst) is usually allocated by
3039 * ni_encoder_frame_buffer_alloc.
3040 *
3041 * \param[out] p_dst pointers of Y/Cb/Cr to which data is copied
3042 * \param[in] p_src pointers of Y/Cb/Cr from which data is copied
3043 * \param[in] width source YUV frame width
3044 * \param[in] height source YUV frame height
3045 * \param[in] factor 1 for 8 bit, 2 for 10 bit
3046 * \param[in] is_semiplanar non-0 for semiplanar frame, 0 otherwise
3047 * \param[in] conf_win_right right offset of conformance window
3048 * \param[in] dst_stride size (in bytes) of each plane width in destination
3049 * \param[in] dst_height size of each plane height in destination
3050 * \param[in] src_stride size (in bytes) of each plane width in source
3051 * \param[in] src_height size of each plane height in source
3052 *
3053 * \return Y/Cb/Cr data
3054 *
3055 ******************************************************************************/
3057 uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS],
3058 int frame_width, int frame_height, int factor,
3059 int is_semiplanar, int conf_win_right,
3060 int dst_stride[NI_MAX_NUM_DATA_POINTERS],
3061 int dst_height[NI_MAX_NUM_DATA_POINTERS],
3062 int src_stride[NI_MAX_NUM_DATA_POINTERS],
3063 int src_height[NI_MAX_NUM_DATA_POINTERS])
3064{
3066 "%s dst_stride %d/%d/%d src_stride %d/%d/%d dst_height "
3067 "%d/%d/%d src_height %d/%d/%d\n",
3068 __func__, dst_stride[0], dst_stride[1], dst_stride[2], src_stride[0],
3069 src_stride[1], src_stride[2], dst_height[0], dst_height[1],
3070 dst_height[2], src_height[0], src_height[1], src_height[2]);
3071
3072 int i;
3073
3074 for (i = 0; i < NI_MAX_NUM_DATA_POINTERS - 1; i++)
3075 {
3076 ni_copy_plane_data(p_dst, p_src, frame_width, frame_height, factor,
3077 is_semiplanar, conf_win_right, dst_stride,
3078 dst_height, src_stride, src_height, i);
3079 }
3080}
3081
3082/*!*****************************************************************************
3083 * \brief Copy RGBA or YUV data to Netint HW frame layout to be sent
3084 * to encoder for encoding. Data buffer (dst) is usually allocated by
3085 * ni_encoder_frame_buffer_alloc.
3086 *
3087 * \param[out] p_dst pointers to which data is copied
3088 * \param[in] p_src pointers from which data is copied
3089 * \param[in] width source frame width
3090 * \param[in] height source frame height
3091 * \param[in] factor 1 for 8 bit, 2 for 10 bit
3092 * \param[in] pix_fmt pixel format to distinguish between planar types and/or components
3093 * \param[in] conf_win_right right offset of conformance window
3094 * \param[in] dst_stride size (in bytes) of each plane width in destination
3095 * \param[in] dst_height size of each plane height in destination
3096 * \param[in] src_stride size (in bytes) of each plane width in source
3097 * \param[in] src_height size of each plane height in source
3098 *
3099 * \return copied data
3100 *
3101 ******************************************************************************/
3103 uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS],
3104 int frame_width, int frame_height,
3105 int factor, ni_pix_fmt_t pix_fmt,
3106 int conf_win_right,
3107 int dst_stride[NI_MAX_NUM_DATA_POINTERS],
3108 int dst_height[NI_MAX_NUM_DATA_POINTERS],
3109 int src_stride[NI_MAX_NUM_DATA_POINTERS],
3110 int src_height[NI_MAX_NUM_DATA_POINTERS])
3111{
3113 "%s frame_width %d frame_height %d factor %d conf_win_right %d "
3114 "dst_stride %d/%d/%d src_stride %d/%d/%d dst_height "
3115 "%d/%d/%d src_height %d/%d/%d pix_fmt %d\n",
3116 __func__, frame_width, frame_height, factor, conf_win_right,
3117 dst_stride[0], dst_stride[1], dst_stride[2], src_stride[0],
3118 src_stride[1], src_stride[2], dst_height[0], dst_height[1],
3119 dst_height[2], src_height[0], src_height[1], src_height[2],
3120 pix_fmt);
3121
3122 int is_rgba = 0;
3123 int is_semiplanar = 0;
3124 switch (pix_fmt)
3125 {
3126 case NI_PIX_FMT_NV12:
3127 case NI_PIX_FMT_P010LE:
3128 is_semiplanar = 1;
3129 break;
3130 case NI_PIX_FMT_ARGB:
3131 case NI_PIX_FMT_ABGR:
3132 case NI_PIX_FMT_RGBA:
3133 case NI_PIX_FMT_BGRA:
3134 is_rgba = 1;
3135 break;
3136 default:
3137 break;
3138 }
3139
3140 if (is_rgba)
3141 {
3142 ni_copy_plane_data(p_dst, p_src,
3143 frame_width, frame_height, 4,
3144 is_semiplanar, conf_win_right,
3145 dst_stride, dst_height,
3146 src_stride, src_height,
3147 0); // just one plane for rgba
3148 }
3149 else
3150 {
3151 ni_copy_hw_yuv420p(p_dst, p_src, frame_width, frame_height, factor,
3152 is_semiplanar, conf_win_right, dst_stride,
3153 dst_height, src_stride, src_height);
3154 }
3155}
3156
3157/*!*****************************************************************************
3158 * \brief Copy yuv444p data to yuv420p frame layout to be sent
3159 * to encoder for encoding. Data buffer (dst) is usually allocated by
3160 * ni_encoder_frame_buffer_alloc.
3161 *
3162 * \param[out] p_dst0 pointers of Y/Cb/Cr as yuv420p output0
3163 * \param[out] p_dst1 pointers of Y/Cb/Cr as yuv420p output1
3164 * \param[in] p_src pointers of Y/Cb/Cr as yuv444p intput
3165 * \param[in] width source YUV frame width
3166 * \param[in] height source YUV frame height
3167 * \param[in] factor 1 for 8 bit, 2 for 10 bit
3168 * \param[in] mode 0 for
3169 * out0 is Y+1/2V, with the original input as the out0, 1/4V
3170 * copy to data[1] 1/4V copy to data[2]
3171 * out1 is U+1/2V, U copy to data[0], 1/4V copy to data[1], 1/4V
3172 * copy to data[2]
3173 * mode 1 for
3174 * out0 is Y+1/2u+1/2v, with the original input as the output0,
3175 * 1/4U copy to data[1] 1/4V copy to data[2]
3176 * out1 is (1/2U+1/2V)+1/4U+1/4V, 1/2U & 1/2V copy to data[0],
3177 * 1/4U copy to data[1], 1/4V copy to data[2]
3178 *
3179 * \return Y/Cb/Cr data
3180 *
3181 ******************************************************************************/
3183 uint8_t *p_dst1[NI_MAX_NUM_DATA_POINTERS],
3184 uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS],
3185 int frame_width, int frame_height,
3186 int factor, int mode)
3187{
3188 int i, j;
3189 int y_444p_linesize = frame_width * factor;
3190 int uv_444p_linesize = y_444p_linesize;
3191 int y_420p_linesize = NI_VPU_ALIGN128(y_444p_linesize);
3192 int uv_420p_linesize = NI_VPU_ALIGN128(uv_444p_linesize / 2);
3193
3194 // return to avoid self copy
3195 if (p_dst0[0] == p_dst1[0] && p_dst0[1] == p_dst1[1] &&
3196 p_dst0[2] == p_dst1[2])
3197 {
3198 ni_log(NI_LOG_DEBUG, "%s: src and dst identical, return\n", __func__);
3199 return;
3200 }
3201
3202 // Y component
3203 for (i = 0; i < frame_height; i++)
3204 {
3205 memcpy(&p_dst0[0][(ptrdiff_t)i * y_420p_linesize], &p_src[0][(ptrdiff_t)i * y_444p_linesize],
3206 y_444p_linesize);
3207 }
3208
3209 if (mode == 0)
3210 {
3211 // out0 data[0]: Y data[1]: 0.25V data[2]: 0.25V
3212 // out1 data[0]: U data[1]: 0.25V data[2]: 0.25V
3213 // U component
3214 for (i = 0; i < frame_height; i++)
3215 {
3216 memcpy(&p_dst1[0][(ptrdiff_t)i * y_420p_linesize],
3217 &p_src[1][(ptrdiff_t)i * y_444p_linesize], y_444p_linesize);
3218 }
3219
3220 for (i = 0; i < frame_height / 2; i++)
3221 {
3222 for (j = 0; j < frame_width * factor / 2; j += factor)
3223 {
3224 // V component
3225 // even line
3226 memcpy(&p_dst0[1][i * uv_420p_linesize + j],
3227 &p_src[2][2 * i * uv_444p_linesize + 2 * j],
3228 factor);
3229 memcpy(&p_dst0[2][i * uv_420p_linesize + j],
3230 &p_src[2][2 * i * uv_444p_linesize + (2 * j + factor)],
3231 factor);
3232 // odd line
3233 memcpy(&p_dst1[1][i * uv_420p_linesize + j],
3234 &p_src[2][(2 * i + 1) * uv_444p_linesize + 2 * j],
3235 factor);
3236 memcpy(&p_dst1[2][i * uv_420p_linesize + j],
3237 &p_src[2][(2 * i + 1) * uv_444p_linesize + (2 * j + factor)],
3238 factor);
3239 }
3240 }
3241 } else
3242 {
3243 // out0 data[0]: Y data[1]: 0.25U data[2]: 0.25V
3244 // out1 data[0]: 0.5U + 0.5V data[1]: 0.25U data[2]: 0.25V
3245 for (i = 0; i < frame_height / 2; i++)
3246 {
3247 for (j = 0; j < frame_width * factor / 2; j += factor)
3248 {
3249 // U component
3250 // even line 0.25U
3251 memcpy(&p_dst1[1][i * uv_420p_linesize + j],
3252 &p_src[1][2 * i * uv_444p_linesize + (2 * j + factor)],
3253 factor);
3254 // odd line 0.5U
3255 memcpy(&p_dst1[0][2 * i * uv_444p_linesize + 2 * j],
3256 &p_src[1][(2 * i + 1) * uv_444p_linesize + 2 * j],
3257 (ptrdiff_t)factor * 2);
3258 // even line 0.25U
3259 memcpy(&p_dst0[1][i * uv_420p_linesize + j],
3260 &p_src[1][2 * i * uv_444p_linesize + 2 * j],
3261 factor);
3262
3263 // V component
3264 // even line 0.25V
3265 memcpy(&p_dst1[2][i * uv_420p_linesize + j],
3266 &p_src[2][2 * i * uv_444p_linesize + (2 * j + factor)],
3267 factor);
3268 // odd line 0.5V
3269 memcpy(&p_dst1[0][(2 * i + 1) * uv_444p_linesize + 2 * j],
3270 &p_src[2][(2 * i + 1) * uv_444p_linesize + 2 * j],
3271 (ptrdiff_t)factor * 2);
3272 // even line 0.25V
3273 memcpy(&p_dst0[2][i * uv_420p_linesize + j],
3274 &p_src[2][2 * i * uv_444p_linesize + 2 * j],
3275 factor);
3276 }
3277 }
3278 }
3279}
3280
3281// NAL operations
3282
3283/*!*****************************************************************************
3284 * \brief Insert emulation prevention byte(s) as needed into the data buffer
3285 *
3286 * \param buf data buffer to be worked on - new byte(s) will be inserted
3287 * size number of bytes starting from buf to check
3288 *
3289 * \return the number of emulation prevention bytes inserted into buf, 0 if
3290 * none.
3291 *
3292 * Note: caller *MUST* ensure for newly inserted bytes, buf has enough free
3293 * space starting from buf + size
3294 ******************************************************************************/
3295int ni_insert_emulation_prevent_bytes(uint8_t *buf, int size)
3296{
3297 int insert_bytes = 0;
3298 uint8_t *buf_curr = buf;
3299 uint8_t *buf_end = buf + size - 1;
3300 int zeros = 0, insert_ep3_byte;
3301
3302 ni_log(NI_LOG_TRACE, "%s: enter\n", __func__);
3303
3304 for (; buf_curr <= buf_end; buf_curr++)
3305 {
3306 if (zeros == 2)
3307 {
3308 insert_ep3_byte = (*buf_curr <= 3);
3309 if (insert_ep3_byte)
3310 {
3311 // move bytes from curr to end 1 position to make space for ep3
3312 memmove(buf_curr + 1, buf_curr, buf_end - buf_curr + 1);
3313 *buf_curr = 0x3;
3314
3315 buf_curr++;
3316 buf_end++;
3317 insert_bytes++;
3318 }
3319
3320 zeros = 0;
3321 }
3322
3323 if (!*buf_curr)
3324 {
3325 zeros++;
3326 } else
3327 {
3328 zeros = 0;
3329 }
3330 }
3331
3332 ni_log(NI_LOG_TRACE, "%s: %d, exit\n", __func__, insert_bytes);
3333 return insert_bytes;
3334}
3335
3336/*!*****************************************************************************
3337 * \brief Remove emulation prevention byte(s) as needed from the data buffer
3338 *
3339 * \param buf data buffer to be worked on - emu prevent byte(s) will be
3340 * removed from.
3341 * size number of bytes starting from buf to check
3342 *
3343 * \return the number of emulation prevention bytes removed from buf, 0 if
3344 * none.
3345 *
3346 * Note: buf will be modified if emu prevent byte(s) found and removed.
3347 ******************************************************************************/
3348int ni_remove_emulation_prevent_bytes(uint8_t *buf, int size)
3349{
3350 int remove_bytes = 0;
3351 uint8_t *buf_curr = buf;
3352 uint8_t *buf_end = buf + size - 1;
3353 int zeros = 0, remove_ep3_byte;
3354
3355 ni_log(NI_LOG_TRACE, "%s: enter\n", __func__);
3356
3357 for (; buf_curr < buf_end; buf_curr++)
3358 {
3359 if (zeros == 2)
3360 {
3361 remove_ep3_byte = (*buf_curr == 0x03 && *(buf_curr + 1) <= 3);
3362 if (remove_ep3_byte)
3363 {
3364 // move bytes after curr to end, 1 position forward to overwrite ep3
3365 memmove(buf_curr, buf_curr + 1, buf_end - buf_curr);
3366
3367 // buf_curr unchanged
3368 buf_end--;
3369 remove_bytes++;
3370 }
3371
3372 zeros = 0;
3373 }
3374
3375 if (!*buf_curr)
3376 {
3377 zeros++;
3378 } else
3379 {
3380 zeros = 0;
3381 }
3382 }
3383
3384 ni_log(NI_LOG_TRACE, "%s: %d, exit\n", __func__, remove_bytes);
3385 return remove_bytes;
3386}
3387
3388/******************************************************************************
3389 *
3390 * Ai utils apis
3391 *
3392 ******************************************************************************/
3393static uint32_t ni_ai_type_get_bytes(const uint32_t type)
3394{
3395 switch (type)
3396 {
3399 return 1;
3404 return 2;
3408 return 4;
3412 return 8;
3413
3414 default:
3415 return 0;
3416 }
3417}
3418
3419static void ni_ai_integer_convert(const void *src, void *dest,
3420 ni_ai_buffer_format_e src_dtype,
3421 ni_ai_buffer_format_e dst_dtype)
3422{
3423 unsigned char all_zeros[] = {0x00, 0x00, 0x00, 0x00,
3424 0x00, 0x00, 0x00, 0x00};
3425 unsigned char all_ones[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
3426 uint32_t src_sz = ni_ai_type_get_bytes(src_dtype);
3427 uint32_t dest_sz = ni_ai_type_get_bytes(dst_dtype);
3428 unsigned char *buffer = all_zeros;
3429
3430 if (((int8_t *)src)[src_sz - 1] & 0x80)
3431 {
3432 buffer = all_ones;
3433 }
3434 memcpy(buffer, src, src_sz);
3435 memcpy(dest, buffer, dest_sz);
3436}
3437
3438static float ni_ai_int8_to_fp32(signed char val, signed char fixedPointPos)
3439{
3440 float result = 0.0f;
3441
3442 if (fixedPointPos > 0)
3443 {
3444 result = (float)val * (1.0f / ((float)(1 << fixedPointPos)));
3445 } else
3446 {
3447 result = (float)val * ((float)(1 << -fixedPointPos));
3448 }
3449
3450 return result;
3451}
3452
3453static float ni_ai_int16_to_fp32(int16_t val, signed char fixedPointPos)
3454{
3455 float result = 0.0f;
3456
3457 if (fixedPointPos > 0)
3458 {
3459 result = (float)val * (1.0f / ((float)(1 << fixedPointPos)));
3460 } else
3461 {
3462 result = (float)val * ((float)(1 << -fixedPointPos));
3463 }
3464
3465 return result;
3466}
3467
3468static float ni_ai_uint8_to_fp32(uint8_t val, int32_t zeroPoint, float scale)
3469{
3470 float result = 0.0f;
3471
3472 result = (float)(val - (uint8_t)zeroPoint) * scale;
3473
3474 return result;
3475}
3476
3477static float ni_ai_fp16_to_fp32(const short in)
3478{
3479 typedef union
3480 {
3481 unsigned int u;
3482 float f;
3483 } _fp32_t;
3484
3485 const _fp32_t magic = {(254 - 15) << 23};
3486 const _fp32_t infnan = {(127 + 16) << 23};
3487 _fp32_t o;
3488 // Non-sign bits
3489 o.u = (in & 0x7fff) << 13;
3490 o.f *= magic.f;
3491 if (o.f >= infnan.f)
3492 {
3493 o.u |= 255 << 23;
3494 }
3495 //Sign bit
3496 o.u |= (in & 0x8000) << 16;
3497 return o.f;
3498}
3499
3500static float ni_ai_affine_to_fp32(int32_t val, int32_t zeroPoint, float scale)
3501{
3502 float result = 0.0f;
3503 result = ((float)val - (float)zeroPoint) * scale;
3504 return result;
3505}
3506
3507static uint32_t ni_ai_get_tensor_size(int32_t *shape, uint32_t dim_num,
3508 int32_t type)
3509{
3510 uint32_t sz;
3511 uint32_t i;
3512 sz = 0;
3513 if (NULL == shape || 0 == dim_num)
3514 {
3515 return sz;
3516 }
3517 sz = 1;
3518 for (i = 0; i < dim_num; i++)
3519 {
3520 sz *= shape[i];
3521 }
3522 sz *= ni_ai_type_get_bytes(type);
3523
3524 return sz;
3525}
3526
3527static uint32_t ni_ai_get_element_num(int32_t *sizes, uint32_t num_of_dims,
3528 int32_t data_format)
3529{
3530 uint32_t num;
3531 uint32_t sz;
3532 uint32_t dsize;
3533
3534 sz = ni_ai_get_tensor_size(sizes, num_of_dims, data_format);
3535 dsize = ni_ai_type_get_bytes(data_format);
3536 if (dsize)
3537 {
3538 num = (uint32_t)(sz / dsize);
3539 } else
3540 {
3541 num = 0;
3542 }
3543
3544 return num;
3545}
3546
3547static int32_t ni_ai_type_is_integer(const int32_t type)
3548{
3549 int32_t ret = 0;
3550 switch (type)
3551 {
3558 ret = 1;
3559 break;
3560 default:
3561 break;
3562 }
3563
3564 return ret;
3565}
3566
3567static int32_t ni_ai_type_is_signed(const int32_t type)
3568{
3569 int32_t ret = 0;
3570 switch (type)
3571 {
3578 ret = 1;
3579 break;
3580 default:
3581 break;
3582 }
3583
3584 return ret;
3585}
3586
3587static void ni_ai_type_get_range(int32_t type, double *max_range,
3588 double *min_range)
3589{
3590 int32_t bits;
3591 double from, to;
3592 from = 0.0;
3593 to = 0.0;
3594 bits = (int32_t)(ni_ai_type_get_bytes(type) * 8);
3595 if (ni_ai_type_is_integer(type))
3596 {
3597 if (ni_ai_type_is_signed(type))
3598 {
3599 from = (double)(-(1L << (bits - 1)));
3600 to = (double)((1UL << (bits - 1)) - 1);
3601 } else
3602 {
3603 from = 0.0;
3604 to = (double)((1UL << bits) - 1);
3605 }
3606 }
3607 if (NULL != max_range)
3608 {
3609 *max_range = to;
3610 }
3611 if (NULL != min_range)
3612 {
3613 *min_range = from;
3614 }
3615}
3616
3617static inline double ni_abs(double x)
3618{
3619 return x < 0 ? -x : x;
3620}
3621
3622static double ni_ai_copy_sign(double number, double sign)
3623{
3624 double value = ni_abs(number);
3625 return (sign > 0) ? value : (-value);
3626}
3627
3628static inline int ni_ai_math_floorf(double x)
3629{
3630 return x >= 0 ? (int)x : (int)x - 1;
3631}
3632
3633static double ni_ai_rint(double x)
3634{
3635#define NI_AI_EPSILON 1e-8
3636 double decimal;
3637 double inter;
3638 int intpart;
3639
3640 intpart = (int)x;
3641 decimal = x - intpart;
3642 inter = (double)intpart;
3643
3644 if (ni_abs((ni_abs(decimal) - 0.5f)) < NI_AI_EPSILON)
3645 {
3646 inter += (int32_t)(inter) % 2;
3647 } else
3648 {
3649 return ni_ai_copy_sign(ni_ai_math_floorf(ni_abs(x) + 0.5f), x);
3650 }
3651
3652 return inter;
3653}
3654
3655static int32_t ni_ai_fp32_to_dfp(const float in, const signed char fl,
3656 const int32_t type)
3657{
3658 int32_t data;
3659 double max_range;
3660 double min_range;
3661 ni_ai_type_get_range(type, &max_range, &min_range);
3662 if (fl > 0)
3663 {
3664 data = (int32_t)ni_ai_rint(in * (float)(1 << fl));
3665 } else
3666 {
3667 data = (int32_t)ni_ai_rint(in * (1.0f / (float)(1 << -fl)));
3668 }
3669 data = ni_min(data, (int32_t)max_range);
3670 data = ni_max(data, (int32_t)min_range);
3671
3672 return data;
3673}
3674
3675static int32_t ni_ai_fp32_to_affine(const float in, const float scale,
3676 const int zero_point, const int32_t type)
3677{
3678 int32_t data;
3679 double max_range;
3680 double min_range;
3681 ni_ai_type_get_range(type, &max_range, &min_range);
3682 data = (int32_t)(ni_ai_rint(in / scale) + zero_point);
3683 data = ni_max((int32_t)min_range, ni_min((int32_t)max_range, data));
3684 return data;
3685}
3686
3687static unsigned short ni_ai_fp32_to_bfp16_rtne(float in)
3688{
3689 /*
3690 Convert a float point to bfloat16, with round-nearest-to-even as rounding method.
3691 */
3692 unsigned short out;
3693
3694 uint32_t fp32;
3695 memcpy(&fp32, &in, sizeof(uint32_t));
3696
3697 uint32_t lsb =
3698 (fp32 >> 16) & 1; /* Least significant bit of resulting bfloat. */
3699 uint32_t rounding_bias = 0x7fff + lsb;
3700
3701 if ((float)0x7FC00000 == in)
3702 {
3703 out = 0x7fc0;
3704 } else
3705 {
3706 fp32 += rounding_bias;
3707 out = (unsigned short)(fp32 >> 16);
3708 }
3709
3710 return out;
3711}
3712
3713static unsigned short ni_ai_fp32_to_fp16(float in)
3714{
3715 uint32_t fp32 = 0;
3716 uint32_t t1 = 0;
3717 uint32_t t2 = 0;
3718 uint32_t t3 = 0;
3719 uint32_t fp16 = 0u;
3720
3721 memcpy((uint8_t *)&fp32, (uint8_t *)&in, sizeof(uint32_t));
3722
3723 t1 = (fp32 & 0x80000000u) >> 16; /* sign bit. */
3724 t2 = (fp32 & 0x7F800000u) >> 13; /* Exponent bits */
3725 t3 = (fp32 & 0x007FE000u) >> 13; /* Mantissa bits, no rounding */
3726
3727 if (t2 >= 0x023c00u)
3728 {
3729 fp16 = t1 | 0x7BFF; /* Don't round to infinity. */
3730 } else if (t2 <= 0x01c000u)
3731 {
3732 fp16 = t1;
3733 } else
3734 {
3735 t2 -= 0x01c000u;
3736 fp16 = t1 | t2 | t3;
3737 }
3738
3739 return (unsigned short)fp16;
3740}
3741
3742static void ni_ai_float32_to_dtype(float src, unsigned char *dst,
3743 const int32_t data_type,
3744 const int32_t quant_format,
3745 signed char fixed_point_pos, float tf_scale,
3746 int32_t tf_zerop)
3747{
3748 switch (data_type)
3749 {
3751 memcpy(dst, &src, sizeof(float));
3752 break;
3754 *(int16_t *)dst = (int16_t)ni_ai_fp32_to_fp16(src);
3755 break;
3757 *(int16_t *)dst = (int16_t)ni_ai_fp32_to_bfp16_rtne(src);
3758 break;
3762 {
3763 int32_t dst_value = 0;
3764 switch (quant_format)
3765 {
3767 dst_value =
3768 ni_ai_fp32_to_dfp(src, fixed_point_pos, data_type);
3769 break;
3771 dst_value = ni_ai_fp32_to_affine(src, tf_scale, tf_zerop,
3772 data_type);
3773 break;
3775 dst_value = (int32_t)src;
3776 break;
3777 default:
3778 break;
3779 }
3780 ni_ai_integer_convert(&dst_value, dst, NI_AI_BUFFER_FORMAT_INT32,
3781 data_type);
3782 }
3783 break;
3784 default:;
3785 }
3786}
3787
3789 ni_packet_t *p_packet,
3790 ni_network_data_t *p_network,
3791 uint32_t layer)
3792{
3793 uint8_t *data;
3794 uint32_t data_len;
3796
3797 if (!p_network || !dst || dst_len == 0 || !p_packet || !p_packet->p_data)
3798 {
3800 }
3801
3802 if (layer >= p_network->output_num)
3803 {
3805 }
3806
3807 p_param = &p_network->linfo.out_param[layer];
3808 data = (uint8_t *)p_packet->p_data + p_network->outset[layer].offset;
3809 data_len = ni_ai_network_layer_size(p_param);
3810 return ni_network_convert_data_to_tensor(dst, dst_len, data, data_len,
3811 p_param);
3812}
3813
3815{
3816 void *private;
3817 uint32_t total_num;
3818 uint32_t next_idx;
3819};
3820
3821static int open_tensor_rsrc_file(struct tensor_rsrc *rsrc, void *data,
3822 uint32_t num)
3823{
3824 (void)num;
3825 FILE *f = NULL;
3826 ni_fopen(&f, (const char *)data, "r");
3827 rsrc->private = (void *)f;
3828 return rsrc->private ? 0 : -1;
3829}
3830
3831static int get_tensor_rsrc_from_file(struct tensor_rsrc *rsrc, float *value)
3832{
3833 FILE *fp = (FILE *)rsrc->private;
3834 float tensor;
3835
3836 if (ni_fscanf(fp, "%f ", &tensor) == 1)
3837 {
3838 *value = tensor;
3839 return 0;
3840 }
3841
3842 return -1;
3843}
3844
3845static void close_tensor_rsrc_file(struct tensor_rsrc *rsrc)
3846{
3847 FILE *fp = (FILE *)rsrc->private;
3848 (void)fclose(fp);
3849}
3850
3851static int open_tensor_rsrc_rawdata(struct tensor_rsrc *rsrc, void *data,
3852 uint32_t len)
3853{
3854 rsrc->private = (void *)data;
3855 rsrc->total_num = len / sizeof(float);
3856 rsrc->next_idx = 0;
3857 return 0;
3858}
3859
3860static int get_tensor_rsrc_from_rawdata(struct tensor_rsrc *rsrc, float *value)
3861{
3862 float *tensors = (float *)rsrc->private;
3863
3864 if (rsrc->next_idx < rsrc->total_num)
3865 {
3866 *value = tensors[rsrc->next_idx];
3867 rsrc->next_idx++;
3868 return 0;
3869 }
3870
3871 return -1;
3872}
3873
3874static void close_tensor_rsrc_rawdata(struct tensor_rsrc *rsrc)
3875{
3876}
3877
3878static ni_retcode_t ni_network_tensor_to_data(
3879 uint8_t *dst, uint32_t dst_len, void *tensor, uint32_t src_len,
3881 int (*open_tensor_rsrc)(struct tensor_rsrc *, void *, uint32_t),
3882 int (*get_tensor_rsrc)(struct tensor_rsrc *, float *),
3883 void (*close_tensor_rsrc)(struct tensor_rsrc *))
3884{
3885 uint8_t *tensor_data;
3886 uint32_t i, sz;
3887 uint32_t stride;
3888 float fval;
3889 int32_t data_format;
3890 int32_t quant_format;
3891 int32_t fixed_point_pos;
3892 float tf_scale;
3893 int32_t tf_zerop;
3894 struct tensor_rsrc *rsrc;
3895
3896 data_format = p_param->data_format;
3897 quant_format = p_param->quant_format;
3898 fixed_point_pos = p_param->quant_data.dfp.fixed_point_pos;
3899 tf_scale = p_param->quant_data.affine.scale;
3900 tf_zerop = p_param->quant_data.affine.zeroPoint;
3901
3902 sz = ni_ai_get_element_num((int32_t *)p_param->sizes, p_param->num_of_dims,
3903 data_format);
3904 stride = ni_ai_type_get_bytes(data_format);
3905
3906 if ((size_t)sz * stride * sizeof(uint8_t) != dst_len)
3907 {
3909 }
3910
3911 rsrc = (struct tensor_rsrc *)calloc(1, sizeof(struct tensor_rsrc));
3912 if (!rsrc)
3913 {
3914 return NI_RETCODE_FAILURE;
3915 }
3916
3917 if (open_tensor_rsrc(rsrc, tensor, src_len) != 0)
3918 {
3919 free(rsrc);
3920 return NI_RETCODE_FAILURE;
3921 }
3922
3923 memset(dst, 0, (size_t)sz * stride * sizeof(uint8_t));
3924 tensor_data = dst;
3925 for (i = 0; i < sz; i++)
3926 {
3927 if (get_tensor_rsrc(rsrc, &fval) == 0)
3928 {
3929 ni_ai_float32_to_dtype(fval, &tensor_data[(ptrdiff_t)stride * i], data_format,
3930 quant_format, (int8_t)fixed_point_pos, tf_scale,
3931 tf_zerop);
3932 } else
3933 {
3934 break;
3935 }
3936 }
3937
3938 close_tensor_rsrc(rsrc);
3939 free(rsrc);
3940 return NI_RETCODE_SUCCESS;
3941}
3942
3943ni_retcode_t ni_network_layer_convert_tensor(uint8_t *dst, uint32_t dst_len,
3944 const char *tensor_file,
3946{
3947 return ni_network_tensor_to_data(
3948 dst, dst_len, (void *)tensor_file, 0, p_param, open_tensor_rsrc_file,
3949 get_tensor_rsrc_from_file, close_tensor_rsrc_file);
3950}
3951
3953ni_network_convert_tensor_to_data(uint8_t *dst, uint32_t dst_len, float *src,
3954 uint32_t src_len,
3956{
3957 return ni_network_tensor_to_data(
3958 dst, dst_len, src, src_len, p_param, open_tensor_rsrc_rawdata,
3959 get_tensor_rsrc_from_rawdata, close_tensor_rsrc_rawdata);
3960}
3961
3963ni_network_convert_data_to_tensor(float *dst, uint32_t dst_len, uint8_t *src,
3964 uint32_t src_len,
3966{
3967 uint32_t i = 0;
3968 uint8_t *data;
3969 uint32_t ele_size;
3970 float *dst_float = dst;
3971 uint32_t type_size;
3972
3973 if (!src || src_len == 0 || !dst || dst_len == 0 || !p_param)
3974 {
3976 }
3977
3978 type_size = ni_ai_type_get_bytes(p_param->data_format);
3979
3980 data = src;
3981
3982 ele_size = 1;
3983 for (i = 0; i < p_param->num_of_dims; i++)
3984 {
3985 ele_size *= p_param->sizes[i];
3986 }
3987
3988 if (dst_len != ele_size * sizeof(float))
3989 {
3991 }
3992
3993 if (src_len != ni_ai_network_layer_size(p_param))
3994 {
3996 }
3997
3998 if (p_param->data_format == NI_AI_BUFFER_FORMAT_INT8)
3999 {
4000 int32_t quant_format = p_param->quant_format;
4001
4003 {
4004 uint8_t fix_pos = (uint8_t)p_param->quant_data.dfp.fixed_point_pos;
4005
4006 for (i = 0; i < ele_size; i++, data += type_size)
4007 {
4008 dst_float[i] = ni_ai_int8_to_fp32((int8_t)*data, (int8_t)fix_pos);
4009 }
4010 } else if (quant_format == NI_AI_BUFFER_QUANTIZE_TF_ASYMM)
4011 {
4012 int32_t zero_point = p_param->quant_data.affine.zeroPoint;
4013 float scale = p_param->quant_data.affine.scale;
4014
4015 for (i = 0; i < ele_size; i++, data += type_size)
4016 {
4017 int32_t src_value = 0;
4018 ni_ai_integer_convert(data, &src_value,
4021 dst_float[i] =
4022 ni_ai_affine_to_fp32(src_value, zero_point, scale);
4023 }
4024 } else
4025 {
4026 for (i = 0; i < ele_size; i++, data += type_size)
4027 {
4028 void *float_data = (void *)data;
4029 dst_float[i] = *((float *)float_data);
4030 }
4031 }
4032 } else if (p_param->data_format == NI_AI_BUFFER_FORMAT_FP16)
4033 {
4034 for (i = 0; i < ele_size; i++, data += type_size)
4035 {
4036 dst_float[i] = ni_ai_fp16_to_fp32(*((short *)data));
4037 }
4038 } else if (p_param->data_format == NI_AI_BUFFER_FORMAT_UINT8)
4039 {
4040 int32_t zero_point = p_param->quant_data.affine.zeroPoint;
4041 float scale = p_param->quant_data.affine.scale;
4042
4043 for (i = 0; i < ele_size; i++, data += type_size)
4044 {
4045 dst_float[i] = ni_ai_uint8_to_fp32(*data, zero_point, scale);
4046 }
4047 } else if (p_param->data_format == NI_AI_BUFFER_FORMAT_INT16)
4048 {
4049 uint8_t fix_pos = p_param->quant_data.dfp.fixed_point_pos;
4050
4051 for (i = 0; i < ele_size; i++, data += type_size)
4052 {
4053 dst_float[i] = ni_ai_int16_to_fp32(*((short *)data), (int8_t)fix_pos);
4054 }
4055 } else if (p_param->data_format == NI_AI_BUFFER_FORMAT_FP32)
4056 {
4057 for (i = 0; i < ele_size; i++, data += type_size)
4058 {
4059 void *float_data = (void *)data;
4060 dst_float[i] = *((float *)float_data);
4061 }
4062 } else
4063 {
4065 }
4066
4067 return NI_RETCODE_SUCCESS;
4068}
4069
4071{
4072 return ni_ai_get_tensor_size((int32_t *)p_param->sizes,
4073 p_param->num_of_dims, p_param->data_format);
4074}
4075
4077{
4078 uint32_t i, dims = 1;
4079
4080 for (i = 0; i < p_param->num_of_dims; i++)
4081 {
4082 dims *= p_param->sizes[i];
4083 }
4084
4085 return dims;
4086}
4087
4088/* sha256 */
4089// SHA256 outputs a 32 byte digest
4090#define SHA256_BLOCK_SIZE 32
4091
4092typedef struct SHA256CTX
4093{
4094 uint8_t aui8Data[64];
4097 uint32_t aui32State[8];
4099
4100#define ROTLEFT(a, b) (((a) << (b)) | ((a) >> (32 - (b))))
4101#define ROTRIGHT(a, b) (((a) >> (b)) | ((a) << (32 - (b))))
4102
4103#define CH(x, y, z) (((x) & (y)) ^ (~(x) & (z)))
4104#define MAJ(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
4105#define EP0(x) (ROTRIGHT(x, 2) ^ ROTRIGHT(x, 13) ^ ROTRIGHT(x, 22))
4106#define EP1(x) (ROTRIGHT(x, 6) ^ ROTRIGHT(x, 11) ^ ROTRIGHT(x, 25))
4107#define SIG0(x) (ROTRIGHT(x, 7) ^ ROTRIGHT(x, 18) ^ ((x) >> 3))
4108#define SIG1(x) (ROTRIGHT(x, 17) ^ ROTRIGHT(x, 19) ^ ((x) >> 10))
4109
4110static const uint32_t ui32k[64] = {
4111 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
4112 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
4113 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
4114 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
4115 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
4116 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
4117 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
4118 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
4119 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
4120 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
4121 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2};
4122
4123void ni_SHA256Transform(SHA256CTX *psCtx, const uint8_t aui8Data[])
4124{
4125 uint32_t ui32a, ui32b, ui32c, ui32d, ui32e, ui32f, ui32g, ui32h, ui32i,
4126 ui32j, ui32t1, ui32t2, ui32m[64];
4127
4128 for (ui32i = 0, ui32j = 0; ui32i < 16; ++ui32i, ui32j += 4)
4129 ui32m[ui32i] = (aui8Data[ui32j] << 24) | (aui8Data[ui32j + 1] << 16) |
4130 (aui8Data[ui32j + 2] << 8) | (aui8Data[ui32j + 3]);
4131 for (; ui32i < 64; ++ui32i)
4132 ui32m[ui32i] = SIG1(ui32m[ui32i - 2]) + ui32m[ui32i - 7] +
4133 SIG0(ui32m[ui32i - 15]) + ui32m[ui32i - 16];
4134
4135 ui32a = psCtx->aui32State[0];
4136 ui32b = psCtx->aui32State[1];
4137 ui32c = psCtx->aui32State[2];
4138 ui32d = psCtx->aui32State[3];
4139 ui32e = psCtx->aui32State[4];
4140 ui32f = psCtx->aui32State[5];
4141 ui32g = psCtx->aui32State[6];
4142 ui32h = psCtx->aui32State[7];
4143
4144 for (ui32i = 0; ui32i < 64; ++ui32i)
4145 {
4146 ui32t1 = ui32h + EP1(ui32e) + CH(ui32e, ui32f, ui32g) + ui32k[ui32i] +
4147 ui32m[ui32i];
4148 ui32t2 = EP0(ui32a) + MAJ(ui32a, ui32b, ui32c);
4149 ui32h = ui32g;
4150 ui32g = ui32f;
4151 ui32f = ui32e;
4152 ui32e = ui32d + ui32t1;
4153 ui32d = ui32c;
4154 ui32c = ui32b;
4155 ui32b = ui32a;
4156 ui32a = ui32t1 + ui32t2;
4157 }
4158
4159 psCtx->aui32State[0] += ui32a;
4160 psCtx->aui32State[1] += ui32b;
4161 psCtx->aui32State[2] += ui32c;
4162 psCtx->aui32State[3] += ui32d;
4163 psCtx->aui32State[4] += ui32e;
4164 psCtx->aui32State[5] += ui32f;
4165 psCtx->aui32State[6] += ui32g;
4166 psCtx->aui32State[7] += ui32h;
4167}
4168
4170{
4171 psCtx->ui32DataLength = 0;
4172 psCtx->ui64BitLength = 0;
4173 psCtx->aui32State[0] = 0x6a09e667;
4174 psCtx->aui32State[1] = 0xbb67ae85;
4175 psCtx->aui32State[2] = 0x3c6ef372;
4176 psCtx->aui32State[3] = 0xa54ff53a;
4177 psCtx->aui32State[4] = 0x510e527f;
4178 psCtx->aui32State[5] = 0x9b05688c;
4179 psCtx->aui32State[6] = 0x1f83d9ab;
4180 psCtx->aui32State[7] = 0x5be0cd19;
4181}
4182
4183void ni_SHA256Update(SHA256CTX *psCtx, const uint8_t aui8Data[],
4184 size_t ui32Length)
4185{
4186 uint32_t ui32i;
4187
4188 for (ui32i = 0; ui32i < ui32Length; ++ui32i)
4189 {
4190 psCtx->aui8Data[psCtx->ui32DataLength] = aui8Data[ui32i];
4191 psCtx->ui32DataLength++;
4192 if (psCtx->ui32DataLength == 64)
4193 {
4194 ni_SHA256Transform(psCtx, psCtx->aui8Data);
4195 psCtx->ui64BitLength += 512;
4196 psCtx->ui32DataLength = 0;
4197 }
4198 }
4199}
4200
4201void ni_SHA256Final(SHA256CTX *psCtx, uint8_t aui8Hash[])
4202{
4203 uint32_t ui32i;
4204
4205 ui32i = psCtx->ui32DataLength;
4206
4207 // Pad whatever data is left in the buffer.
4208 if (psCtx->ui32DataLength < 56)
4209 {
4210 psCtx->aui8Data[ui32i++] = 0x80;
4211 while (ui32i < 56)
4212 psCtx->aui8Data[ui32i++] = 0x00;
4213 } else
4214 {
4215 psCtx->aui8Data[ui32i++] = 0x80;
4216 while (ui32i < 64)
4217 psCtx->aui8Data[ui32i++] = 0x00;
4218 ni_SHA256Transform(psCtx, psCtx->aui8Data);
4219 memset(psCtx->aui8Data, 0, 56);
4220 }
4221
4222 // Append to the padding the total message's length in bits and transform.
4223 psCtx->ui64BitLength += (uint64_t)psCtx->ui32DataLength * 8;
4224 psCtx->aui8Data[63] = (uint8_t)psCtx->ui64BitLength;
4225 psCtx->aui8Data[62] = (uint8_t)(psCtx->ui64BitLength >> 8);
4226 psCtx->aui8Data[61] = (uint8_t)(psCtx->ui64BitLength >> 16);
4227 psCtx->aui8Data[60] = (uint8_t)(psCtx->ui64BitLength >> 24);
4228 psCtx->aui8Data[59] = (uint8_t)(psCtx->ui64BitLength >> 32);
4229 psCtx->aui8Data[58] = (uint8_t)(psCtx->ui64BitLength >> 40);
4230 psCtx->aui8Data[57] = (uint8_t)(psCtx->ui64BitLength >> 48);
4231 psCtx->aui8Data[56] = (uint8_t)(psCtx->ui64BitLength >> 56);
4232 ni_SHA256Transform(psCtx, psCtx->aui8Data);
4233
4234 // Since this implementation uses little endian byte ordering and SHA uses big endian,
4235 // reverse all the bytes when copying the final state to the output hash.
4236 for (ui32i = 0; ui32i < 4; ++ui32i)
4237 {
4238 aui8Hash[ui32i] =
4239 (psCtx->aui32State[0] >> (24 - ui32i * 8)) & 0x000000ff;
4240 aui8Hash[ui32i + 4] =
4241 (psCtx->aui32State[1] >> (24 - ui32i * 8)) & 0x000000ff;
4242 aui8Hash[ui32i + 8] =
4243 (psCtx->aui32State[2] >> (24 - ui32i * 8)) & 0x000000ff;
4244 aui8Hash[ui32i + 12] =
4245 (psCtx->aui32State[3] >> (24 - ui32i * 8)) & 0x000000ff;
4246 aui8Hash[ui32i + 16] =
4247 (psCtx->aui32State[4] >> (24 - ui32i * 8)) & 0x000000ff;
4248 aui8Hash[ui32i + 20] =
4249 (psCtx->aui32State[5] >> (24 - ui32i * 8)) & 0x000000ff;
4250 aui8Hash[ui32i + 24] =
4251 (psCtx->aui32State[6] >> (24 - ui32i * 8)) & 0x000000ff;
4252 aui8Hash[ui32i + 28] =
4253 (psCtx->aui32State[7] >> (24 - ui32i * 8)) & 0x000000ff;
4254 }
4255}
4256
4257void ni_calculate_sha256(const uint8_t aui8Data[], size_t ui32DataLength,
4258 uint8_t aui8Hash[])
4259{
4260 // Create the context structure
4261 SHA256CTX sCtx;
4262
4263 // Initialize the context
4264 ni_SHA256Init(&sCtx);
4265 // Update the context with data and data length
4266 ni_SHA256Update(&sCtx, aui8Data, ui32DataLength);
4267 // Finalize the result and put it into a hash buffer
4268 ni_SHA256Final(&sCtx, aui8Hash);
4269}
4270
4271/*!*****************************************************************************
4272 * \brief Copy Descriptor data to Netint HW descriptor frame layout to be sent
4273 * to encoder for encoding. Data buffer (dst) is usually allocated by
4274 * ni_encoder_frame_buffer_alloc. Only necessary when metadata size in
4275 * source is insufficient
4276 *
4277 * \param[out] p_dst pointers of Y/Cb/Cr to which data is copied
4278 * \param[in] p_src pointers of Y/Cb/Cr from which data is copied
4279 *
4280 * \return descriptor data
4281 *
4282 ******************************************************************************/
4284 uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS])
4285{
4286 // return to avoid self copy
4287 if (p_dst[0] == p_src[0] && p_dst[1] == p_src[1] && p_dst[2] == p_src[2] &&
4288 p_dst[3] == p_src[3])
4289 {
4290 ni_log(NI_LOG_DEBUG, "ni_copy_hw_yuv420p: src and dst identical, return\n");
4291 return;
4292 }
4293 niFrameSurface1_t *src_desc = (niFrameSurface1_t *)p_src[3];
4294 niFrameSurface1_t *dest_desc = (niFrameSurface1_t *)p_dst[3];
4295 memcpy(dest_desc, src_desc, sizeof(niFrameSurface1_t));
4296 ni_log(NI_LOG_DEBUG, "ni_copy_hw_descriptors dst FID Handle %d/%d src FID handle "
4297 "%d/%d\n",
4298 src_desc->ui16FrameIdx, src_desc->device_handle,
4299 dest_desc->ui16FrameIdx, dest_desc->device_handle);
4300}
4301
4302/*!*****************************************************************************
4303 * \brief Get libxcoder API version
4304 *
4305 * \return char pointer to libxcoder API version
4306 ******************************************************************************/
4308{
4309 static char* libxcoder_api_ver = LIBXCODER_API_VERSION;
4310 return libxcoder_api_ver;
4311}
4312
4313#ifndef DEPRECATION_AS_ERROR
4314/*!*****************************************************************************
4315 * \brief Get FW API version libxcoder is compatible with.
4316 * Deprecated in favour of `ni_fmt_fw_api_ver_str(&NI_XCODER_REVISION[NI_XCODER_REVISION_API_MAJOR_VER_IDX], &char_buf[0]);`
4317 *
4318 * \return char pointer to FW API version libxcoder is compatible with
4319 ******************************************************************************/
4321{
4322 static char compat_fw_api_ver_str[5] = "";
4323 // init static array one byte at a time to avoid msvc compiler error C2099
4324 if (!compat_fw_api_ver_str[0])
4325 {
4326 compat_fw_api_ver_str[0] = \
4328 compat_fw_api_ver_str[1] = '.';
4329 compat_fw_api_ver_str[2] = \
4332 compat_fw_api_ver_str[3] = \
4334 else
4335 compat_fw_api_ver_str[3] = 0;
4336 compat_fw_api_ver_str[4] = 0;
4337 }
4338 return &compat_fw_api_ver_str[0];
4339}
4340#endif
4341
4342/*!*****************************************************************************
4343 * \brief Get formatted FW API version string from unformatted FW API version
4344 * string
4345 *
4346 * \param[in] ver_str pointer to string containing FW API. Only up to 3
4347 * characters will be read
4348 * \param[out] fmt_str pointer to string buffer of at least size 5 to output
4349 * formated version string to
4350 *
4351 * \return none
4352 ******************************************************************************/
4353void ni_fmt_fw_api_ver_str(const char ver_str[], char fmt_str[])
4354{
4355 if (!ver_str || !fmt_str) {
4356 return;
4357 }
4358
4359 fmt_str[0] = ver_str[0];
4360 fmt_str[1] = '.';
4361 fmt_str[2] = ver_str[1];
4362
4363 if ((ver_str[0] < '6' || (ver_str[0] == '6' && ver_str[1] <= 'q')) ||
4364 (ver_str[2] == 0)) {
4365 fmt_str[3] = 0;
4366 } else {
4367 fmt_str[3] = ver_str[2];
4368 }
4369 fmt_str[4] = 0;
4370}
4371
4372/*!*****************************************************************************
4373 * \brief Compare two 3 character strings containing a FW API version. Handle
4374 * comparision when FW API version format length changed from 2 to 3.
4375 *
4376 * \param[in] ver1 pointer to string containing FW API. Only up to 3
4377 * characters will be read
4378 * \param[in] ver2 pointer to string containing FW API. Only up to 3
4379 * characters will be read
4380 *
4381 * \return 0 if ver1 == ver2, 1 if ver1 > ver2, -1 if ver1 < ver2
4382 ******************************************************************************/
4383int ni_cmp_fw_api_ver(const char ver1[], const char ver2[])
4384{
4385 int index;
4386
4387 index = 0;
4388
4389 if (ver1[index] > ver2[index])
4390 return 1;
4391 else if (ver1[index] < ver2[index])
4392 return -1;
4393
4394 index++;
4395
4396 if (ver1[index] > ver2[index])
4397 return 1;
4398 else if (ver1[index] < ver2[index])
4399 return -1;
4400
4401 if ((ver1[index - 1] < '6') || ((ver1[index - 1] == '6') && (ver1[index] <= 'q')))
4402 return 0;
4403
4404 index++;
4405
4406 if (ver1[index] > ver2[index])
4407 return 1;
4408 else if (ver1[index] < ver2[index])
4409 return -1;
4410
4411 return 0;
4412}
4413
4414/*!*****************************************************************************
4415 * \brief Get libxcoder SW release version
4416 *
4417 * \return char pointer to libxcoder SW release version
4418 ******************************************************************************/
4420{
4421 static char release_ver_str[6] = "";
4422 // init static array one byte at a time to avoid compiler error C2099
4423 if (!release_ver_str[0])
4424 {
4425 release_ver_str[0] = NI_XCODER_REVISION[0];
4426 release_ver_str[1] = '.';
4427 release_ver_str[2] = NI_XCODER_REVISION[1];
4428 release_ver_str[3] = '.';
4429 release_ver_str[4] = NI_XCODER_REVISION[2];
4430 release_ver_str[5] = 0;
4431 }
4432 return &release_ver_str[0];
4433}
4434
4435/*!*****************************************************************************
4436 * \brief Get text string for the provided error
4437 *
4438 * \return char pointer for the provided error
4439 ******************************************************************************/
4441{
4442 int i;
4443 for (i = 0;
4444 i < sizeof(ni_err_rc_description) / sizeof(ni_err_rc_txt_entry_t); i++)
4445 {
4446 if (rc == ni_err_rc_description[i].rc)
4447 {
4448 return ni_err_rc_description[i].txt;
4449 }
4450 }
4451 return "rc not supported";
4452}
4453
4454/*!*****************************************************************************
4455 * \brief retrieve key and value from 'key=value' pair
4456 *
4457 * \param[in] p_str pointer to string to extract pair from
4458 * \param[out] key pointer to key
4459 * \param[out] value pointer to value
4460 *
4461 * \return return 0 if successful, otherwise 1
4462 *
4463 ******************************************************************************/
4464int ni_param_get_key_value(char *p_str, char *key, char *value)
4465{
4466 if (!p_str || !key || !value)
4467 {
4468 return 1;
4469 }
4470
4471 char *p = strchr(p_str, '=');
4472 if (!p)
4473 {
4474 return 1;
4475 } else
4476 {
4477 *p = '\0';
4478 key[0] = '\0';
4479 value[0] = '\0';
4480 int64_t key_len = p - p_str;
4481 ni_strncpy(key, 64, p_str, key_len);
4482 ni_strcpy(value, 64, p + 1);
4483 return 0;
4484 }
4485}
4486
4487/*!*****************************************************************************
4488 * \brief retrieve encoder config parameter values from --xcoder-params
4489 *
4490 * \param[in] xcoderParams pointer to string containing xcoder params
4491 * \param[out] params pointer to xcoder params to fill out
4492 * \param[out] ctx pointer to session context
4493 *
4494 * \return return 0 if successful, -1 otherwise
4495 *
4496 ******************************************************************************/
4497int ni_retrieve_xcoder_params(char xcoderParams[],
4498 ni_xcoder_params_t *params,
4500{
4501 char key[64], value[64];
4502 char *curr = xcoderParams, *colon_pos;
4503 int ret = 0;
4504
4505 while (*curr)
4506 {
4507 colon_pos = strchr(curr, ':');
4508
4509 if (colon_pos)
4510 {
4511 *colon_pos = '\0';
4512 }
4513
4514 if (strlen(curr) > sizeof(key) + sizeof(value) - 1 ||
4515 ni_param_get_key_value(curr, key, value))
4516 {
4518 "Error: xcoder-params p_config key/value not "
4519 "retrieved: %s\n",
4520 curr);
4521 ret = -1;
4522 break;
4523 }
4524 ret = ni_encoder_params_set_value(params, key, value);
4525 switch (ret)
4526 {
4528 ni_log(NI_LOG_ERROR, "Error: unknown option: %s.\n", key);
4529 break;
4531 ni_log(NI_LOG_ERROR, "Error: invalid value for %s: %s.\n", key,
4532 value);
4533 break;
4534 default:
4535 break;
4536 }
4537
4538 if (NI_RETCODE_SUCCESS != ret)
4539 {
4540 ni_log(NI_LOG_ERROR, "Error: config parsing failed %d: %s\n", ret,
4541 ni_get_rc_txt(ret));
4542 break;
4543 }
4544
4545 if (colon_pos)
4546 {
4547 curr = colon_pos + 1;
4548 } else
4549 {
4550 curr += strlen(curr);
4551 }
4552 }
4554 // reuse decoder_low_delay for low delay encoding to store wait interval
4555 // in send/recv multi-thread mode.
4556 ctx->decoder_low_delay = params->low_delay_mode;
4557
4558 return ret;
4559}
4560
4561/*!*****************************************************************************
4562 * \brief Retrieve custom gop config values from --xcoder-gop
4563 *
4564 * \param[in] xcoderGop pointer to string containing xcoder gop
4565 * \param[out] params pointer to xcoder params to fill out
4566 * \param[out] ctx pointer to session context
4567 *
4568 * \return return 0 if successful, -1 otherwise
4569 *
4570 ******************************************************************************/
4571int ni_retrieve_xcoder_gop(char xcoderGop[],
4572 ni_xcoder_params_t *params,
4574{
4575 (void)ctx;
4576 char key[64], value[64];
4577 char *curr = xcoderGop, *colon_pos;
4578 int ret = 0;
4579
4580 while (*curr)
4581 {
4582 colon_pos = strchr(curr, ':');
4583
4584 if (colon_pos)
4585 {
4586 *colon_pos = '\0';
4587 }
4588
4589 if (strlen(curr) > sizeof(key) + sizeof(value) - 1 ||
4590 ni_param_get_key_value(curr, key, value))
4591 {
4593 "Error: xcoder-params p_config key/value not "
4594 "retrieved: %s\n",
4595 curr);
4596 ret = -1;
4597 break;
4598 }
4599 ret = ni_encoder_gop_params_set_value(params, key, value);
4600 switch (ret)
4601 {
4603 ni_log(NI_LOG_ERROR, "Error: unknown option: %s.\n", key);
4604 break;
4606 ni_log(NI_LOG_ERROR, "Error: invalid value for %s: %s.\n", key,
4607 value);
4608 break;
4609 default:
4610 break;
4611 }
4612
4613 if (NI_RETCODE_SUCCESS != ret)
4614 {
4615 ni_log(NI_LOG_ERROR, "Error: gop config parsing failed %d: %s\n", ret,
4616 ni_get_rc_txt(ret));
4617 break;
4618 }
4619
4620 if (colon_pos)
4621 {
4622 curr = colon_pos + 1;
4623 } else
4624 {
4625 curr += strlen(curr);
4626 }
4627 }
4628
4629 return ret;
4630}
4631
4632/*!*****************************************************************************
4633 * \brief retrieve decoder config parameter values from --decoder-params
4634 *
4635 * \param[in] xcoderParams pointer to string containing xcoder params
4636 * \param[out] params pointer to xcoder params to fill out
4637 * \param[out] ctx pointer to session context
4638 *
4639 * \return return 0 if successful, -1 otherwise
4640 *
4641 ******************************************************************************/
4642int ni_retrieve_decoder_params(char xcoderParams[],
4643 ni_xcoder_params_t *params,
4645{
4646 char key[64], value[64];
4647 char *curr = xcoderParams, *colon_pos;
4648 int ret = 0;
4649
4650 while (*curr)
4651 {
4652 colon_pos = strchr(curr, ':');
4653
4654 if (colon_pos)
4655 {
4656 *colon_pos = '\0';
4657 }
4658
4659 if (strlen(curr) > sizeof(key) + sizeof(value) - 1 ||
4660 ni_param_get_key_value(curr, key, value))
4661 {
4663 "Error: decoder-params p_config key/value not "
4664 "retrieved: %s\n",
4665 curr);
4666 ret = -1;
4667 break;
4668 }
4669 ret = ni_decoder_params_set_value(params, key, value);
4670 switch (ret)
4671 {
4673 ni_log(NI_LOG_ERROR, "Error: unknown option: %s.\n", key);
4674 break;
4676 ni_log(NI_LOG_ERROR, "Error: invalid value for %s: %s.\n", key,
4677 value);
4678 break;
4679 default:
4680 break;
4681 }
4682
4683 if (NI_RETCODE_SUCCESS != ret)
4684 {
4685 ni_log(NI_LOG_ERROR, "Error: config parsing failed %d: %s\n", ret,
4686 ni_get_rc_txt(ret));
4687 break;
4688 }
4689
4690 if (colon_pos)
4691 {
4692 curr = colon_pos + 1;
4693 } else
4694 {
4695 curr += strlen(curr);
4696 }
4697 }
4700
4701 return ret;
4702}
4703
4704/*!*****************************************************************************
4705 * \brief initialize a mutex
4706 *
4707 * \param[in] thread mutex
4708 *
4709 * \return On success returns 0
4710 * On failure returns <0
4711 ******************************************************************************/
4712int ni_pthread_mutex_init(ni_pthread_mutex_t *mutex)
4713{
4714#ifdef _WIN32
4715 bool rc = false;
4716 // error return zero
4717 rc = InitializeCriticalSectionEx(mutex, 0, CRITICAL_SECTION_NO_DEBUG_INFO);
4718 if (rc)
4719 {
4720 return 0;
4721 }
4722 else
4723 {
4724 return -1;
4725 }
4726#else
4727 int rc;
4728 ni_pthread_mutexattr_t attr;
4729
4730 rc = pthread_mutexattr_init(&attr);
4731 if (rc != 0)
4732 {
4733 return -1;
4734 }
4735
4736 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
4737
4738 return pthread_mutex_init(mutex, &attr);
4739#endif
4740}
4741
4742/*!*****************************************************************************
4743 * \brief destory a mutex
4744 *
4745 * \param[in] thread mutex
4746 *
4747 * \return On success returns 0
4748 * On failure returns <0
4749 ******************************************************************************/
4750int ni_pthread_mutex_destroy(ni_pthread_mutex_t *mutex)
4751{
4752#ifdef _WIN32
4753 DeleteCriticalSection(mutex);
4754 return 0;
4755#else
4756 return pthread_mutex_destroy(mutex);
4757#endif
4758}
4759
4760/*!*****************************************************************************
4761 * \brief thread mutex lock
4762 *
4763 * \param[in] thread mutex
4764 *
4765 * \return On success returns 0
4766 * On failure returns <0
4767 ******************************************************************************/
4768int ni_pthread_mutex_lock(ni_pthread_mutex_t *mutex)
4769{
4770 int rc = 0;
4771 if (mutex != NULL)
4772 {
4773#ifdef _WIN32
4774 EnterCriticalSection(mutex);
4775#else
4776 rc = pthread_mutex_lock(mutex);
4777#endif
4778 } else
4779 {
4780 rc = -1;
4781 }
4782
4783 return rc;
4784}
4785
4786/*!*****************************************************************************
4787 * \brief thread mutex unlock
4788 *
4789 * \param[in] thread mutex
4790 *
4791 * \return On success returns 0
4792 * On failure returns <0
4793 ******************************************************************************/
4794int ni_pthread_mutex_unlock(ni_pthread_mutex_t *mutex)
4795{
4796 int rc = 0;
4797 if (mutex != NULL)
4798 {
4799#ifdef _WIN32
4800 LeaveCriticalSection(mutex);
4801#else
4802 rc = pthread_mutex_unlock(mutex);
4803#endif
4804 } else
4805 {
4806 rc = -1;
4807 }
4808
4809 return rc;
4810}
4811
4812#ifdef _WIN32
4813static unsigned __stdcall __thread_worker(void *arg)
4814{
4815 ni_pthread_t *t = (ni_pthread_t *)arg;
4816 t->rc = t->start_routine(t->arg);
4817 return 0;
4818}
4819#endif
4820
4821/*!*****************************************************************************
4822 * \brief create a new thread
4823 *
4824 * \param[in] thread thread id
4825 * \param[in] attr attributes to the new thread
4826 * \param[in] start_routine entry of the thread routine
4827 * \param[in] arg sole argument of the routine
4828 *
4829 * \return On success returns 0
4830 * On failure returns <0
4831 ******************************************************************************/
4832int ni_pthread_create(ni_pthread_t *thread, const ni_pthread_attr_t *attr,
4833 void *(*start_routine)(void *), void *arg)
4834{
4835#ifdef _WIN32
4836 thread->start_routine = start_routine;
4837 thread->arg = arg;
4838 thread->handle =
4839#if HAVE_WINRT
4840 (void *)CreateThread(NULL, 0, win32thread_worker, thread, 0, NULL);
4841#else
4842 (void *)_beginthreadex(NULL, 0, __thread_worker, thread, 0, NULL);
4843#endif
4844 return !thread->handle;
4845#else
4846 return pthread_create(thread, attr, start_routine, arg);
4847#endif
4848}
4849
4850/*!*****************************************************************************
4851 * \brief join with a terminated thread
4852 *
4853 * \param[in] thread thread id
4854 * \param[out] value_ptr return status
4855 *
4856 * \return On success returns 0
4857 * On failure returns <0
4858 ******************************************************************************/
4859int ni_pthread_join(ni_pthread_t thread, void **value_ptr)
4860{
4861#ifdef _WIN32
4862 DWORD rc = WaitForSingleObject(thread.handle, INFINITE);
4863 if (rc != WAIT_OBJECT_0)
4864 {
4865 if (rc == WAIT_ABANDONED)
4866 return EINVAL;
4867 else
4868 return EDEADLK;
4869 }
4870 if (value_ptr)
4871 *value_ptr = thread.rc;
4872 CloseHandle(thread.handle);
4873 return 0;
4874#else
4875 return pthread_join(thread, value_ptr);
4876#endif
4877}
4878
4879/*!*****************************************************************************
4880 * \brief initialize condition variables
4881 *
4882 * \param[in] cond condition variable
4883 * \param[in] attr attribute to the condvar
4884 *
4885 * \return On success returns 0
4886 * On failure returns <0
4887 ******************************************************************************/
4888int ni_pthread_cond_init(ni_pthread_cond_t *cond,
4889 const ni_pthread_condattr_t *attr)
4890{
4891#ifdef _WIN32
4892 InitializeConditionVariable(cond);
4893 return 0;
4894#else
4895 return pthread_cond_init(cond, attr);
4896#endif
4897}
4898
4899/*!*****************************************************************************
4900 * \brief destroy condition variables
4901 *
4902 * \param[in] cond condition variable
4903 *
4904 * \return On success returns 0
4905 * On failure returns <0
4906 ******************************************************************************/
4907int ni_pthread_cond_destroy(ni_pthread_cond_t *cond)
4908{
4909#ifdef _WIN32
4910 /* native condition variables do not destroy */
4911 return 0;
4912#else
4913 return pthread_cond_destroy(cond);
4914#endif
4915}
4916
4917/*!*****************************************************************************
4918 * \brief broadcast a condition
4919 *
4920 * \param[in] cond condition variable
4921 *
4922 * \return On success returns 0
4923 * On failure returns <0
4924 ******************************************************************************/
4925int ni_pthread_cond_broadcast(ni_pthread_cond_t *cond)
4926{
4927#ifdef _WIN32
4928 WakeAllConditionVariable(cond);
4929 return 0;
4930#else
4931 return pthread_cond_broadcast(cond);
4932#endif
4933}
4934
4935/*!*****************************************************************************
4936 * \brief wait on a condition
4937 *
4938 * \param[in] cond condition variable
4939 * \param[in] mutex mutex related to the condvar
4940 *
4941 * \return On success returns 0
4942 * On failure returns <0
4943 ******************************************************************************/
4944int ni_pthread_cond_wait(ni_pthread_cond_t *cond, ni_pthread_mutex_t *mutex)
4945{
4946#ifdef _WIN32
4947 SleepConditionVariableCS(cond, mutex, INFINITE);
4948 return 0;
4949#else
4950 return pthread_cond_wait(cond, mutex);
4951#endif
4952}
4953
4954/*!******************************************************************************
4955 * \brief signal a condition
4956 *
4957 * \param[in] cond condition variable
4958 *
4959 * \return On success returns 0
4960 * On failure returns <0
4961 *******************************************************************************/
4962int ni_pthread_cond_signal(ni_pthread_cond_t *cond)
4963{
4964#ifdef _WIN32
4965 WakeConditionVariable(cond);
4966 return 0;
4967#else
4968 return pthread_cond_signal(cond);
4969#endif
4970}
4971
4972/*!*****************************************************************************
4973 * \brief wait on a condition
4974 *
4975 * \param[in] cond condition variable
4976 * \param[in] mutex mutex related to the condvar
4977 * \param[in[ abstime abstract value of timeout
4978 *
4979 * \return On success returns 0
4980 * On failure returns <0
4981 ******************************************************************************/
4982int ni_pthread_cond_timedwait(ni_pthread_cond_t *cond,
4983 ni_pthread_mutex_t *mutex,
4984 const struct timespec *abstime)
4985{
4986#ifdef _WIN32
4987 int64_t abs_ns = abstime->tv_sec * 1000000000LL + abstime->tv_nsec;
4988 DWORD t = (uint32_t)((abs_ns - ni_gettime_ns()) / 1000000);
4989
4990 if (!SleepConditionVariableCS(cond, mutex, t))
4991 {
4992 DWORD err = GetLastError();
4993 if (err == ERROR_TIMEOUT)
4994 return ETIMEDOUT;
4995 else
4996 return EINVAL;
4997 }
4998 return 0;
4999#else
5000 return pthread_cond_timedwait(cond, mutex, abstime);
5001#endif
5002}
5003
5004/*!*****************************************************************************
5005 * \brief examine and change mask of blocked signals
5006 *
5007 * \param[in] how behavior of this call, can be value of SIG_BLOCK,
5008 * SIG_UNBLOCK and SIG_SETMASK
5009 * \param[in] set current value of the signal mask. If NULL, the mask keeps
5010 * unchanged.
5011 * \param[in] old_set previous value of the signal mask, can be NULL.
5012 *
5013 * \return On success returns 0
5014 * On failure returns <0
5015 ******************************************************************************/
5016int ni_pthread_sigmask(int how, const ni_sigset_t *set, ni_sigset_t *oldset)
5017{
5018#ifdef _WIN32
5019 return 0;
5020#else
5021 return pthread_sigmask(how, set, oldset);
5022#endif
5023}
5024
5025/*!*****************************************************************************
5026 * \brief return error string according to error code from firmware
5027 *
5028 * \param[in] rc error code return from firmware
5029 *
5030 * \return error string
5031 ******************************************************************************/
5032const char *ni_ai_errno_to_str(int rc)
5033{
5034 switch (rc)
5035 {
5037 return "Success";
5039 return "General Error";
5041 return "Not Initialized";
5043 return "Already Initialized";
5045 return "IO Busy";
5047 return "Resource Not Available";
5049 return "Create Network Failed";
5051 return "Input Buffer Full";
5053 return "Output Buffer Empty";
5055 return "Invalid Params";
5057 return "Error Start Network";
5059 return "Erorr Set Inout";
5061 return "Bad Option";
5063 return "Map Error";
5065 return "Context Not Available";
5067 return "Model Not Found";
5069 return "IO Error";
5071 return "Invalid Address";
5073 return "Out Of Memory";
5075 return "Bad Inout";
5077 return "Invalid Instance";
5079 return "IO Not Allowed";
5081 return "Network Not Ready";
5082 default:
5083 return "Other Error";
5084 }
5085}
5086/*!******************************************************************************
5087 * \brief decode the raw current obtained and determine power
5088 *
5089 * \param[in] current_value current value
5090 * \param[in] serial_number board SN
5091 *
5092 * \return On success returns power
5093 * On failure returns -1
5094 ********************************************************************************/
5095uint32_t ni_decode_power_measurement(uint32_t current_data, const uint8_t *serial_number)
5096{
5097 uint32_t power_mw;
5098 float current_ma,voltage_mv;
5099
5100 if ((!serial_number) || (current_data == NI_INVALID_POWER))
5101 {
5102 return NI_INVALID_POWER;
5103 }
5104 char pcb_config[3];
5105 (void)snprintf(pcb_config, sizeof(pcb_config), "%.2s", &serial_number[2]);
5106
5107 float current_value = (float)current_data;
5108 voltage_mv = 12000.0f;
5109 if (strncmp(pcb_config, "A1", 2) == 0)
5110 {
5111 current_ma = (((current_value * 1000) / TPS25940_R_IMON) - TPS25940_IMON_OS) / TPS25940_GAIN_IMON;
5112 }
5113 else if ((strncmp(pcb_config, "A2", 2) == 0) || (strncmp(pcb_config, "A3", 2) == 0))
5114 {
5115 current_ma = ((current_value * MAX15162AAWE_C_IRATIO) / MAX15162AAWE_R_IMON);
5116 }
5117 else if ((strncmp(pcb_config, "AA", 2) == 0) || (strncmp(pcb_config, "AB", 2) == 0))
5118 {
5119 current_ma = (((current_value * 1000) / (TPS25946_R_IMON_T2A * TPS25946_GAIN_IMON)) * 1000);
5120 }
5121 else if (strncmp(pcb_config, "U0", 2) == 0)
5122 {
5123 current_ma = ((((current_value) * MAX17613B_R_ISET_TOTAL / MAX17613B_R_ISET_R2) *
5125 }
5126 else if ((strncmp(pcb_config, "U1", 2) == 0) || (strncmp(pcb_config, "U2", 2) == 0) || (strncmp(pcb_config, "U3", 2) == 0))
5127 {
5128 current_ma = ((1 * current_value * MAX15162AAWE_C_IRATIO) / MAX15162AAWE_R_IMON);
5129 }
5130 else if (strncmp(pcb_config, "UA", 2) == 0)
5131 {
5132 current_ma = (((current_value * 1000) / (TPS25946_R_IMON_T1U_UA * TPS25946_GAIN_IMON)) * 1000);
5133 }
5134 else if (strncmp(pcb_config, "S0", 2) == 0)
5135 {
5136 current_ma = (((current_value * 1000) / (TPS25946_R_IMON_T1S * TPS25946_GAIN_IMON)) * 1000);
5137 }
5138 else if ((strncmp(pcb_config, "M0", 2) == 0) || (strncmp(pcb_config, "M1", 2) == 0))
5139 {
5140 current_ma = ((((current_value * 1000) / (TPS25974_R_IMON_T1M * TPS25974_GAIN_IMON)) * 1000) * MCU_REF_VOLTAGE) / MCU_FSR_ADC;
5141 voltage_mv = 3300.0f;
5142 }
5143 else if (strncmp(pcb_config, "M", 1) == 0) // Other than M0 and M1
5144 {
5145 current_ma = ((current_value * 1000) / (TPS25974_R_IMON_T1M * TPS25974_GAIN_IMON)) * 1000;
5146 voltage_mv = 3300.0f;
5147 }
5148 else
5149 {
5150 return NI_INVALID_POWER;
5151 }
5152 power_mw = (uint32_t)((voltage_mv * current_ma) / 1000.0);
5153 return power_mw;
5154}
5155
5156/*!******************************************************************************
5157 * \brief Check a device can be read by ni_device_capability_query()
5158 * by checking the size of the device using ioctl
5159 *
5160 * INFO OR ERROR logs will not be printed in this function
5161 *
5162 * \param[in] p_dev device path string. eg: "/dev/nvme1n2"
5163 * \param[in] size_needed The minimum required size
5164 *
5165 * \return
5166 * returns -1
5167 * when the device can not be read by ni_device_capability_query()
5168 *
5169 * returns 1
5170 * when the device can be read by ni_device_capability_query()
5171 *
5172 * returns 0 when the result can not be determined
5173 *
5174 *******************************************************************************/
5175static int ni_device_size_precheck_ioctl(const char *p_dev, const uint64_t size_needed)
5176{
5177#if defined(_WIN32) || !defined(BLKGETSIZE64)
5178 (void)p_dev;
5179 (void)size_needed;
5180 return 0;
5181#else
5182 int fd = -1;
5183 int call_ret = 0;
5184 int ret = 0;
5185 uint64_t bytes = 0;
5186
5187 if (!p_dev)
5188 {
5189 return -1;
5190 }
5191
5192 fd = open(p_dev, O_RDONLY);
5193
5194 if (fd < 0)
5195 {
5196 return 0;
5197 }
5198
5199 call_ret = ioctl(fd, BLKGETSIZE64, &bytes);
5200 if (call_ret < 0)
5201 {
5202 ret = 0;
5203 }
5204 else if (bytes < size_needed)
5205 {
5206 ret = -1;
5207 }
5208 else
5209 {
5210 ret = 1;
5211 }
5212
5213 close(fd);
5214 return ret;
5215#endif
5216}
5217
5218/*!******************************************************************************
5219 * \brief Check a device can be read by ni_device_capability_query()
5220 * by checking the vendor id
5221 *
5222 * INFO OR ERROR logs will not be printed in this function
5223 *
5224 * \param[in] p_dev device path string. eg: "/dev/nvme1n2"
5225 *
5226 * \return
5227 * returns -1
5228 * when the device can not be read by ni_device_capability_query()
5229 *
5230 * returns 1
5231 * when the device can be read by ni_device_capability_query()
5232 *
5233 * returns 0 when the result can not be determined
5234 *
5235 *******************************************************************************/
5236static int ni_device_vendor_id_precheck(const char *p_dev)
5237{
5238#ifndef __linux__
5239 (void) p_dev;
5240 return 0;
5241#else
5242
5243 int ret = 0;
5244
5245 if (!p_dev)
5246 {
5247 return -1;
5248 }
5249
5250 const char *vendor_path_devs[] = {"/sys/class/block/%s/device/vendor", "/sys/class/block/%s/device/device/vendor"};
5251
5252 const char *last_slash = strrchr(p_dev, '/');
5253 const char *device_name = (last_slash ? (last_slash + 1) : p_dev);
5254
5255 const size_t path_len = strlen(p_dev);
5256
5257 for (size_t i = 0; i < sizeof(vendor_path_devs)/sizeof(vendor_path_devs[0]); ++i)
5258 {
5259 size_t template_len = strlen(vendor_path_devs[i]);
5260 char *vendor_path = (char *)calloc(1, template_len + path_len);
5261 if (!vendor_path)
5262 {
5263 continue;
5264 }
5265 (void)snprintf(vendor_path, template_len + path_len, vendor_path_devs[i], device_name);
5266
5267 int fd = open(vendor_path, O_RDONLY);
5268 if (fd >= 0)
5269 {
5270 char vendor_id[10] = {0};
5271 ssize_t read_size = read(fd, vendor_id, sizeof(vendor_id));
5272 if (read_size >= 4 && (size_t)read_size < sizeof(vendor_id))
5273 {
5274 char *find_1d82 = strstr(vendor_id, "1d82");
5275 if (find_1d82)
5276 {
5277 ret = 1;
5278 }
5279 else
5280 {
5281 ni_log2(NULL, NI_LOG_DEBUG, "%s() vendor check failed. vendor id: %s", __func__, vendor_id);
5282 ret = -1;
5283 }
5284 }
5285
5286 close(fd);
5287 }
5288
5289 free(vendor_path);
5290
5291 if (ret != 0)
5292 {
5293 break;
5294 }
5295 }
5296
5297 return ret;
5298
5299#endif
5300}
5301
5302
5303/*!******************************************************************************
5304 * \brief Check a device can be read by ni_device_capability_query()
5305 * by reading size from /sys/class/block/<devname>/size and
5306 * /sys/class/block/<devname>/queue/logical_block_size
5307 *
5308 * INFO OR ERROR logs will not be printed in this function
5309 *
5310 * \param[in] p_dev device path string. eg: "/dev/nvme1n2"
5311 * \param[in] size_needed The minimum required size
5312 *
5313 * \return
5314 * returns -1
5315 * when the device can not be read by ni_device_capability_query()
5316 *
5317 * returns 1
5318 * when the device can be read by ni_device_capability_query()
5319 *
5320 * returns 0 when the result can not be determined
5321 *
5322 *******************************************************************************/
5323static int ni_device_size_precheck_system_information(const char *p_dev, const uint64_t size_needed)
5324{
5325#ifndef __linux__
5326 (void) p_dev;
5327 (void) size_needed;
5328 return 0;
5329#else
5330
5331 int ret = 0;
5332
5333 if (!p_dev)
5334 {
5335 return -1;
5336 }
5337
5338 const char block_path_dev[] = "/sys/class/block/%s/size";
5339 const char logical_block_size_path_dev[] = "/sys/class/block/%s/queue/logical_block_size";
5340
5341 const char *last_slash = strrchr(p_dev, '/');
5342 const char *device_name = (last_slash ? (last_slash + 1) : p_dev);
5343
5344 const size_t path_len = strlen(p_dev);
5345
5346 int size_fd = -1;
5347 int logical_block_fd = -1;
5348
5349 char *block_path = (char *)calloc(1, sizeof(block_path_dev) + path_len);
5350 char *logical_block_size_path = (char *)calloc(1, sizeof(logical_block_size_path_dev) + path_len);
5351
5352 if (!block_path || !logical_block_size_path)
5353 {
5354 LRETURN;
5355 }
5356
5357 (void)snprintf(block_path, sizeof(block_path_dev) + path_len, block_path_dev, device_name);
5358 (void)snprintf(logical_block_size_path, sizeof(logical_block_size_path_dev) + path_len, logical_block_size_path_dev, device_name);
5359
5360 size_fd = open(block_path, O_RDONLY);
5361 logical_block_fd = open(logical_block_size_path, O_RDONLY);
5362
5363 if (size_fd < 0 || logical_block_fd < 0)
5364 {
5365 LRETURN;
5366 }
5367
5368 char this_size_str [20] = {0};
5369 char this_block_size_str [20] = {0};
5370
5371 if (read(size_fd, this_size_str, sizeof(this_size_str)) <= 0 || read(logical_block_fd, this_block_size_str, sizeof(this_block_size_str)) <= 0)
5372 {
5373 ret = 0;
5374 }
5375 else
5376 {
5377 char *endptr1 = NULL;
5378 char *endptr2 = NULL;
5379 errno = 0;
5380 unsigned long long this_size = strtoull(this_size_str, &endptr1, 10);
5381 unsigned long long this_block_size = strtoull(this_block_size_str, &endptr2, 10);
5382
5383 if (errno == 0 && endptr1 != this_size_str && endptr2 != this_block_size_str)
5384 {
5385 if (this_size * this_block_size >= size_needed)
5386 {
5387 ret = 1;
5388 }
5389 else
5390 {
5391 ni_log2(NULL, NI_LOG_DEBUG, "%s() read size check failed. size: %" PRIu64 "\n", __func__, this_size * this_block_size);
5392 ret = -1;
5393 }
5394 }
5395 }
5396
5397END:
5398 if (block_path)
5399 {
5400 free(block_path);
5401 }
5402 if (logical_block_size_path)
5403 {
5404 free(logical_block_size_path);
5405 }
5406
5407 if (size_fd >= 0)
5408 {
5409 close(size_fd);
5410 }
5411 if (logical_block_fd >= 0)
5412 {
5413 close(logical_block_fd);
5414 }
5415
5416 return ret;
5417
5418#endif
5419}
5420
5421/*!******************************************************************************
5422 * \brief precheck a device can be read by ni_device_capability_query()
5423 * INFO OR ERROR logs will not be printed in this function
5424 * \param[in] p_dev device path string. eg: "/dev/nvme1n2"
5425 *
5426 * \return
5427 * returns NI_RETCODE_FAILURE
5428 * when the device can not be read by ni_device_capability_query()
5429 *
5430 * returns NI_RETCODE_SUCCESS when
5431 * 1. the device can not be read by ni_device_capability_query()
5432 * 2. the result can not be determined to prevent query failures due to
5433 * some reasons such as missing commands on the system
5434 *******************************************************************************/
5436{
5437#ifndef __linux__
5438 (void) p_dev;
5439 return 0;
5440#else
5441 int ret = 0;
5442
5443 const uint64_t SIZE_NEEDED = ((IDENTIFY_DEVICE_R) << (LBA_BIT_OFFSET)) + (NI_NVME_IDENTITY_CMD_DATA_SZ);
5444
5445 if (!p_dev)
5446 {
5447 return NI_RETCODE_FAILURE;
5448 }
5449
5450 const size_t path_len = strlen(p_dev);
5451
5452 if (path_len > NI_MAX_DEVICE_NAME_LEN)
5453 {
5454 return NI_RETCODE_FAILURE;
5455 }
5456
5457 ret = ni_device_size_precheck_ioctl(p_dev, SIZE_NEEDED);
5458 if (ret > 0)
5459 {
5460 return NI_RETCODE_SUCCESS;
5461 }
5462 if (ret < 0)
5463 {
5464 return NI_RETCODE_FAILURE;
5465 }
5466
5467 ret = ni_device_vendor_id_precheck(p_dev);
5468 if (ret > 0)
5469 {
5470 return NI_RETCODE_SUCCESS;
5471 }
5472 if (ret < 0)
5473 {
5474 return NI_RETCODE_FAILURE;
5475 }
5476
5477 ret = ni_device_size_precheck_system_information(p_dev, SIZE_NEEDED);
5478 if (ret > 0)
5479 {
5480 return NI_RETCODE_SUCCESS;
5481 }
5482 if (ret < 0)
5483 {
5484 return NI_RETCODE_FAILURE;
5485 }
5486
5487 // ret == 0 here: prechecks were inconclusive, default to success
5488 return NI_RETCODE_SUCCESS;
5489
5490#endif
5491}
#define NI_DEPRECATED
Definition ni_defs.h:80
#define NI_XCODER_REVISION_API_MAJOR_VER_IDX
Definition ni_defs.h:99
#define END
Definition ni_defs.h:338
#define NI_XCODER_REVISION
Definition ni_defs.h:98
#define LIBXCODER_API_VERSION
Definition ni_defs.h:115
#define NI_MAX_NUM_DATA_POINTERS
Definition ni_defs.h:244
#define NI_MAX_DEVICE_NAME_LEN
Definition ni_defs.h:236
#define ni_assert(expression)
Definition ni_defs.h:341
#define NI_MEM_PAGE_ALIGNMENT
Definition ni_defs.h:263
#define NI_FW_META_DATA_SZ
Definition ni_defs.h:320
#define QUADRA
Definition ni_defs.h:123
#define LRETURN
Definition ni_defs.h:337
@ NI_AI_STATUS_CREATE_NETWORK_FAILED
Definition ni_defs.h:617
@ NI_AI_STATUS_IO_NOT_ALLOWED
Definition ni_defs.h:632
@ NI_AI_STATUS_NETWORK_NOT_READY
Definition ni_defs.h:633
@ NI_AI_STATUS_GENERIC_ERROR
Definition ni_defs.h:612
@ NI_AI_STATUS_CONTEXT_NOT_AVAILABLE
Definition ni_defs.h:625
@ NI_AI_STATUS_OUT_OF_MEMORY
Definition ni_defs.h:629
@ NI_AI_STATUS_INVALID_ADDRESS
Definition ni_defs.h:628
@ NI_AI_STATUS_MAP_ERROR
Definition ni_defs.h:624
@ NI_AI_STATUS_RESOURCE_NOT_AVAILABLE
Definition ni_defs.h:616
@ NI_AI_STATUS_ALREADY_INITIALIZED
Definition ni_defs.h:614
@ NI_AI_STATUS_MODEL_NOT_FOUND
Definition ni_defs.h:626
@ NI_AI_STATUS_INVALID_PARAMS
Definition ni_defs.h:620
@ NI_AI_STATUS_IO_ERROR
Definition ni_defs.h:627
@ NI_AI_STATUS_NOT_INITIALIZED
Definition ni_defs.h:613
@ NI_AI_STATUS_INPUT_BUFFER_FULL
Definition ni_defs.h:618
@ NI_AI_STATUS_BAD_OPTION
Definition ni_defs.h:623
@ NI_AI_STATUS_BAD_INOUT
Definition ni_defs.h:630
@ NI_AI_STATUS_SUCCESS
Definition ni_defs.h:611
@ NI_AI_STATUS_ERROR_START_NETWORK
Definition ni_defs.h:621
@ NI_AI_STATUS_IO_BUSY
Definition ni_defs.h:615
@ NI_AI_STATUS_ERROR_SET_INOUT
Definition ni_defs.h:622
@ NI_AI_STATUS_INVALID_INSTANCE
Definition ni_defs.h:631
@ NI_AI_STATUS_OUTPUT_BUFFER_EMPTY
Definition ni_defs.h:619
ni_retcode_t
Definition ni_defs.h:447
@ NI_RETCODE_ERROR_LOCK_DOWN_DEVICE
Definition ni_defs.h:528
@ NI_RETCODE_PARAM_ERROR_MX_NUM_MERGE
Definition ni_defs.h:472
@ NI_RETCODE_PARAM_ERROR_INTRA_PERIOD
Definition ni_defs.h:466
@ NI_RETCODE_PARAM_ERROR_TRATE
Definition ni_defs.h:463
@ NI_RETCODE_PARAM_WARNING_DEPRECATED
Definition ni_defs.h:537
@ NI_RETCODE_PARAM_ERROR_HEIGHT_TOO_BIG
Definition ni_defs.h:519
@ NI_RETCODE_PARAM_ERROR_BRATE
Definition ni_defs.h:461
@ NI_RETCODE_NVME_SC_STREAM_ERROR
Definition ni_defs.h:566
@ NI_RETCODE_PARAM_ERROR_ZERO
Definition ni_defs.h:513
@ NI_RETCODE_PARAM_ERROR_HVS_QP_EN
Definition ni_defs.h:478
@ NI_RETCODE_FAILURE
Definition ni_defs.h:449
@ NI_RETCODE_PARAM_ERROR_VBV_BUFFER_SIZE
Definition ni_defs.h:465
@ NI_RETCODE_PARAM_ERROR_PICSKIP
Definition ni_defs.h:541
@ NI_RETCODE_NVME_SC_INTERLACED_NOT_SUPPORTED
Definition ni_defs.h:567
@ NI_RETCODE_PARAM_ERROR_HVS_QP_SCL
Definition ni_defs.h:479
@ NI_RETCODE_NVME_SC_REQUEST_NOT_COMPLETED
Definition ni_defs.h:562
@ NI_RETCODE_PARAM_ERROR_CUSIZE_MODE_8X8_EN
Definition ni_defs.h:507
@ NI_RETCODE_PARAM_ERROR_FILLER
Definition ni_defs.h:540
@ NI_RETCODE_PARAM_ERROR_CUSIZE_MODE_32X32_EN
Definition ni_defs.h:509
@ NI_RETCODE_PARAM_ERROR_RCENABLE
Definition ni_defs.h:497
@ NI_RETCODE_PARAM_ERROR_MX_DELTA_QP
Definition ni_defs.h:484
@ NI_RETCODE_PARAM_ERROR_LOOK_AHEAD_DEPTH
Definition ni_defs.h:538
@ NI_RETCODE_PARAM_ERROR_CONF_WIN_R
Definition ni_defs.h:492
@ NI_RETCODE_NVME_SC_RESOURCE_NOT_FOUND
Definition ni_defs.h:560
@ NI_RETCODE_ERROR_INVALID_SESSION
Definition ni_defs.h:454
@ NI_RETCODE_PARAM_ERROR_CU_SIZE_MODE
Definition ni_defs.h:471
@ NI_RETCODE_PARAM_ERROR_CONF_WIN_BOT
Definition ni_defs.h:488
@ NI_RETCODE_PARAM_ERROR_MN_QP
Definition ni_defs.h:480
@ NI_RETCODE_NVME_SC_INVALID_PARAMETER
Definition ni_defs.h:565
@ NI_RETCODE_ERROR_GET_DEVICE_POOL
Definition ni_defs.h:527
@ NI_RETCODE_PARAM_ERROR_PIC_WIDTH
Definition ni_defs.h:501
@ NI_RETCODE_PARAM_ERROR_CONF_WIN_TOP
Definition ni_defs.h:486
@ NI_RETCODE_PARAM_ERROR_CONF_WIN_L
Definition ni_defs.h:490
@ NI_RETCODE_PARAM_ERROR_DECODING_REFRESH_TYPE
Definition ni_defs.h:505
@ NI_RETCODE_ERROR_UNLOCK_DEVICE
Definition ni_defs.h:530
@ NI_RETCODE_PARAM_INVALID_NAME
Definition ni_defs.h:457
@ NI_RETCODE_PARAM_ERROR_AREA_TOO_BIG
Definition ni_defs.h:523
@ NI_RETCODE_PARAM_ERROR_FRATE
Definition ni_defs.h:459
@ NI_RETCODE_NVME_SC_WRITE_BUFFER_FULL
Definition ni_defs.h:555
@ NI_RETCODE_PARAM_ERROR_BRATE_LT_TRATE
Definition ni_defs.h:496
@ NI_RETCODE_NVME_SC_VPU_RECOVERY
Definition ni_defs.h:568
@ NI_RETCODE_ERROR_STREAM_ERROR
Definition ni_defs.h:545
@ NI_RETCODE_SUCCESS
Definition ni_defs.h:448
@ NI_RETCODE_PARAM_ERROR_HEIGHT_TOO_SMALL
Definition ni_defs.h:521
@ NI_RETCODE_PARAM_WARN
Definition ni_defs.h:547
@ NI_RETCODE_ERROR_INVALID_HANDLE
Definition ni_defs.h:532
@ NI_RETCODE_PARAM_ERROR_TOO_BIG
Definition ni_defs.h:510
@ NI_RETCODE_PARAM_INVALID_VALUE
Definition ni_defs.h:458
@ NI_RETCODE_ERROR_RESOURCE_UNAVAILABLE
Definition ni_defs.h:455
@ NI_RETCODE_PARAM_ERROR_CU_LVL_RC_EN
Definition ni_defs.h:476
@ NI_RETCODE_PARAM_ERROR_INTRA_QP
Definition ni_defs.h:468
@ NI_RETCODE_ERROR_EXCEED_MAX_NUM_SESSIONS
Definition ni_defs.h:525
@ NI_RETCODE_PARAM_ERROR_MAXNUMMERGE
Definition ni_defs.h:498
@ NI_RETCODE_NVME_SC_RESOURCE_IS_EMPTY
Definition ni_defs.h:558
@ NI_RETCODE_PARAM_ERROR_DY_MERGE_32X32_EN
Definition ni_defs.h:475
@ NI_RETCODE_NVME_SC_RESOURCE_UNAVAILABLE
Definition ni_defs.h:557
@ NI_RETCODE_PARAM_ERROR_DY_MERGE_16X16_EN
Definition ni_defs.h:474
@ NI_RETCODE_NVME_SC_VPU_GENERAL_ERROR
Definition ni_defs.h:571
@ NI_RETCODE_PARAM_ERROR_GOP_PRESET
Definition ni_defs.h:469
@ NI_RETCODE_ERROR_INVALID_ALLOCATION_METHOD
Definition ni_defs.h:534
@ NI_RETCODE_PARAM_ERROR_WIDTH_TOO_BIG
Definition ni_defs.h:515
@ NI_RETCODE_ERROR_NVME_CMD_FAILED
Definition ni_defs.h:453
@ NI_RETCODE_PARAM_ERROR_USR_RMD_ENC_PARAM
Definition ni_defs.h:494
@ NI_RETCODE_PARAM_ERROR_PIC_HEIGHT
Definition ni_defs.h:503
@ NI_RETCODE_NVME_SC_VPU_RSRC_INSUFFICIENT
Definition ni_defs.h:569
@ NI_RETCODE_ERROR_MEM_ALOC
Definition ni_defs.h:452
@ NI_RETCODE_PARAM_ERROR_OOR
Definition ni_defs.h:514
@ NI_RETCODE_PARAM_ERROR_CUSIZE_MODE_16X16_EN
Definition ni_defs.h:508
@ NI_RETCODE_PARAM_ERROR_DY_MERGE_8X8_EN
Definition ni_defs.h:473
@ NI_RETCODE_ERROR_VPU_RECOVERY
Definition ni_defs.h:536
@ NI_RETCODE_PARAM_ERROR_WIDTH_TOO_SMALL
Definition ni_defs.h:517
@ NI_RETCODE_PARAM_ERROR_CUSTOM_GOP
Definition ni_defs.h:499
@ NI_RETCODE_INVALID_PARAM
Definition ni_defs.h:450
@ NI_RETCODE_PARAM_ERROR_TOO_SMALL
Definition ni_defs.h:511
@ NI_RETCODE_NVME_SC_REQUEST_IN_PROGRESS
Definition ni_defs.h:563
@ NI_RETCODE_ERROR_OPEN_DEVICE
Definition ni_defs.h:531
@ NI_RETCODE_PARAM_ERROR_MX_QP
Definition ni_defs.h:482
#define NI_XCODER_REVISION_API_MINOR_VER_IDX
Definition ni_defs.h:100
#define NI_UNUSED
Definition ni_defs.h:67
ni_retcode_t ni_decoder_params_set_value(ni_xcoder_params_t *p_params, const char *name, char *value)
Set value referenced by name in decoder parameters structure.
ni_retcode_t ni_encoder_params_set_value(ni_xcoder_params_t *p_params, const char *name, const char *value)
Set value referenced by name in encoder parameters structure.
ni_retcode_t ni_encoder_gop_params_set_value(ni_xcoder_params_t *p_params, const char *name, const char *value)
Set GOP parameter value referenced by name in encoder parameters structure.
#define NI_MIN_HEIGHT
#define NI_MIN_WIDTH
#define NI_VPU_ALIGN16(_x)
#define NI_MAX_SEI_DATA
#define NI_VPU_ALIGN128(_x)
@ NI_AI_BUFFER_QUANTIZE_DYNAMIC_FIXED_POINT
@ NI_AI_BUFFER_QUANTIZE_NONE
@ NI_AI_BUFFER_QUANTIZE_TF_ASYMM
enum _ni_ai_buffer_format_e ni_ai_buffer_format_e
ni_pix_fmt_t
@ NI_PIX_FMT_ARGB
@ NI_PIX_FMT_P010LE
@ NI_PIX_FMT_YUV420P
@ NI_PIX_FMT_ABGR
@ NI_PIX_FMT_BGR0
@ NI_PIX_FMT_YUYV422
@ NI_PIX_FMT_RGBA
@ NI_PIX_FMT_NV12
@ NI_PIX_FMT_BGRA
@ NI_PIX_FMT_NV16
@ NI_PIX_FMT_UYVY422
@ NI_PIX_FMT_YUV420P10LE
@ NI_AI_BUFFER_FORMAT_INT8
@ NI_AI_BUFFER_FORMAT_FP64
@ NI_AI_BUFFER_FORMAT_FP32
@ NI_AI_BUFFER_FORMAT_UINT16
@ NI_AI_BUFFER_FORMAT_UINT8
@ NI_AI_BUFFER_FORMAT_BFP16
@ NI_AI_BUFFER_FORMAT_FP16
@ NI_AI_BUFFER_FORMAT_INT64
@ NI_AI_BUFFER_FORMAT_UINT32
@ NI_AI_BUFFER_FORMAT_INT32
@ NI_AI_BUFFER_FORMAT_INT16
@ NI_AI_BUFFER_FORMAT_UINT64
#define NI_VPU_ALIGN64(_x)
void ni_log2(const void *p_context, ni_log_level_t level, const char *fmt,...)
print log message and additional information using ni_log_callback,
Definition ni_log.c:337
void ni_log(ni_log_level_t level, const char *fmt,...)
print log message using ni_log_callback
Definition ni_log.c:183
@ NI_LOG_DEBUG
Definition ni_log.h:64
@ NI_LOG_TRACE
Definition ni_log.h:65
@ NI_LOG_FATAL
Definition ni_log.h:61
@ NI_LOG_ERROR
Definition ni_log.h:62
@ NI_LOG_INFO
Definition ni_log.h:63
Private definitions for interfacing with NETINT video processing devices over NVMe.
#define LBA_BIT_OFFSET
Definition ni_nvme.h:628
#define IDENTIFY_DEVICE_R
Definition ni_nvme.h:692
#define NI_NVME_IDENTITY_CMD_DATA_SZ
Definition ni_nvme.h:38
#define EP1(x)
Definition ni_util.c:4106
ni_queue_node_t * ni_buffer_pool_get_queue_buffer(ni_queue_buffer_pool_t *p_buffer_pool)
Definition ni_util.c:1560
int ni_pthread_cond_init(ni_pthread_cond_t *cond, const ni_pthread_condattr_t *attr)
initialize condition variables
Definition ni_util.c:4888
#define NI_AI_EPSILON
ni_retcode_t ni_timestamp_register(ni_queue_buffer_pool_t *p_buffer_pool, ni_timestamp_table_t *p_table, int64_t timestamp, uint64_t data_info)
Register timestamp in timestamp/frameoffset table.
Definition ni_util.c:2013
ni_retcode_t ni_queue_pop(ni_queue_t *p_queue, uint64_t frame_info, int64_t *p_timestamp, int32_t threshold, int32_t print, ni_queue_buffer_pool_t *p_buffer_pool)
Pop from the xcoder queue.
Definition ni_util.c:2252
#define CH(x, y, z)
Definition ni_util.c:4103
int ni_pthread_mutex_lock(ni_pthread_mutex_t *mutex)
thread mutex lock
Definition ni_util.c:4768
int ni_remove_emulation_prevent_bytes(uint8_t *buf, int size)
Remove emulation prevention byte(s) as needed from the data buffer.
Definition ni_util.c:3348
ni_retcode_t ni_queue_pop_threshold(ni_queue_t *p_queue, uint64_t frame_info, int64_t *p_timestamp, int32_t threshold, int32_t print, ni_queue_buffer_pool_t *p_buffer_pool)
Definition ni_util.c:2358
int ni_pthread_cond_destroy(ni_pthread_cond_t *cond)
destroy condition variables
Definition ni_util.c:4907
void ni_SHA256Update(SHA256CTX *psCtx, const uint8_t aui8Data[], size_t ui32Length)
Definition ni_util.c:4183
void ni_copy_frame_data(uint8_t *p_dst[NI_MAX_NUM_DATA_POINTERS], uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS], int frame_width, int frame_height, int factor, ni_pix_fmt_t pix_fmt, int conf_win_right, int dst_stride[NI_MAX_NUM_DATA_POINTERS], int dst_height[NI_MAX_NUM_DATA_POINTERS], int src_stride[NI_MAX_NUM_DATA_POINTERS], int src_height[NI_MAX_NUM_DATA_POINTERS])
Copy RGBA or YUV data to Netint HW frame layout to be sent to encoder for encoding....
Definition ni_util.c:3102
void ni_buffer_pool_free(ni_queue_buffer_pool_t *p_buffer_pool)
Definition ni_util.c:1427
uint32_t ni_ai_network_layer_dims(ni_network_layer_params_t *p_param)
Definition ni_util.c:4076
void ni_dec_fme_buffer_pool_free(ni_buf_pool_t *p_buffer_pool)
Definition ni_util.c:1373
int32_t ni_parse_name(const char *arg, const char *const *names, bool *b_error)
Parse name.
Definition ni_util.c:2673
ni_retcode_t ni_quadra_card_identify_precheck(const char *p_dev)
precheck a device can be read by ni_device_capability_query() INFO OR ERROR logs will not be printed ...
Definition ni_util.c:5435
ni_retcode_t ni_strncpy(char *dest, size_t dmax, const char *src, size_t slen)
Definition ni_util.c:525
void ni_SHA256Transform(SHA256CTX *psCtx, const uint8_t aui8Data[])
Definition ni_util.c:4123
void ni_copy_yuv_444p_to_420p(uint8_t *p_dst0[NI_MAX_NUM_DATA_POINTERS], uint8_t *p_dst1[NI_MAX_NUM_DATA_POINTERS], uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS], int frame_width, int frame_height, int factor, int mode)
Copy yuv444p data to yuv420p frame layout to be sent to encoder for encoding. Data buffer (dst) is us...
Definition ni_util.c:3182
ni_retcode_t ni_queue_init(ni_session_context_t *p_ctx, ni_queue_t *p_queue, const char *name)
Initialize xcoder queue.
Definition ni_util.c:2154
#define SIG0(x)
Definition ni_util.c:4107
void ni_SHA256Final(SHA256CTX *psCtx, uint8_t aui8Hash[])
Definition ni_util.c:4201
ni_retcode_t ni_queue_print(ni_queue_t *p_queue)
Print xcoder queue info.
Definition ni_util.c:2493
ni_queue_node_t * ni_buffer_pool_allocate_buffer(ni_queue_buffer_pool_t *p_buffer_pool)
Definition ni_util.c:1471
uint64_t ni_get_utime(void)
Get system time for log.
Definition ni_util.c:2694
void ni_copy_plane_data(uint8_t *p_dst[NI_MAX_NUM_DATA_POINTERS], uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS], int frame_width, int frame_height, int factor, int is_semiplanar, int conf_win_right, int dst_stride[NI_MAX_NUM_DATA_POINTERS], int dst_height[NI_MAX_NUM_DATA_POINTERS], int src_stride[NI_MAX_NUM_DATA_POINTERS], int src_height[NI_MAX_NUM_DATA_POINTERS], int i)
Copy RGBA or YUV data to Netint HW frame layout to be sent to encoder for encoding....
Definition ni_util.c:2932
int ni_pthread_cond_signal(ni_pthread_cond_t *cond)
signal a condition
Definition ni_util.c:4962
int ni_retrieve_xcoder_params(char xcoderParams[], ni_xcoder_params_t *params, ni_session_context_t *ctx)
retrieve encoder config parameter values from –xcoder-params
Definition ni_util.c:4497
ni_buf_t * ni_buf_pool_allocate_buffer(ni_buf_pool_t *p_buffer_pool, int buffer_size)
Definition ni_util.c:1222
int32_t ni_get_frame_index(uint32_t *value)
Get xcoder instance id.
Definition ni_util.c:1660
int ni_posix_memalign(void **memptr, size_t alignment, size_t size)
Allocate aligned memory.
Definition ni_util.c:206
int ni_fscanf(FILE *stream, const char *fmt,...)
Definition ni_util.c:1035
int ni_pthread_create(ni_pthread_t *thread, const ni_pthread_attr_t *attr, void *(*start_routine)(void *), void *arg)
create a new thread
Definition ni_util.c:4832
void ni_get_min_frame_dim(int width, int height, ni_pix_fmt_t pix_fmt, int plane_stride[NI_MAX_NUM_DATA_POINTERS], int plane_height[NI_MAX_NUM_DATA_POINTERS])
Get dimension information of frame to be sent to encoder for encoding. Caller usually retrieves this ...
Definition ni_util.c:2884
ni_retcode_t ni_strncat(char *dest, size_t dmax, const char *src, size_t slen)
Definition ni_util.c:822
ni_buf_t * ni_buf_pool_get_buffer(ni_buf_pool_t *p_buffer_pool)
Definition ni_util.c:1105
void ni_fmt_fw_api_ver_str(const char ver_str[], char fmt_str[])
Get formatted FW API version string from unformatted FW API version string.
Definition ni_util.c:4353
const char * ni_ai_errno_to_str(int rc)
return error string according to error code from firmware
Definition ni_util.c:5032
int ni_pthread_cond_broadcast(ni_pthread_cond_t *cond)
broadcast a condition
Definition ni_util.c:4925
int32_t ni_gettimeofday(struct timeval *p_tp, void *p_tzp)
Get time for logs with microsecond timestamps.
Definition ni_util.c:147
ni_retcode_t ni_strtod_val(const char *str, double *out_val)
Safely convert a decimal string to a double with full validation. Trailing whitespace is tolerated.
Definition ni_util.c:2612
ni_retcode_t ni_strerror(char *dest, size_t dmax, int errnum)
Definition ni_util.c:663
ni_retcode_t ni_network_convert_tensor_to_data(uint8_t *dst, uint32_t dst_len, float *src, uint32_t src_len, ni_network_layer_params_t *p_param)
Definition ni_util.c:3953
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:4464
void ni_calculate_sha256(const uint8_t aui8Data[], size_t ui32DataLength, uint8_t aui8Hash[])
Definition ni_util.c:4257
int ni_pthread_mutex_destroy(ni_pthread_mutex_t *mutex)
destory a mutex
Definition ni_util.c:4750
int32_t ni_dec_fme_buffer_pool_initialize(ni_session_context_t *p_ctx, int32_t number_of_buffers, int width, int height, int height_align, int factor)
Definition ni_util.c:1264
ni_retcode_t ni_timestamp_get_with_threshold(ni_timestamp_table_t *p_table, uint64_t frame_info, int64_t *p_timestamp, int32_t threshold, int32_t print, ni_queue_buffer_pool_t *p_buffer_pool)
Definition ni_util.c:2064
void ni_copy_hw_descriptors(uint8_t *p_dst[NI_MAX_NUM_DATA_POINTERS], uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS])
Copy Descriptor data to Netint HW descriptor frame layout to be sent to encoder for encoding....
Definition ni_util.c:4283
int32_t ni_atobool(const char *p_str, bool *b_error)
Convert string to boolean.
Definition ni_util.c:2550
uint32_t ni_round_up(uint32_t number_to_round, uint32_t multiple)
Definition ni_util.c:177
ni_retcode_t ni_strcat(char *dest, size_t dmax, const char *src)
Definition ni_util.c:704
void ni_get_hw_yuv420p_dim(int width, int height, int factor, int is_semiplanar, int plane_stride[NI_MAX_NUM_DATA_POINTERS], int plane_height[NI_MAX_NUM_DATA_POINTERS])
Get dimension information of Netint HW YUV420p frame to be sent to encoder for encoding....
Definition ni_util.c:2743
char * ni_strtok(char *s, const char *delim, char **saveptr)
Definition ni_util.c:429
void ni_SHA256Init(SHA256CTX *psCtx)
Definition ni_util.c:4169
#define SIG1(x)
Definition ni_util.c:4108
ni_retcode_t ni_fopen(FILE **fp, const char *filename, const char *mode)
Definition ni_util.c:998
ni_retcode_t ni_network_layer_convert_output(float *dst, uint32_t dst_len, ni_packet_t *p_packet, ni_network_data_t *p_network, uint32_t layer)
Definition ni_util.c:3788
ni_retcode_t ni_queue_push(ni_queue_buffer_pool_t *p_buffer_pool, ni_queue_t *p_queue, uint64_t frame_info, int64_t timestamp)
Push into xcoder queue.
Definition ni_util.c:2181
int ni_pthread_sigmask(int how, const ni_sigset_t *set, ni_sigset_t *oldset)
examine and change mask of blocked signals
Definition ni_util.c:5016
ni_retcode_t ni_strcpy(char *dest, size_t dmax, const char *src)
Definition ni_util.c:460
uint32_t ni_ai_network_layer_size(ni_network_layer_params_t *p_param)
Definition ni_util.c:4070
struct ni_err_rc_txt_entry ni_err_rc_txt_entry_t
const char * ni_get_rc_txt(ni_retcode_t rc)
Get text string for the provided error.
Definition ni_util.c:4440
ni_retcode_t ni_timestamp_get(ni_timestamp_table_t *p_table, uint64_t frame_info, int64_t *p_timestamp, int32_t threshold, int32_t print, ni_queue_buffer_pool_t *p_buffer_pool)
Retrieve timestamp from table based on frameoffset info.
Definition ni_util.c:2040
ni_buf_t * ni_buf_pool_expand(ni_buf_pool_t *pool)
Definition ni_util.c:1088
int ni_pthread_cond_timedwait(ni_pthread_cond_t *cond, ni_pthread_mutex_t *mutex, const struct timespec *abstime)
wait on a condition
Definition ni_util.c:4982
int32_t ni_atoi(const char *p_str, bool *b_error)
Definition ni_util.c:2633
ni_retcode_t ni_timestamp_init(ni_session_context_t *p_ctx, ni_timestamp_table_t **pp_table, const char *name)
Initialize timestamp handling.
Definition ni_util.c:1948
int ni_retrieve_decoder_params(char xcoderParams[], ni_xcoder_params_t *params, ni_session_context_t *ctx)
retrieve decoder config parameter values from –decoder-params
Definition ni_util.c:4642
int32_t ni_buffer_pool_initialize(ni_session_context_t *p_ctx, int32_t number_of_buffers)
Definition ni_util.c:1500
int ni_retrieve_xcoder_gop(char xcoderGop[], ni_xcoder_params_t *params, ni_session_context_t *ctx)
Retrieve custom gop config values from –xcoder-gop.
Definition ni_util.c:4571
void ni_usleep(int64_t usec)
Definition ni_util.c:366
struct tm * ni_localtime(struct tm *dest, const time_t *src)
Definition ni_util.c:1018
ni_retcode_t ni_find_blk_name(const char *p_dev, char *p_out_buf, int out_buf_len)
Find NVMe name space block from device name If none is found, assume nvme multi-pathing is disabled a...
Definition ni_util.c:1821
int ni_vsprintf(char *dest, const size_t dmax, const char *fmt, va_list args)
Definition ni_util.c:1054
char * ni_get_libxcoder_api_ver(void)
Get libxcoder API version.
Definition ni_util.c:4307
#define EP0(x)
Definition ni_util.c:4105
void ni_buf_pool_return_buffer(ni_buf_t *buf, ni_buf_pool_t *p_buffer_pool)
Definition ni_util.c:1166
double ni_atof(const char *p_str, bool *b_error)
Convert string to floating.
Definition ni_util.c:2653
ni_retcode_t ni_queue_free(ni_queue_t *p_queue, ni_queue_buffer_pool_t *p_buffer_pool)
Free xcoder queue.
Definition ni_util.c:2453
NI_DEPRECATED char * ni_get_compat_fw_api_ver(void)
Get FW API version libxcoder is compatible with. Deprecated in favour of ni_fmt_fw_api_ver_str(&NI_XC...
Definition ni_util.c:4320
uint64_t ni_gettime_ns(void)
Definition ni_util.c:2701
void ni_timestamp_scan_cleanup(ni_timestamp_table_t *pts_list, ni_timestamp_table_t *dts_list, ni_queue_buffer_pool_t *p_buffer_pool)
Definition ni_util.c:2072
int ni_pthread_join(ni_pthread_t thread, void **value_ptr)
join with a terminated thread
Definition ni_util.c:4859
ni_retcode_t ni_network_layer_convert_tensor(uint8_t *dst, uint32_t dst_len, const char *tensor_file, ni_network_layer_params_t *p_param)
Definition ni_util.c:3943
int ni_insert_emulation_prevent_bytes(uint8_t *buf, int size)
Insert emulation prevention byte(s) as needed into the data buffer.
Definition ni_util.c:3295
void ni_get_frame_dim(int width, int height, ni_pix_fmt_t pix_fmt, int plane_stride[NI_MAX_NUM_DATA_POINTERS], int plane_height[NI_MAX_NUM_DATA_POINTERS])
Get dimension information of frame to be sent to encoder for encoding. Caller usually retrieves this ...
Definition ni_util.c:2795
int ni_pthread_mutex_unlock(ni_pthread_mutex_t *mutex)
thread mutex unlock
Definition ni_util.c:4794
int ni_sprintf(char *dest, size_t dmax, const char *fmt,...)
Definition ni_util.c:1077
char * ni_get_libxcoder_release_ver(void)
Get libxcoder SW release version.
Definition ni_util.c:4419
int ni_pthread_mutex_init(ni_pthread_mutex_t *mutex)
initialize a mutex
Definition ni_util.c:4712
ni_retcode_t ni_check_dev_name(const char *p_dev)
check dev name
Definition ni_util.c:1892
ni_retcode_t ni_network_convert_data_to_tensor(float *dst, uint32_t dst_len, uint8_t *src, uint32_t src_len, ni_network_layer_params_t *p_param)
Definition ni_util.c:3963
int ni_pthread_cond_wait(ni_pthread_cond_t *cond, ni_pthread_mutex_t *mutex)
wait on a condition
Definition ni_util.c:4944
#define MAJ(x, y, z)
Definition ni_util.c:4104
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
ni_queue_node_t * ni_buffer_pool_expand(ni_queue_buffer_pool_t *pool)
Definition ni_util.c:1542
void ni_copy_hw_yuv420p(uint8_t *p_dst[NI_MAX_NUM_DATA_POINTERS], uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS], int frame_width, int frame_height, int factor, int is_semiplanar, int conf_win_right, int dst_stride[NI_MAX_NUM_DATA_POINTERS], int dst_height[NI_MAX_NUM_DATA_POINTERS], int src_stride[NI_MAX_NUM_DATA_POINTERS], int src_height[NI_MAX_NUM_DATA_POINTERS])
Copy YUV data to Netint HW YUV420p frame layout to be sent to encoder for encoding....
Definition ni_util.c:3056
void ni_buffer_pool_return_buffer(ni_queue_node_t *buf, ni_queue_buffer_pool_t *p_buffer_pool)
Definition ni_util.c:1613
ni_retcode_t ni_timestamp_done(ni_timestamp_table_t *p_table, ni_queue_buffer_pool_t *p_buffer_pool)
Clean up timestamp handling.
Definition ni_util.c:1988
ni_retcode_t ni_timestamp_get_v2(ni_timestamp_table_t *p_table, uint64_t frame_offset, int64_t *p_timestamp, int32_t threshold, ni_queue_buffer_pool_t *p_buffer_pool)
Retrieve timestamp from table based on frameoffset info.
Definition ni_util.c:2116
uint32_t ni_decode_power_measurement(uint32_t current_data, const uint8_t *serial_number)
decode the raw current obtained and determine power
Definition ni_util.c:5095
int ni_cmp_fw_api_ver(const char ver1[], const char ver2[])
Compare two 3 character strings containing a FW API version. Handle comparision when FW API version f...
Definition ni_util.c:4383
Utility definitions.
#define NI_INVALID_POWER
Definition ni_util.h:44
#define TPS25946_R_IMON_T1U_UA
Definition ni_util.h:54
#define BUFFER_POOL_SZ_PER_CONTEXT
Definition ni_util.h:109
#define MCU_FSR_ADC
Definition ni_util.h:67
#define TPS25946_GAIN_IMON
Definition ni_util.h:51
#define TPS25946_R_IMON_T1S
Definition ni_util.h:55
#define NI_DEC_FRAME_BUF_POOL_SIZE_EXPAND
Definition ni_util.h:118
#define TPS25940_GAIN_IMON
Definition ni_util.h:47
#define TPS25946_R_IMON_T2A
Definition ni_util.h:53
#define ni_aligned_free(p_memptr)
Definition ni_util.h:402
#define TPS25974_R_IMON_T1M
Definition ni_util.h:56
#define XCODER_MAX_NUM_QUEUE_ENTRIES
Definition ni_util.h:107
#define TPS25940_IMON_OS
Definition ni_util.h:46
#define MAX17613B_R_ISET_TOTAL
Definition ni_util.h:63
#define MAX15162AAWE_C_IRATIO
Definition ni_util.h:59
#define MCU_REF_VOLTAGE
Definition ni_util.h:68
#define MAX17613B_R_ISET_R2
Definition ni_util.h:64
#define TPS25940_R_IMON
Definition ni_util.h:48
#define MAX15162AAWE_R_IMON
Definition ni_util.h:60
#define MAX17613B_C_IRATIO
Definition ni_util.h:65
#define TPS25974_GAIN_IMON
Definition ni_util.h:52
ni_pthread_mutex_t mutex
ni_buf_t * p_free_tail
ni_buf_t * p_used_head
ni_buf_t * p_used_tail
uint32_t number_of_buffers
ni_buf_t * p_free_head
struct _ni_buf_t * p_previous_buffer
struct _ni_buf_pool_t * pool
struct _ni_buf_t * p_next
struct _ni_buf_t * p_prev
struct _ni_buf_t * p_next_buffer
ni_network_layer_info_t linfo
ni_network_layer_offset_t * outset
ni_network_layer_params_t * out_param
union _ni_network_layer_params_t::@13 quant_data
struct _ni_network_layer_params_t::@13::@15 affine
struct _ni_network_layer_params_t::@13::@14 dfp
ni_queue_node_t * p_used_tail
ni_queue_node_t * p_free_head
ni_queue_node_t * p_used_head
ni_queue_node_t * p_free_tail
struct _ni_queue_node_t * p_previous_buffer
struct _ni_queue_node_t * p_next_buffer
struct _ni_queue_node_t * p_next
struct _ni_queue_node_t * p_prev
ni_queue_node_t * p_last
ni_queue_node_t * p_first
ni_queue_buffer_pool_t * buffer_pool
ni_buf_pool_t * dec_fme_buf_pool
ni_encoder_cfg_params_t cfg_enc_params
ni_decoder_input_params_t dec_input_params
uint64_t ui64BitLength
Definition ni_util.c:4096
uint32_t aui32State[8]
Definition ni_util.c:4097
uint8_t aui8Data[64]
Definition ni_util.c:4094
uint32_t ui32DataLength
Definition ni_util.c:4095
Definition ni_util.c:51
ni_retcode_t rc
Definition ni_util.c:52
const char * txt
Definition ni_util.c:53
uint32_t total_num
Definition ni_util.c:3817
uint32_t next_idx
Definition ni_util.c:3818
void * private
Definition ni_util.c:3816