libxcoder 5.9.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#ifdef __linux__
2721 clock_gettime(CLOCK_MONOTONIC, &ts);
2722#else
2723 clock_gettime(CLOCK_REALTIME, &ts);
2724#endif
2725 return ts.tv_sec * 1000000000LL + ts.tv_nsec;
2726#endif
2727}
2728
2729// Netint HW YUV420p data layout related utility functions
2730
2731/*!*****************************************************************************
2732 * \brief Get dimension information of Netint HW YUV420p frame to be sent
2733 * to encoder for encoding. Caller usually retrieves this info and
2734 * uses it in the call to ni_encoder_frame_buffer_alloc for buffer
2735 * allocation.
2736 *
2737 * \param[in] width source YUV frame width
2738 * \param[in] height source YUV frame height
2739 * \param[in] factor 1 for 8 bit, 2 for 10 bit
2740 * \param[in] is_semiplanar 1 for semiplanar frame, 0 otherwise
2741 * \param[out] plane_stride size (in bytes) of each plane width
2742 * \param[out] plane_height size of each plane height
2743 *
2744 * \return Y/Cb/Cr stride and height info
2745 *
2746 ******************************************************************************/
2747void ni_get_hw_yuv420p_dim(int width, int height, int factor,
2748 int is_semiplanar,
2749 int plane_stride[NI_MAX_NUM_DATA_POINTERS],
2750 int plane_height[NI_MAX_NUM_DATA_POINTERS])
2751{
2752 // strides are multiples of 128
2753 if (width < NI_MIN_WIDTH)
2754 {
2755 plane_stride[0] = ((NI_MIN_WIDTH * factor + 127) / 128) * 128;
2756 plane_stride[1] =
2757 (((NI_MIN_WIDTH / (is_semiplanar ? 1 : 2) * factor) + 127) /
2758 128) *
2759 128;
2760 plane_stride[2] = (is_semiplanar ? 0 : plane_stride[1]);
2761 } else
2762 {
2763 width = ((width + 1) / 2) * 2; // pad odd resolution
2764 plane_stride[0] = ((width * factor + 127) / 128) * 128;
2765 plane_stride[1] =
2766 (((width / (is_semiplanar ? 1 : 2) * factor) + 127) / 128) *
2767 128;
2768 plane_stride[2] = (is_semiplanar ? 0 : plane_stride[1]);
2769 }
2770
2771 // height (in lines) just needs to be even number
2772 if (height < NI_MIN_HEIGHT)
2773 {
2774 plane_height[0] = NI_MIN_HEIGHT;
2775 } else
2776 {
2777 plane_height[0] = ((height + 1) / 2) * 2;
2778 }
2779 plane_height[1] = plane_height[2] = plane_height[0] / 2;
2780}
2781
2782/*!*****************************************************************************
2783 * \brief Get dimension information of frame to be sent
2784 * to encoder for encoding. Caller usually retrieves this info and
2785 * uses it in the call to ni_encoder_frame_buffer_alloc for buffer
2786 * allocation.
2787 * The returned stride and height info will take alignment
2788 * requirements into account.
2789 *
2790 * \param[in] width source frame width
2791 * \param[in] height source frame height
2792 * \param[in] pix_fmt ni pixel format
2793 * \param[out] plane_stride size (in bytes) of each plane width
2794 * \param[out] plane_height size of each plane height
2795 *
2796 * \return stride and height info
2797 *
2798 ******************************************************************************/
2799void ni_get_frame_dim(int width, int height,
2800 ni_pix_fmt_t pix_fmt,
2801 int plane_stride[NI_MAX_NUM_DATA_POINTERS],
2802 int plane_height[NI_MAX_NUM_DATA_POINTERS])
2803{
2804 plane_height[0] = ((height + 1) / 2) * 2;
2805 plane_height[1] = plane_height[2] = plane_height[0] / 2;
2806
2807 switch (pix_fmt)
2808 {
2809 /* 8-bit YUV420 planar */
2810 case NI_PIX_FMT_YUV420P:
2811 plane_stride[0] = NI_VPU_ALIGN128(width);
2812 plane_stride[1] = NI_VPU_ALIGN128((width / 2));
2813 plane_stride[2] = plane_stride[1];
2814 plane_stride[3] = 0;
2815 break;
2816 /* 10-bit YUV420 planar, little-endian, least significant bits */
2818 plane_stride[0] = NI_VPU_ALIGN128(width * 2);
2819 plane_stride[1] = NI_VPU_ALIGN128(width);
2820 plane_stride[2] = plane_stride[1];
2821 plane_stride[3] = 0;
2822 break;
2823 /* 8-bit YUV420 semi-planar */
2824 case NI_PIX_FMT_NV12:
2825 plane_stride[0] = NI_VPU_ALIGN128(width);
2826 plane_stride[1] = plane_stride[0];
2827 plane_stride[2] = 0;
2828 plane_stride[3] = 0;
2829 break;
2830 /* 8-bit yuv422 semi-planar */
2831 case NI_PIX_FMT_NV16:
2832 plane_stride[0] = NI_VPU_ALIGN64(width);
2833 plane_stride[1] = plane_stride[0];
2834 plane_stride[2] = 0;
2835 plane_stride[3] = 0;
2836 break;
2837 /*8-bit yuv422 planar */
2838 case NI_PIX_FMT_YUYV422:
2839 case NI_PIX_FMT_UYVY422:
2840 plane_stride[0] = NI_VPU_ALIGN16(width) * 2;
2841 plane_stride[1] = 0;
2842 plane_stride[2] = 0;
2843 plane_stride[3] = 0;
2844 break;
2845 /* 10-bit YUV420 semi-planar, little endian, most significant bits */
2846 case NI_PIX_FMT_P010LE:
2847 plane_stride[0] = NI_VPU_ALIGN128(width * 2);
2848 plane_stride[1] = plane_stride[0];
2849 plane_stride[2] = 0;
2850 plane_stride[3] = 0;
2851 break;
2852 /* 32-bit RGBA packed */
2853 case NI_PIX_FMT_ARGB:
2854 case NI_PIX_FMT_ABGR:
2855 case NI_PIX_FMT_RGBA:
2856 case NI_PIX_FMT_BGRA:
2857 case NI_PIX_FMT_BGR0:
2858 plane_height[1] = plane_height[2] = 0;
2859
2860 plane_stride[0] = NI_VPU_ALIGN16(width) * 4;
2861 plane_stride[1] = 0;
2862 plane_stride[2] = 0;
2863 plane_stride[3] = 0;
2864 break;
2865 default:
2866 break;
2867 }
2868
2869}
2870
2871/*!*****************************************************************************
2872 * \brief Get dimension information of frame to be sent
2873 * to encoder for encoding. Caller usually retrieves this info and
2874 * uses it in the call to ni_encoder_frame_buffer_alloc for buffer
2875 * allocation.
2876 * The returned stride and height info will take into account both min
2877 * resolution and alignment requirements.
2878 *
2879 * \param[in] width source frame width
2880 * \param[in] height source frame height
2881 * \param[in] pix_fmt ni pixel format
2882 * \param[out] plane_stride size (in bytes) of each plane width
2883 * \param[out] plane_height size of each plane height
2884 *
2885 * \return stride and height info
2886 *
2887 ******************************************************************************/
2888void ni_get_min_frame_dim(int width, int height,
2889 ni_pix_fmt_t pix_fmt,
2890 int plane_stride[NI_MAX_NUM_DATA_POINTERS],
2891 int plane_height[NI_MAX_NUM_DATA_POINTERS])
2892{
2893
2894 if (height < NI_MIN_HEIGHT)
2895 {
2896 height = NI_MIN_HEIGHT;
2897 }
2898 if (width < NI_MIN_WIDTH)
2899 {
2900 width = NI_MIN_WIDTH;
2901 }
2902 else
2903 {
2904 width = ((width + 1) / 2) * 2; // pad odd resolution
2905 }
2906
2907 ni_get_frame_dim(width, height, pix_fmt, plane_stride, plane_height);
2908
2910 "%s dst_stride %d/%d/%d height %d/%d/%d pix_fmt %d\n",
2911 __func__, plane_stride[0], plane_stride[1], plane_stride[2],
2912 plane_height[0], plane_height[1], plane_height[2], pix_fmt);
2913}
2914
2915/*!*****************************************************************************
2916 * \brief Copy RGBA or YUV data to Netint HW frame layout to be sent
2917 * to encoder for encoding. Data buffer (dst) is usually allocated by
2918 * ni_encoder_frame_buffer_alloc.
2919 *
2920 * \param[out] p_dst pointers to which data is copied
2921 * \param[in] p_src pointers from which data is copied
2922 * \param[in] width source frame width
2923 * \param[in] height source frame height
2924 * \param[in] factor 1 for 8 bit, 2 for 10 bit
2925 * \param[in] is_semiplanar non-0 for semiplanar frame, 0 otherwise
2926 * \param[in] conf_win_right right offset of conformance window
2927 * \param[in] dst_stride size (in bytes) of each plane width in destination
2928 * \param[in] dst_height size of each plane height in destination
2929 * \param[in] src_stride size (in bytes) of each plane width in source
2930 * \param[in] src_height size of each plane height in source
2931 * \param[in] i index to plane to be copied
2932 *
2933 * \return copied data
2934 *
2935 ******************************************************************************/
2937 uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS],
2938 int frame_width, int frame_height, int factor,
2939 int is_semiplanar, int conf_win_right,
2940 int dst_stride[NI_MAX_NUM_DATA_POINTERS],
2941 int dst_height[NI_MAX_NUM_DATA_POINTERS],
2942 int src_stride[NI_MAX_NUM_DATA_POINTERS],
2943 int src_height[NI_MAX_NUM_DATA_POINTERS],
2944 int i)
2945{
2946 (void)frame_height;
2947 if (i >= NI_MAX_NUM_DATA_POINTERS)
2948 {
2949 ni_log(NI_LOG_ERROR, "%s: error, invalid plane index %d\n", __func__,
2950 i);
2951 return;
2952 }
2953 if (p_dst[i] == p_src[i])
2954 {
2955 ni_log(NI_LOG_DEBUG, "%s: src and dst identical, return\n", __func__);
2956 return;
2957 }
2958
2959 int height =
2960 (src_height[i] < dst_height[i] ? src_height[i] : dst_height[i]);
2961 uint8_t *dst = p_dst[i];
2962 const uint8_t *src = (const uint8_t *)p_src[i];
2963
2964 // width padding length in bytes, if needed
2965 int pad_len_bytes;
2966
2967 if (0 == i || is_semiplanar) // Y
2968 {
2969 pad_len_bytes = dst_stride[i] - frame_width * factor;
2970 }
2971 else
2972 {
2973 // U/V share the same padding length
2974 pad_len_bytes = dst_stride[i] - frame_width / 2 * factor;
2975 }
2976
2977 if (0 == pad_len_bytes && conf_win_right > 0)
2978 {
2979 if (0 == i) // Y
2980 {
2981 pad_len_bytes = conf_win_right * factor;
2982 }
2983 else
2984 {
2985 // U/V share the same padding length
2986 pad_len_bytes = conf_win_right * factor / 2;
2987 }
2988 }
2989
2991 "%s plane %d stride padding: %d pixel (%d bytes), copy height: "
2992 "%d.\n",
2993 __func__, i, pad_len_bytes / factor, pad_len_bytes,
2994 height);
2995
2996 for (; height > 0; height--)
2997 {
2998 memcpy(dst, src,
2999 (src_stride[i] < dst_stride[i] ? src_stride[i] : dst_stride[i]));
3000 dst += dst_stride[i];
3001
3002 // dst is now at the line end
3003 if (pad_len_bytes)
3004 {
3005 // repeat last pixel
3006 if (factor > 1)
3007 {
3008 // for 10 bit it's 2 bytes
3009 int j;
3010 uint8_t *tmp_dst = dst - pad_len_bytes;
3011 for (j = 0; j < pad_len_bytes / factor; j++)
3012 {
3013 memcpy(tmp_dst, dst - pad_len_bytes - factor, factor);
3014 tmp_dst += factor;
3015 }
3016 }
3017 else
3018 {
3019 memset(dst - pad_len_bytes, *(dst - pad_len_bytes - 1),
3020 pad_len_bytes);
3021 }
3022 }
3023 src += src_stride[i];
3024 }
3025
3026 // height padding/cropping if needed
3027 int padding_height = dst_height[i] - src_height[i];
3028 if (padding_height > 0)
3029 {
3030 ni_log(NI_LOG_DEBUG, "%s plane %d padding height: %d\n", __func__,
3031 i, padding_height);
3032 src = dst - dst_stride[i];
3033 for (; padding_height > 0; padding_height--)
3034 {
3035 memcpy(dst, src, dst_stride[i]);
3036 dst += dst_stride[i];
3037 }
3038 }
3039}
3040/*!*****************************************************************************
3041 * \brief Copy YUV data to Netint HW YUV420p frame layout to be sent
3042 * to encoder for encoding. Data buffer (dst) is usually allocated by
3043 * ni_encoder_frame_buffer_alloc.
3044 *
3045 * \param[out] p_dst pointers of Y/Cb/Cr to which data is copied
3046 * \param[in] p_src pointers of Y/Cb/Cr from which data is copied
3047 * \param[in] width source YUV frame width
3048 * \param[in] height source YUV frame height
3049 * \param[in] factor 1 for 8 bit, 2 for 10 bit
3050 * \param[in] is_semiplanar non-0 for semiplanar frame, 0 otherwise
3051 * \param[in] conf_win_right right offset of conformance window
3052 * \param[in] dst_stride size (in bytes) of each plane width in destination
3053 * \param[in] dst_height size of each plane height in destination
3054 * \param[in] src_stride size (in bytes) of each plane width in source
3055 * \param[in] src_height size of each plane height in source
3056 *
3057 * \return Y/Cb/Cr data
3058 *
3059 ******************************************************************************/
3061 uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS],
3062 int frame_width, int frame_height, int factor,
3063 int is_semiplanar, int conf_win_right,
3064 int dst_stride[NI_MAX_NUM_DATA_POINTERS],
3065 int dst_height[NI_MAX_NUM_DATA_POINTERS],
3066 int src_stride[NI_MAX_NUM_DATA_POINTERS],
3067 int src_height[NI_MAX_NUM_DATA_POINTERS])
3068{
3070 "%s dst_stride %d/%d/%d src_stride %d/%d/%d dst_height "
3071 "%d/%d/%d src_height %d/%d/%d\n",
3072 __func__, dst_stride[0], dst_stride[1], dst_stride[2], src_stride[0],
3073 src_stride[1], src_stride[2], dst_height[0], dst_height[1],
3074 dst_height[2], src_height[0], src_height[1], src_height[2]);
3075
3076 int i;
3077
3078 for (i = 0; i < NI_MAX_NUM_DATA_POINTERS - 1; i++)
3079 {
3080 ni_copy_plane_data(p_dst, p_src, frame_width, frame_height, factor,
3081 is_semiplanar, conf_win_right, dst_stride,
3082 dst_height, src_stride, src_height, i);
3083 }
3084}
3085
3086/*!*****************************************************************************
3087 * \brief Copy RGBA or YUV data to Netint HW frame layout to be sent
3088 * to encoder for encoding. Data buffer (dst) is usually allocated by
3089 * ni_encoder_frame_buffer_alloc.
3090 *
3091 * \param[out] p_dst pointers to which data is copied
3092 * \param[in] p_src pointers from which data is copied
3093 * \param[in] width source frame width
3094 * \param[in] height source frame height
3095 * \param[in] factor 1 for 8 bit, 2 for 10 bit
3096 * \param[in] pix_fmt pixel format to distinguish between planar types and/or components
3097 * \param[in] conf_win_right right offset of conformance window
3098 * \param[in] dst_stride size (in bytes) of each plane width in destination
3099 * \param[in] dst_height size of each plane height in destination
3100 * \param[in] src_stride size (in bytes) of each plane width in source
3101 * \param[in] src_height size of each plane height in source
3102 *
3103 * \return copied data
3104 *
3105 ******************************************************************************/
3107 uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS],
3108 int frame_width, int frame_height,
3109 int factor, ni_pix_fmt_t pix_fmt,
3110 int conf_win_right,
3111 int dst_stride[NI_MAX_NUM_DATA_POINTERS],
3112 int dst_height[NI_MAX_NUM_DATA_POINTERS],
3113 int src_stride[NI_MAX_NUM_DATA_POINTERS],
3114 int src_height[NI_MAX_NUM_DATA_POINTERS])
3115{
3117 "%s frame_width %d frame_height %d factor %d conf_win_right %d "
3118 "dst_stride %d/%d/%d src_stride %d/%d/%d dst_height "
3119 "%d/%d/%d src_height %d/%d/%d pix_fmt %d\n",
3120 __func__, frame_width, frame_height, factor, conf_win_right,
3121 dst_stride[0], dst_stride[1], dst_stride[2], src_stride[0],
3122 src_stride[1], src_stride[2], dst_height[0], dst_height[1],
3123 dst_height[2], src_height[0], src_height[1], src_height[2],
3124 pix_fmt);
3125
3126 int is_rgba = 0;
3127 int is_semiplanar = 0;
3128 switch (pix_fmt)
3129 {
3130 case NI_PIX_FMT_NV12:
3131 case NI_PIX_FMT_P010LE:
3132 is_semiplanar = 1;
3133 break;
3134 case NI_PIX_FMT_ARGB:
3135 case NI_PIX_FMT_ABGR:
3136 case NI_PIX_FMT_RGBA:
3137 case NI_PIX_FMT_BGRA:
3138 is_rgba = 1;
3139 break;
3140 default:
3141 break;
3142 }
3143
3144 if (is_rgba)
3145 {
3146 ni_copy_plane_data(p_dst, p_src,
3147 frame_width, frame_height, 4,
3148 is_semiplanar, conf_win_right,
3149 dst_stride, dst_height,
3150 src_stride, src_height,
3151 0); // just one plane for rgba
3152 }
3153 else
3154 {
3155 ni_copy_hw_yuv420p(p_dst, p_src, frame_width, frame_height, factor,
3156 is_semiplanar, conf_win_right, dst_stride,
3157 dst_height, src_stride, src_height);
3158 }
3159}
3160
3161/*!*****************************************************************************
3162 * \brief Copy yuv444p data to yuv420p frame layout to be sent
3163 * to encoder for encoding. Data buffer (dst) is usually allocated by
3164 * ni_encoder_frame_buffer_alloc.
3165 *
3166 * \param[out] p_dst0 pointers of Y/Cb/Cr as yuv420p output0
3167 * \param[out] p_dst1 pointers of Y/Cb/Cr as yuv420p output1
3168 * \param[in] p_src pointers of Y/Cb/Cr as yuv444p intput
3169 * \param[in] width source YUV frame width
3170 * \param[in] height source YUV frame height
3171 * \param[in] factor 1 for 8 bit, 2 for 10 bit
3172 * \param[in] mode 0 for
3173 * out0 is Y+1/2V, with the original input as the out0, 1/4V
3174 * copy to data[1] 1/4V copy to data[2]
3175 * out1 is U+1/2V, U copy to data[0], 1/4V copy to data[1], 1/4V
3176 * copy to data[2]
3177 * mode 1 for
3178 * out0 is Y+1/2u+1/2v, with the original input as the output0,
3179 * 1/4U copy to data[1] 1/4V copy to data[2]
3180 * out1 is (1/2U+1/2V)+1/4U+1/4V, 1/2U & 1/2V copy to data[0],
3181 * 1/4U copy to data[1], 1/4V copy to data[2]
3182 *
3183 * \return Y/Cb/Cr data
3184 *
3185 ******************************************************************************/
3187 uint8_t *p_dst1[NI_MAX_NUM_DATA_POINTERS],
3188 uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS],
3189 int frame_width, int frame_height,
3190 int factor, int mode)
3191{
3192 int i, j;
3193 int y_444p_linesize = frame_width * factor;
3194 int uv_444p_linesize = y_444p_linesize;
3195 int y_420p_linesize = NI_VPU_ALIGN128(y_444p_linesize);
3196 int uv_420p_linesize = NI_VPU_ALIGN128(uv_444p_linesize / 2);
3197
3198 // return to avoid self copy
3199 if (p_dst0[0] == p_dst1[0] && p_dst0[1] == p_dst1[1] &&
3200 p_dst0[2] == p_dst1[2])
3201 {
3202 ni_log(NI_LOG_DEBUG, "%s: src and dst identical, return\n", __func__);
3203 return;
3204 }
3205
3206 // Y component
3207 for (i = 0; i < frame_height; i++)
3208 {
3209 memcpy(&p_dst0[0][(ptrdiff_t)i * y_420p_linesize], &p_src[0][(ptrdiff_t)i * y_444p_linesize],
3210 y_444p_linesize);
3211 }
3212
3213 if (mode == 0)
3214 {
3215 // out0 data[0]: Y data[1]: 0.25V data[2]: 0.25V
3216 // out1 data[0]: U data[1]: 0.25V data[2]: 0.25V
3217 // U component
3218 for (i = 0; i < frame_height; i++)
3219 {
3220 memcpy(&p_dst1[0][(ptrdiff_t)i * y_420p_linesize],
3221 &p_src[1][(ptrdiff_t)i * y_444p_linesize], y_444p_linesize);
3222 }
3223
3224 for (i = 0; i < frame_height / 2; i++)
3225 {
3226 for (j = 0; j < frame_width * factor / 2; j += factor)
3227 {
3228 // V component
3229 // even line
3230 memcpy(&p_dst0[1][i * uv_420p_linesize + j],
3231 &p_src[2][2 * i * uv_444p_linesize + 2 * j],
3232 factor);
3233 memcpy(&p_dst0[2][i * uv_420p_linesize + j],
3234 &p_src[2][2 * i * uv_444p_linesize + (2 * j + factor)],
3235 factor);
3236 // odd line
3237 memcpy(&p_dst1[1][i * uv_420p_linesize + j],
3238 &p_src[2][(2 * i + 1) * uv_444p_linesize + 2 * j],
3239 factor);
3240 memcpy(&p_dst1[2][i * uv_420p_linesize + j],
3241 &p_src[2][(2 * i + 1) * uv_444p_linesize + (2 * j + factor)],
3242 factor);
3243 }
3244 }
3245 } else
3246 {
3247 // out0 data[0]: Y data[1]: 0.25U data[2]: 0.25V
3248 // out1 data[0]: 0.5U + 0.5V data[1]: 0.25U data[2]: 0.25V
3249 for (i = 0; i < frame_height / 2; i++)
3250 {
3251 for (j = 0; j < frame_width * factor / 2; j += factor)
3252 {
3253 // U component
3254 // even line 0.25U
3255 memcpy(&p_dst1[1][i * uv_420p_linesize + j],
3256 &p_src[1][2 * i * uv_444p_linesize + (2 * j + factor)],
3257 factor);
3258 // odd line 0.5U
3259 memcpy(&p_dst1[0][2 * i * uv_444p_linesize + 2 * j],
3260 &p_src[1][(2 * i + 1) * uv_444p_linesize + 2 * j],
3261 (ptrdiff_t)factor * 2);
3262 // even line 0.25U
3263 memcpy(&p_dst0[1][i * uv_420p_linesize + j],
3264 &p_src[1][2 * i * uv_444p_linesize + 2 * j],
3265 factor);
3266
3267 // V component
3268 // even line 0.25V
3269 memcpy(&p_dst1[2][i * uv_420p_linesize + j],
3270 &p_src[2][2 * i * uv_444p_linesize + (2 * j + factor)],
3271 factor);
3272 // odd line 0.5V
3273 memcpy(&p_dst1[0][(2 * i + 1) * uv_444p_linesize + 2 * j],
3274 &p_src[2][(2 * i + 1) * uv_444p_linesize + 2 * j],
3275 (ptrdiff_t)factor * 2);
3276 // even line 0.25V
3277 memcpy(&p_dst0[2][i * uv_420p_linesize + j],
3278 &p_src[2][2 * i * uv_444p_linesize + 2 * j],
3279 factor);
3280 }
3281 }
3282 }
3283}
3284
3285// NAL operations
3286
3287/*!*****************************************************************************
3288 * \brief Insert emulation prevention byte(s) as needed into the data buffer
3289 *
3290 * \param buf data buffer to be worked on - new byte(s) will be inserted
3291 * size number of bytes starting from buf to check
3292 *
3293 * \return the number of emulation prevention bytes inserted into buf, 0 if
3294 * none.
3295 *
3296 * Note: caller *MUST* ensure for newly inserted bytes, buf has enough free
3297 * space starting from buf + size
3298 ******************************************************************************/
3299int ni_insert_emulation_prevent_bytes(uint8_t *buf, int size)
3300{
3301 int insert_bytes = 0;
3302 uint8_t *buf_curr = buf;
3303 uint8_t *buf_end = buf + size - 1;
3304 int zeros = 0, insert_ep3_byte;
3305
3306 ni_log(NI_LOG_TRACE, "%s: enter\n", __func__);
3307
3308 for (; buf_curr <= buf_end; buf_curr++)
3309 {
3310 if (zeros == 2)
3311 {
3312 insert_ep3_byte = (*buf_curr <= 3);
3313 if (insert_ep3_byte)
3314 {
3315 // move bytes from curr to end 1 position to make space for ep3
3316 memmove(buf_curr + 1, buf_curr, buf_end - buf_curr + 1);
3317 *buf_curr = 0x3;
3318
3319 buf_curr++;
3320 buf_end++;
3321 insert_bytes++;
3322 }
3323
3324 zeros = 0;
3325 }
3326
3327 if (!*buf_curr)
3328 {
3329 zeros++;
3330 } else
3331 {
3332 zeros = 0;
3333 }
3334 }
3335
3336 ni_log(NI_LOG_TRACE, "%s: %d, exit\n", __func__, insert_bytes);
3337 return insert_bytes;
3338}
3339
3340/*!*****************************************************************************
3341 * \brief Remove emulation prevention byte(s) as needed from the data buffer
3342 *
3343 * \param buf data buffer to be worked on - emu prevent byte(s) will be
3344 * removed from.
3345 * size number of bytes starting from buf to check
3346 *
3347 * \return the number of emulation prevention bytes removed from buf, 0 if
3348 * none.
3349 *
3350 * Note: buf will be modified if emu prevent byte(s) found and removed.
3351 ******************************************************************************/
3352int ni_remove_emulation_prevent_bytes(uint8_t *buf, int size)
3353{
3354 int remove_bytes = 0;
3355 uint8_t *buf_curr = buf;
3356 uint8_t *buf_end = buf + size - 1;
3357 int zeros = 0, remove_ep3_byte;
3358
3359 ni_log(NI_LOG_TRACE, "%s: enter\n", __func__);
3360
3361 for (; buf_curr < buf_end; buf_curr++)
3362 {
3363 if (zeros == 2)
3364 {
3365 remove_ep3_byte = (*buf_curr == 0x03 && *(buf_curr + 1) <= 3);
3366 if (remove_ep3_byte)
3367 {
3368 // move bytes after curr to end, 1 position forward to overwrite ep3
3369 memmove(buf_curr, buf_curr + 1, buf_end - buf_curr);
3370
3371 // buf_curr unchanged
3372 buf_end--;
3373 remove_bytes++;
3374 }
3375
3376 zeros = 0;
3377 }
3378
3379 if (!*buf_curr)
3380 {
3381 zeros++;
3382 } else
3383 {
3384 zeros = 0;
3385 }
3386 }
3387
3388 ni_log(NI_LOG_TRACE, "%s: %d, exit\n", __func__, remove_bytes);
3389 return remove_bytes;
3390}
3391
3392/******************************************************************************
3393 *
3394 * Ai utils apis
3395 *
3396 ******************************************************************************/
3397static uint32_t ni_ai_type_get_bytes(const uint32_t type)
3398{
3399 switch (type)
3400 {
3403 return 1;
3408 return 2;
3412 return 4;
3416 return 8;
3417
3418 default:
3419 return 0;
3420 }
3421}
3422
3423static void ni_ai_integer_convert(const void *src, void *dest,
3424 ni_ai_buffer_format_e src_dtype,
3425 ni_ai_buffer_format_e dst_dtype)
3426{
3427 unsigned char all_zeros[] = {0x00, 0x00, 0x00, 0x00,
3428 0x00, 0x00, 0x00, 0x00};
3429 unsigned char all_ones[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
3430 uint32_t src_sz = ni_ai_type_get_bytes(src_dtype);
3431 uint32_t dest_sz = ni_ai_type_get_bytes(dst_dtype);
3432 unsigned char *buffer = all_zeros;
3433
3434 if (((int8_t *)src)[src_sz - 1] & 0x80)
3435 {
3436 buffer = all_ones;
3437 }
3438 memcpy(buffer, src, src_sz);
3439 memcpy(dest, buffer, dest_sz);
3440}
3441
3442static float ni_ai_int8_to_fp32(signed char val, signed char fixedPointPos)
3443{
3444 float result = 0.0f;
3445
3446 if (fixedPointPos > 0)
3447 {
3448 result = (float)val * (1.0f / ((float)(1 << fixedPointPos)));
3449 } else
3450 {
3451 result = (float)val * ((float)(1 << -fixedPointPos));
3452 }
3453
3454 return result;
3455}
3456
3457static float ni_ai_int16_to_fp32(int16_t val, signed char fixedPointPos)
3458{
3459 float result = 0.0f;
3460
3461 if (fixedPointPos > 0)
3462 {
3463 result = (float)val * (1.0f / ((float)(1 << fixedPointPos)));
3464 } else
3465 {
3466 result = (float)val * ((float)(1 << -fixedPointPos));
3467 }
3468
3469 return result;
3470}
3471
3472static float ni_ai_uint8_to_fp32(uint8_t val, int32_t zeroPoint, float scale)
3473{
3474 float result = 0.0f;
3475
3476 result = (float)(val - (uint8_t)zeroPoint) * scale;
3477
3478 return result;
3479}
3480
3481static float ni_ai_fp16_to_fp32(const short in)
3482{
3483 typedef union
3484 {
3485 unsigned int u;
3486 float f;
3487 } _fp32_t;
3488
3489 const _fp32_t magic = {(254 - 15) << 23};
3490 const _fp32_t infnan = {(127 + 16) << 23};
3491 _fp32_t o;
3492 // Non-sign bits
3493 o.u = (in & 0x7fff) << 13;
3494 o.f *= magic.f;
3495 if (o.f >= infnan.f)
3496 {
3497 o.u |= 255 << 23;
3498 }
3499 //Sign bit
3500 o.u |= (in & 0x8000) << 16;
3501 return o.f;
3502}
3503
3504static float ni_ai_affine_to_fp32(int32_t val, int32_t zeroPoint, float scale)
3505{
3506 float result = 0.0f;
3507 result = ((float)val - (float)zeroPoint) * scale;
3508 return result;
3509}
3510
3511static uint32_t ni_ai_get_tensor_size(int32_t *shape, uint32_t dim_num,
3512 int32_t type)
3513{
3514 uint32_t sz;
3515 uint32_t i;
3516 sz = 0;
3517 if (NULL == shape || 0 == dim_num)
3518 {
3519 return sz;
3520 }
3521 sz = 1;
3522 for (i = 0; i < dim_num; i++)
3523 {
3524 sz *= shape[i];
3525 }
3526 sz *= ni_ai_type_get_bytes(type);
3527
3528 return sz;
3529}
3530
3531static uint32_t ni_ai_get_element_num(int32_t *sizes, uint32_t num_of_dims,
3532 int32_t data_format)
3533{
3534 uint32_t num;
3535 uint32_t sz;
3536 uint32_t dsize;
3537
3538 sz = ni_ai_get_tensor_size(sizes, num_of_dims, data_format);
3539 dsize = ni_ai_type_get_bytes(data_format);
3540 if (dsize)
3541 {
3542 num = (uint32_t)(sz / dsize);
3543 } else
3544 {
3545 num = 0;
3546 }
3547
3548 return num;
3549}
3550
3551static int32_t ni_ai_type_is_integer(const int32_t type)
3552{
3553 int32_t ret = 0;
3554 switch (type)
3555 {
3562 ret = 1;
3563 break;
3564 default:
3565 break;
3566 }
3567
3568 return ret;
3569}
3570
3571static int32_t ni_ai_type_is_signed(const int32_t type)
3572{
3573 int32_t ret = 0;
3574 switch (type)
3575 {
3582 ret = 1;
3583 break;
3584 default:
3585 break;
3586 }
3587
3588 return ret;
3589}
3590
3591static void ni_ai_type_get_range(int32_t type, double *max_range,
3592 double *min_range)
3593{
3594 int32_t bits;
3595 double from, to;
3596 from = 0.0;
3597 to = 0.0;
3598 bits = (int32_t)(ni_ai_type_get_bytes(type) * 8);
3599 if (ni_ai_type_is_integer(type))
3600 {
3601 if (ni_ai_type_is_signed(type))
3602 {
3603 from = (double)(-(1L << (bits - 1)));
3604 to = (double)((1UL << (bits - 1)) - 1);
3605 } else
3606 {
3607 from = 0.0;
3608 to = (double)((1UL << bits) - 1);
3609 }
3610 }
3611 if (NULL != max_range)
3612 {
3613 *max_range = to;
3614 }
3615 if (NULL != min_range)
3616 {
3617 *min_range = from;
3618 }
3619}
3620
3621static inline double ni_abs(double x)
3622{
3623 return x < 0 ? -x : x;
3624}
3625
3626static double ni_ai_copy_sign(double number, double sign)
3627{
3628 double value = ni_abs(number);
3629 return (sign > 0) ? value : (-value);
3630}
3631
3632static inline int ni_ai_math_floorf(double x)
3633{
3634 return x >= 0 ? (int)x : (int)x - 1;
3635}
3636
3637static double ni_ai_rint(double x)
3638{
3639#define NI_AI_EPSILON 1e-8
3640 double decimal;
3641 double inter;
3642 int intpart;
3643
3644 intpart = (int)x;
3645 decimal = x - intpart;
3646 inter = (double)intpart;
3647
3648 if (ni_abs((ni_abs(decimal) - 0.5f)) < NI_AI_EPSILON)
3649 {
3650 inter += (int32_t)(inter) % 2;
3651 } else
3652 {
3653 return ni_ai_copy_sign(ni_ai_math_floorf(ni_abs(x) + 0.5f), x);
3654 }
3655
3656 return inter;
3657}
3658
3659static int32_t ni_ai_fp32_to_dfp(const float in, const signed char fl,
3660 const int32_t type)
3661{
3662 int32_t data;
3663 double max_range;
3664 double min_range;
3665 ni_ai_type_get_range(type, &max_range, &min_range);
3666 if (fl > 0)
3667 {
3668 data = (int32_t)ni_ai_rint(in * (float)(1 << fl));
3669 } else
3670 {
3671 data = (int32_t)ni_ai_rint(in * (1.0f / (float)(1 << -fl)));
3672 }
3673 data = ni_min(data, (int32_t)max_range);
3674 data = ni_max(data, (int32_t)min_range);
3675
3676 return data;
3677}
3678
3679static int32_t ni_ai_fp32_to_affine(const float in, const float scale,
3680 const int zero_point, const int32_t type)
3681{
3682 int32_t data;
3683 double max_range;
3684 double min_range;
3685 ni_ai_type_get_range(type, &max_range, &min_range);
3686 data = (int32_t)(ni_ai_rint(in / scale) + zero_point);
3687 data = ni_max((int32_t)min_range, ni_min((int32_t)max_range, data));
3688 return data;
3689}
3690
3691static unsigned short ni_ai_fp32_to_bfp16_rtne(float in)
3692{
3693 /*
3694 Convert a float point to bfloat16, with round-nearest-to-even as rounding method.
3695 */
3696 unsigned short out;
3697
3698 uint32_t fp32;
3699 memcpy(&fp32, &in, sizeof(uint32_t));
3700
3701 uint32_t lsb =
3702 (fp32 >> 16) & 1; /* Least significant bit of resulting bfloat. */
3703 uint32_t rounding_bias = 0x7fff + lsb;
3704
3705 if ((float)0x7FC00000 == in)
3706 {
3707 out = 0x7fc0;
3708 } else
3709 {
3710 fp32 += rounding_bias;
3711 out = (unsigned short)(fp32 >> 16);
3712 }
3713
3714 return out;
3715}
3716
3717static unsigned short ni_ai_fp32_to_fp16(float in)
3718{
3719 uint32_t fp32 = 0;
3720 uint32_t t1 = 0;
3721 uint32_t t2 = 0;
3722 uint32_t t3 = 0;
3723 uint32_t fp16 = 0u;
3724
3725 memcpy((uint8_t *)&fp32, (uint8_t *)&in, sizeof(uint32_t));
3726
3727 t1 = (fp32 & 0x80000000u) >> 16; /* sign bit. */
3728 t2 = (fp32 & 0x7F800000u) >> 13; /* Exponent bits */
3729 t3 = (fp32 & 0x007FE000u) >> 13; /* Mantissa bits, no rounding */
3730
3731 if (t2 >= 0x023c00u)
3732 {
3733 fp16 = t1 | 0x7BFF; /* Don't round to infinity. */
3734 } else if (t2 <= 0x01c000u)
3735 {
3736 fp16 = t1;
3737 } else
3738 {
3739 t2 -= 0x01c000u;
3740 fp16 = t1 | t2 | t3;
3741 }
3742
3743 return (unsigned short)fp16;
3744}
3745
3746static void ni_ai_float32_to_dtype(float src, unsigned char *dst,
3747 const int32_t data_type,
3748 const int32_t quant_format,
3749 signed char fixed_point_pos, float tf_scale,
3750 int32_t tf_zerop)
3751{
3752 switch (data_type)
3753 {
3755 memcpy(dst, &src, sizeof(float));
3756 break;
3758 *(int16_t *)dst = (int16_t)ni_ai_fp32_to_fp16(src);
3759 break;
3761 *(int16_t *)dst = (int16_t)ni_ai_fp32_to_bfp16_rtne(src);
3762 break;
3766 {
3767 int32_t dst_value = 0;
3768 switch (quant_format)
3769 {
3771 dst_value =
3772 ni_ai_fp32_to_dfp(src, fixed_point_pos, data_type);
3773 break;
3775 dst_value = ni_ai_fp32_to_affine(src, tf_scale, tf_zerop,
3776 data_type);
3777 break;
3779 dst_value = (int32_t)src;
3780 break;
3781 default:
3782 break;
3783 }
3784 ni_ai_integer_convert(&dst_value, dst, NI_AI_BUFFER_FORMAT_INT32,
3785 data_type);
3786 }
3787 break;
3788 default:;
3789 }
3790}
3791
3793 ni_packet_t *p_packet,
3794 ni_network_data_t *p_network,
3795 uint32_t layer)
3796{
3797 uint8_t *data;
3798 uint32_t data_len;
3800
3801 if (!p_network || !dst || dst_len == 0 || !p_packet || !p_packet->p_data)
3802 {
3804 }
3805
3806 if (layer >= p_network->output_num)
3807 {
3809 }
3810
3811 p_param = &p_network->linfo.out_param[layer];
3812 data = (uint8_t *)p_packet->p_data + p_network->outset[layer].offset;
3813 data_len = ni_ai_network_layer_size(p_param);
3814 return ni_network_convert_data_to_tensor(dst, dst_len, data, data_len,
3815 p_param);
3816}
3817
3819{
3820 void *private;
3821 uint32_t total_num;
3822 uint32_t next_idx;
3823};
3824
3825static int open_tensor_rsrc_file(struct tensor_rsrc *rsrc, void *data,
3826 uint32_t num)
3827{
3828 (void)num;
3829 FILE *f = NULL;
3830 ni_fopen(&f, (const char *)data, "r");
3831 rsrc->private = (void *)f;
3832 return rsrc->private ? 0 : -1;
3833}
3834
3835static int get_tensor_rsrc_from_file(struct tensor_rsrc *rsrc, float *value)
3836{
3837 FILE *fp = (FILE *)rsrc->private;
3838 float tensor;
3839
3840 if (ni_fscanf(fp, "%f ", &tensor) == 1)
3841 {
3842 *value = tensor;
3843 return 0;
3844 }
3845
3846 return -1;
3847}
3848
3849static void close_tensor_rsrc_file(struct tensor_rsrc *rsrc)
3850{
3851 FILE *fp = (FILE *)rsrc->private;
3852 (void)fclose(fp);
3853}
3854
3855static int open_tensor_rsrc_rawdata(struct tensor_rsrc *rsrc, void *data,
3856 uint32_t len)
3857{
3858 rsrc->private = (void *)data;
3859 rsrc->total_num = len / sizeof(float);
3860 rsrc->next_idx = 0;
3861 return 0;
3862}
3863
3864static int get_tensor_rsrc_from_rawdata(struct tensor_rsrc *rsrc, float *value)
3865{
3866 float *tensors = (float *)rsrc->private;
3867
3868 if (rsrc->next_idx < rsrc->total_num)
3869 {
3870 *value = tensors[rsrc->next_idx];
3871 rsrc->next_idx++;
3872 return 0;
3873 }
3874
3875 return -1;
3876}
3877
3878static void close_tensor_rsrc_rawdata(struct tensor_rsrc *rsrc)
3879{
3880}
3881
3882static ni_retcode_t ni_network_tensor_to_data(
3883 uint8_t *dst, uint32_t dst_len, void *tensor, uint32_t src_len,
3885 int (*open_tensor_rsrc)(struct tensor_rsrc *, void *, uint32_t),
3886 int (*get_tensor_rsrc)(struct tensor_rsrc *, float *),
3887 void (*close_tensor_rsrc)(struct tensor_rsrc *))
3888{
3889 uint8_t *tensor_data;
3890 uint32_t i, sz;
3891 uint32_t stride;
3892 float fval;
3893 int32_t data_format;
3894 int32_t quant_format;
3895 int32_t fixed_point_pos;
3896 float tf_scale;
3897 int32_t tf_zerop;
3898 struct tensor_rsrc *rsrc;
3899
3900 data_format = p_param->data_format;
3901 quant_format = p_param->quant_format;
3902 fixed_point_pos = p_param->quant_data.dfp.fixed_point_pos;
3903 tf_scale = p_param->quant_data.affine.scale;
3904 tf_zerop = p_param->quant_data.affine.zeroPoint;
3905
3906 sz = ni_ai_get_element_num((int32_t *)p_param->sizes, p_param->num_of_dims,
3907 data_format);
3908 stride = ni_ai_type_get_bytes(data_format);
3909
3910 if ((size_t)sz * stride * sizeof(uint8_t) != dst_len)
3911 {
3913 }
3914
3915 rsrc = (struct tensor_rsrc *)calloc(1, sizeof(struct tensor_rsrc));
3916 if (!rsrc)
3917 {
3918 return NI_RETCODE_FAILURE;
3919 }
3920
3921 if (open_tensor_rsrc(rsrc, tensor, src_len) != 0)
3922 {
3923 free(rsrc);
3924 return NI_RETCODE_FAILURE;
3925 }
3926
3927 memset(dst, 0, (size_t)sz * stride * sizeof(uint8_t));
3928 tensor_data = dst;
3929 for (i = 0; i < sz; i++)
3930 {
3931 if (get_tensor_rsrc(rsrc, &fval) == 0)
3932 {
3933 ni_ai_float32_to_dtype(fval, &tensor_data[(ptrdiff_t)stride * i], data_format,
3934 quant_format, (int8_t)fixed_point_pos, tf_scale,
3935 tf_zerop);
3936 } else
3937 {
3938 break;
3939 }
3940 }
3941
3942 close_tensor_rsrc(rsrc);
3943 free(rsrc);
3944 return NI_RETCODE_SUCCESS;
3945}
3946
3947ni_retcode_t ni_network_layer_convert_tensor(uint8_t *dst, uint32_t dst_len,
3948 const char *tensor_file,
3950{
3951 return ni_network_tensor_to_data(
3952 dst, dst_len, (void *)tensor_file, 0, p_param, open_tensor_rsrc_file,
3953 get_tensor_rsrc_from_file, close_tensor_rsrc_file);
3954}
3955
3957ni_network_convert_tensor_to_data(uint8_t *dst, uint32_t dst_len, float *src,
3958 uint32_t src_len,
3960{
3961 return ni_network_tensor_to_data(
3962 dst, dst_len, src, src_len, p_param, open_tensor_rsrc_rawdata,
3963 get_tensor_rsrc_from_rawdata, close_tensor_rsrc_rawdata);
3964}
3965
3967ni_network_convert_data_to_tensor(float *dst, uint32_t dst_len, uint8_t *src,
3968 uint32_t src_len,
3970{
3971 uint32_t i = 0;
3972 uint8_t *data;
3973 uint32_t ele_size;
3974 float *dst_float = dst;
3975 uint32_t type_size;
3976
3977 if (!src || src_len == 0 || !dst || dst_len == 0 || !p_param)
3978 {
3980 }
3981
3982 type_size = ni_ai_type_get_bytes(p_param->data_format);
3983
3984 data = src;
3985
3986 ele_size = 1;
3987 for (i = 0; i < p_param->num_of_dims; i++)
3988 {
3989 ele_size *= p_param->sizes[i];
3990 }
3991
3992 if (dst_len != ele_size * sizeof(float))
3993 {
3995 }
3996
3997 if (src_len != ni_ai_network_layer_size(p_param))
3998 {
4000 }
4001
4002 if (p_param->data_format == NI_AI_BUFFER_FORMAT_INT8)
4003 {
4004 int32_t quant_format = p_param->quant_format;
4005
4007 {
4008 uint8_t fix_pos = (uint8_t)p_param->quant_data.dfp.fixed_point_pos;
4009
4010 for (i = 0; i < ele_size; i++, data += type_size)
4011 {
4012 dst_float[i] = ni_ai_int8_to_fp32((int8_t)*data, (int8_t)fix_pos);
4013 }
4014 } else if (quant_format == NI_AI_BUFFER_QUANTIZE_TF_ASYMM)
4015 {
4016 int32_t zero_point = p_param->quant_data.affine.zeroPoint;
4017 float scale = p_param->quant_data.affine.scale;
4018
4019 for (i = 0; i < ele_size; i++, data += type_size)
4020 {
4021 int32_t src_value = 0;
4022 ni_ai_integer_convert(data, &src_value,
4025 dst_float[i] =
4026 ni_ai_affine_to_fp32(src_value, zero_point, scale);
4027 }
4028 } else
4029 {
4030 for (i = 0; i < ele_size; i++, data += type_size)
4031 {
4032 void *float_data = (void *)data;
4033 dst_float[i] = *((float *)float_data);
4034 }
4035 }
4036 } else if (p_param->data_format == NI_AI_BUFFER_FORMAT_FP16)
4037 {
4038 for (i = 0; i < ele_size; i++, data += type_size)
4039 {
4040 dst_float[i] = ni_ai_fp16_to_fp32(*((short *)data));
4041 }
4042 } else if (p_param->data_format == NI_AI_BUFFER_FORMAT_UINT8)
4043 {
4044 int32_t zero_point = p_param->quant_data.affine.zeroPoint;
4045 float scale = p_param->quant_data.affine.scale;
4046
4047 for (i = 0; i < ele_size; i++, data += type_size)
4048 {
4049 dst_float[i] = ni_ai_uint8_to_fp32(*data, zero_point, scale);
4050 }
4051 } else if (p_param->data_format == NI_AI_BUFFER_FORMAT_INT16)
4052 {
4053 uint8_t fix_pos = p_param->quant_data.dfp.fixed_point_pos;
4054
4055 for (i = 0; i < ele_size; i++, data += type_size)
4056 {
4057 dst_float[i] = ni_ai_int16_to_fp32(*((short *)data), (int8_t)fix_pos);
4058 }
4059 } else if (p_param->data_format == NI_AI_BUFFER_FORMAT_FP32)
4060 {
4061 for (i = 0; i < ele_size; i++, data += type_size)
4062 {
4063 void *float_data = (void *)data;
4064 dst_float[i] = *((float *)float_data);
4065 }
4066 } else
4067 {
4069 }
4070
4071 return NI_RETCODE_SUCCESS;
4072}
4073
4075{
4076 return ni_ai_get_tensor_size((int32_t *)p_param->sizes,
4077 p_param->num_of_dims, p_param->data_format);
4078}
4079
4081{
4082 uint32_t i, dims = 1;
4083
4084 for (i = 0; i < p_param->num_of_dims; i++)
4085 {
4086 dims *= p_param->sizes[i];
4087 }
4088
4089 return dims;
4090}
4091
4092/* sha256 */
4093// SHA256 outputs a 32 byte digest
4094#define SHA256_BLOCK_SIZE 32
4095
4096typedef struct SHA256CTX
4097{
4098 uint8_t aui8Data[64];
4101 uint32_t aui32State[8];
4103
4104#define ROTLEFT(a, b) (((a) << (b)) | ((a) >> (32 - (b))))
4105#define ROTRIGHT(a, b) (((a) >> (b)) | ((a) << (32 - (b))))
4106
4107#define CH(x, y, z) (((x) & (y)) ^ (~(x) & (z)))
4108#define MAJ(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
4109#define EP0(x) (ROTRIGHT(x, 2) ^ ROTRIGHT(x, 13) ^ ROTRIGHT(x, 22))
4110#define EP1(x) (ROTRIGHT(x, 6) ^ ROTRIGHT(x, 11) ^ ROTRIGHT(x, 25))
4111#define SIG0(x) (ROTRIGHT(x, 7) ^ ROTRIGHT(x, 18) ^ ((x) >> 3))
4112#define SIG1(x) (ROTRIGHT(x, 17) ^ ROTRIGHT(x, 19) ^ ((x) >> 10))
4113
4114static const uint32_t ui32k[64] = {
4115 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
4116 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
4117 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
4118 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
4119 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
4120 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
4121 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
4122 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
4123 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
4124 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
4125 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2};
4126
4127void ni_SHA256Transform(SHA256CTX *psCtx, const uint8_t aui8Data[])
4128{
4129 uint32_t ui32a, ui32b, ui32c, ui32d, ui32e, ui32f, ui32g, ui32h, ui32i,
4130 ui32j, ui32t1, ui32t2, ui32m[64];
4131
4132 for (ui32i = 0, ui32j = 0; ui32i < 16; ++ui32i, ui32j += 4)
4133 ui32m[ui32i] = (aui8Data[ui32j] << 24) | (aui8Data[ui32j + 1] << 16) |
4134 (aui8Data[ui32j + 2] << 8) | (aui8Data[ui32j + 3]);
4135 for (; ui32i < 64; ++ui32i)
4136 ui32m[ui32i] = SIG1(ui32m[ui32i - 2]) + ui32m[ui32i - 7] +
4137 SIG0(ui32m[ui32i - 15]) + ui32m[ui32i - 16];
4138
4139 ui32a = psCtx->aui32State[0];
4140 ui32b = psCtx->aui32State[1];
4141 ui32c = psCtx->aui32State[2];
4142 ui32d = psCtx->aui32State[3];
4143 ui32e = psCtx->aui32State[4];
4144 ui32f = psCtx->aui32State[5];
4145 ui32g = psCtx->aui32State[6];
4146 ui32h = psCtx->aui32State[7];
4147
4148 for (ui32i = 0; ui32i < 64; ++ui32i)
4149 {
4150 ui32t1 = ui32h + EP1(ui32e) + CH(ui32e, ui32f, ui32g) + ui32k[ui32i] +
4151 ui32m[ui32i];
4152 ui32t2 = EP0(ui32a) + MAJ(ui32a, ui32b, ui32c);
4153 ui32h = ui32g;
4154 ui32g = ui32f;
4155 ui32f = ui32e;
4156 ui32e = ui32d + ui32t1;
4157 ui32d = ui32c;
4158 ui32c = ui32b;
4159 ui32b = ui32a;
4160 ui32a = ui32t1 + ui32t2;
4161 }
4162
4163 psCtx->aui32State[0] += ui32a;
4164 psCtx->aui32State[1] += ui32b;
4165 psCtx->aui32State[2] += ui32c;
4166 psCtx->aui32State[3] += ui32d;
4167 psCtx->aui32State[4] += ui32e;
4168 psCtx->aui32State[5] += ui32f;
4169 psCtx->aui32State[6] += ui32g;
4170 psCtx->aui32State[7] += ui32h;
4171}
4172
4174{
4175 psCtx->ui32DataLength = 0;
4176 psCtx->ui64BitLength = 0;
4177 psCtx->aui32State[0] = 0x6a09e667;
4178 psCtx->aui32State[1] = 0xbb67ae85;
4179 psCtx->aui32State[2] = 0x3c6ef372;
4180 psCtx->aui32State[3] = 0xa54ff53a;
4181 psCtx->aui32State[4] = 0x510e527f;
4182 psCtx->aui32State[5] = 0x9b05688c;
4183 psCtx->aui32State[6] = 0x1f83d9ab;
4184 psCtx->aui32State[7] = 0x5be0cd19;
4185}
4186
4187void ni_SHA256Update(SHA256CTX *psCtx, const uint8_t aui8Data[],
4188 size_t ui32Length)
4189{
4190 uint32_t ui32i;
4191
4192 for (ui32i = 0; ui32i < ui32Length; ++ui32i)
4193 {
4194 psCtx->aui8Data[psCtx->ui32DataLength] = aui8Data[ui32i];
4195 psCtx->ui32DataLength++;
4196 if (psCtx->ui32DataLength == 64)
4197 {
4198 ni_SHA256Transform(psCtx, psCtx->aui8Data);
4199 psCtx->ui64BitLength += 512;
4200 psCtx->ui32DataLength = 0;
4201 }
4202 }
4203}
4204
4205void ni_SHA256Final(SHA256CTX *psCtx, uint8_t aui8Hash[])
4206{
4207 uint32_t ui32i;
4208
4209 ui32i = psCtx->ui32DataLength;
4210
4211 // Pad whatever data is left in the buffer.
4212 if (psCtx->ui32DataLength < 56)
4213 {
4214 psCtx->aui8Data[ui32i++] = 0x80;
4215 while (ui32i < 56)
4216 psCtx->aui8Data[ui32i++] = 0x00;
4217 } else
4218 {
4219 psCtx->aui8Data[ui32i++] = 0x80;
4220 while (ui32i < 64)
4221 psCtx->aui8Data[ui32i++] = 0x00;
4222 ni_SHA256Transform(psCtx, psCtx->aui8Data);
4223 memset(psCtx->aui8Data, 0, 56);
4224 }
4225
4226 // Append to the padding the total message's length in bits and transform.
4227 psCtx->ui64BitLength += (uint64_t)psCtx->ui32DataLength * 8;
4228 psCtx->aui8Data[63] = (uint8_t)psCtx->ui64BitLength;
4229 psCtx->aui8Data[62] = (uint8_t)(psCtx->ui64BitLength >> 8);
4230 psCtx->aui8Data[61] = (uint8_t)(psCtx->ui64BitLength >> 16);
4231 psCtx->aui8Data[60] = (uint8_t)(psCtx->ui64BitLength >> 24);
4232 psCtx->aui8Data[59] = (uint8_t)(psCtx->ui64BitLength >> 32);
4233 psCtx->aui8Data[58] = (uint8_t)(psCtx->ui64BitLength >> 40);
4234 psCtx->aui8Data[57] = (uint8_t)(psCtx->ui64BitLength >> 48);
4235 psCtx->aui8Data[56] = (uint8_t)(psCtx->ui64BitLength >> 56);
4236 ni_SHA256Transform(psCtx, psCtx->aui8Data);
4237
4238 // Since this implementation uses little endian byte ordering and SHA uses big endian,
4239 // reverse all the bytes when copying the final state to the output hash.
4240 for (ui32i = 0; ui32i < 4; ++ui32i)
4241 {
4242 aui8Hash[ui32i] =
4243 (psCtx->aui32State[0] >> (24 - ui32i * 8)) & 0x000000ff;
4244 aui8Hash[ui32i + 4] =
4245 (psCtx->aui32State[1] >> (24 - ui32i * 8)) & 0x000000ff;
4246 aui8Hash[ui32i + 8] =
4247 (psCtx->aui32State[2] >> (24 - ui32i * 8)) & 0x000000ff;
4248 aui8Hash[ui32i + 12] =
4249 (psCtx->aui32State[3] >> (24 - ui32i * 8)) & 0x000000ff;
4250 aui8Hash[ui32i + 16] =
4251 (psCtx->aui32State[4] >> (24 - ui32i * 8)) & 0x000000ff;
4252 aui8Hash[ui32i + 20] =
4253 (psCtx->aui32State[5] >> (24 - ui32i * 8)) & 0x000000ff;
4254 aui8Hash[ui32i + 24] =
4255 (psCtx->aui32State[6] >> (24 - ui32i * 8)) & 0x000000ff;
4256 aui8Hash[ui32i + 28] =
4257 (psCtx->aui32State[7] >> (24 - ui32i * 8)) & 0x000000ff;
4258 }
4259}
4260
4261void ni_calculate_sha256(const uint8_t aui8Data[], size_t ui32DataLength,
4262 uint8_t aui8Hash[])
4263{
4264 // Create the context structure
4265 SHA256CTX sCtx;
4266
4267 // Initialize the context
4268 ni_SHA256Init(&sCtx);
4269 // Update the context with data and data length
4270 ni_SHA256Update(&sCtx, aui8Data, ui32DataLength);
4271 // Finalize the result and put it into a hash buffer
4272 ni_SHA256Final(&sCtx, aui8Hash);
4273}
4274
4275/*!*****************************************************************************
4276 * \brief Copy Descriptor data to Netint HW descriptor frame layout to be sent
4277 * to encoder for encoding. Data buffer (dst) is usually allocated by
4278 * ni_encoder_frame_buffer_alloc. Only necessary when metadata size in
4279 * source is insufficient
4280 *
4281 * \param[out] p_dst pointers of Y/Cb/Cr to which data is copied
4282 * \param[in] p_src pointers of Y/Cb/Cr from which data is copied
4283 *
4284 * \return descriptor data
4285 *
4286 ******************************************************************************/
4288 uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS])
4289{
4290 // return to avoid self copy
4291 if (p_dst[0] == p_src[0] && p_dst[1] == p_src[1] && p_dst[2] == p_src[2] &&
4292 p_dst[3] == p_src[3])
4293 {
4294 ni_log(NI_LOG_DEBUG, "ni_copy_hw_yuv420p: src and dst identical, return\n");
4295 return;
4296 }
4297 niFrameSurface1_t *src_desc = (niFrameSurface1_t *)p_src[3];
4298 niFrameSurface1_t *dest_desc = (niFrameSurface1_t *)p_dst[3];
4299 memcpy(dest_desc, src_desc, sizeof(niFrameSurface1_t));
4300 ni_log(NI_LOG_DEBUG, "ni_copy_hw_descriptors dst FID Handle %d/%d src FID handle "
4301 "%d/%d\n",
4302 src_desc->ui16FrameIdx, src_desc->device_handle,
4303 dest_desc->ui16FrameIdx, dest_desc->device_handle);
4304}
4305
4306/*!*****************************************************************************
4307 * \brief Get libxcoder API version
4308 *
4309 * \return char pointer to libxcoder API version
4310 ******************************************************************************/
4312{
4313 static char* libxcoder_api_ver = LIBXCODER_API_VERSION;
4314 return libxcoder_api_ver;
4315}
4316
4317#ifndef DEPRECATION_AS_ERROR
4318/*!*****************************************************************************
4319 * \brief Get FW API version libxcoder is compatible with.
4320 * Deprecated in favour of `ni_fmt_fw_api_ver_str(&NI_XCODER_REVISION[NI_XCODER_REVISION_API_MAJOR_VER_IDX], &char_buf[0]);`
4321 *
4322 * \return char pointer to FW API version libxcoder is compatible with
4323 ******************************************************************************/
4325{
4326 static char compat_fw_api_ver_str[5] = "";
4327 // init static array one byte at a time to avoid msvc compiler error C2099
4328 if (!compat_fw_api_ver_str[0])
4329 {
4330 compat_fw_api_ver_str[0] = \
4332 compat_fw_api_ver_str[1] = '.';
4333 compat_fw_api_ver_str[2] = \
4336 compat_fw_api_ver_str[3] = \
4338 else
4339 compat_fw_api_ver_str[3] = 0;
4340 compat_fw_api_ver_str[4] = 0;
4341 }
4342 return &compat_fw_api_ver_str[0];
4343}
4344#endif
4345
4346/*!*****************************************************************************
4347 * \brief Get formatted FW API version string from unformatted FW API version
4348 * string
4349 *
4350 * \param[in] ver_str pointer to string containing FW API. Only up to 3
4351 * characters will be read
4352 * \param[out] fmt_str pointer to string buffer of at least size 5 to output
4353 * formated version string to
4354 *
4355 * \return none
4356 ******************************************************************************/
4357void ni_fmt_fw_api_ver_str(const char ver_str[], char fmt_str[])
4358{
4359 if (!ver_str || !fmt_str) {
4360 return;
4361 }
4362
4363 fmt_str[0] = ver_str[0];
4364 fmt_str[1] = '.';
4365 fmt_str[2] = ver_str[1];
4366
4367 if ((ver_str[0] < '6' || (ver_str[0] == '6' && ver_str[1] <= 'q')) ||
4368 (ver_str[2] == 0)) {
4369 fmt_str[3] = 0;
4370 } else {
4371 fmt_str[3] = ver_str[2];
4372 }
4373 fmt_str[4] = 0;
4374}
4375
4376/*!*****************************************************************************
4377 * \brief Compare two 3 character strings containing a FW API version. Handle
4378 * comparision when FW API version format length changed from 2 to 3.
4379 *
4380 * \param[in] ver1 pointer to string containing FW API. Only up to 3
4381 * characters will be read
4382 * \param[in] ver2 pointer to string containing FW API. Only up to 3
4383 * characters will be read
4384 *
4385 * \return 0 if ver1 == ver2, 1 if ver1 > ver2, -1 if ver1 < ver2
4386 ******************************************************************************/
4387int ni_cmp_fw_api_ver(const char ver1[], const char ver2[])
4388{
4389 int index;
4390
4391 index = 0;
4392
4393 if (ver1[index] > ver2[index])
4394 return 1;
4395 else if (ver1[index] < ver2[index])
4396 return -1;
4397
4398 index++;
4399
4400 if (ver1[index] > ver2[index])
4401 return 1;
4402 else if (ver1[index] < ver2[index])
4403 return -1;
4404
4405 if ((ver1[index - 1] < '6') || ((ver1[index - 1] == '6') && (ver1[index] <= 'q')))
4406 return 0;
4407
4408 index++;
4409
4410 if (ver1[index] > ver2[index])
4411 return 1;
4412 else if (ver1[index] < ver2[index])
4413 return -1;
4414
4415 return 0;
4416}
4417
4418/*!*****************************************************************************
4419 * \brief Get libxcoder SW release version
4420 *
4421 * \return char pointer to libxcoder SW release version
4422 ******************************************************************************/
4424{
4425 static char release_ver_str[6] = "";
4426 // init static array one byte at a time to avoid compiler error C2099
4427 if (!release_ver_str[0])
4428 {
4429 release_ver_str[0] = NI_XCODER_REVISION[0];
4430 release_ver_str[1] = '.';
4431 release_ver_str[2] = NI_XCODER_REVISION[1];
4432 release_ver_str[3] = '.';
4433 release_ver_str[4] = NI_XCODER_REVISION[2];
4434 release_ver_str[5] = 0;
4435 }
4436 return &release_ver_str[0];
4437}
4438
4439/*!*****************************************************************************
4440 * \brief Get text string for the provided error
4441 *
4442 * \return char pointer for the provided error
4443 ******************************************************************************/
4445{
4446 int i;
4447 for (i = 0;
4448 i < sizeof(ni_err_rc_description) / sizeof(ni_err_rc_txt_entry_t); i++)
4449 {
4450 if (rc == ni_err_rc_description[i].rc)
4451 {
4452 return ni_err_rc_description[i].txt;
4453 }
4454 }
4455 return "rc not supported";
4456}
4457
4458/*!*****************************************************************************
4459 * \brief retrieve key and value from 'key=value' pair
4460 *
4461 * \param[in] p_str pointer to string to extract pair from
4462 * \param[out] key pointer to key
4463 * \param[out] value pointer to value
4464 *
4465 * \return return 0 if successful, otherwise 1
4466 *
4467 ******************************************************************************/
4468int ni_param_get_key_value(char *p_str, char *key, char *value)
4469{
4470 if (!p_str || !key || !value)
4471 {
4472 return 1;
4473 }
4474
4475 char *p = strchr(p_str, '=');
4476 if (!p)
4477 {
4478 return 1;
4479 } else
4480 {
4481 *p = '\0';
4482 key[0] = '\0';
4483 value[0] = '\0';
4484 int64_t key_len = p - p_str;
4485 ni_strncpy(key, 256, p_str, key_len);
4486 ni_strcpy(value, 256, p + 1);
4487 return 0;
4488 }
4489}
4490
4491/*!*****************************************************************************
4492 * \brief retrieve encoder config parameter values from --xcoder-params
4493 *
4494 * \param[in] xcoderParams pointer to string containing xcoder params
4495 * \param[out] params pointer to xcoder params to fill out
4496 * \param[out] ctx pointer to session context
4497 *
4498 * \return return 0 if successful, -1 otherwise
4499 *
4500 ******************************************************************************/
4501int ni_retrieve_xcoder_params(char xcoderParams[],
4502 ni_xcoder_params_t *params,
4504{
4505 char key[64], value[64];
4506 char *curr = xcoderParams, *colon_pos;
4507 int ret = 0;
4508
4509 while (*curr)
4510 {
4511 colon_pos = strchr(curr, ':');
4512
4513 if (colon_pos)
4514 {
4515 *colon_pos = '\0';
4516 }
4517
4518 if (strlen(curr) > sizeof(key) + sizeof(value) - 1 ||
4519 ni_param_get_key_value(curr, key, value))
4520 {
4522 "Error: xcoder-params p_config key/value not "
4523 "retrieved: %s\n",
4524 curr);
4525 ret = -1;
4526 break;
4527 }
4528 ret = ni_encoder_params_set_value(params, key, value);
4529 switch (ret)
4530 {
4532 ni_log(NI_LOG_ERROR, "Error: unknown option: %s.\n", key);
4533 break;
4535 ni_log(NI_LOG_ERROR, "Error: invalid value for %s: %s.\n", key,
4536 value);
4537 break;
4538 default:
4539 break;
4540 }
4541
4542 if (NI_RETCODE_SUCCESS != ret)
4543 {
4544 ni_log(NI_LOG_ERROR, "Error: config parsing failed %d: %s\n", ret,
4545 ni_get_rc_txt(ret));
4546 break;
4547 }
4548
4549 if (colon_pos)
4550 {
4551 curr = colon_pos + 1;
4552 } else
4553 {
4554 curr += strlen(curr);
4555 }
4556 }
4558 // reuse decoder_low_delay for low delay encoding to store wait interval
4559 // in send/recv multi-thread mode.
4560 ctx->decoder_low_delay = params->low_delay_mode;
4561
4562 return ret;
4563}
4564
4565/*!*****************************************************************************
4566 * \brief Retrieve custom gop config values from --xcoder-gop
4567 *
4568 * \param[in] xcoderGop pointer to string containing xcoder gop
4569 * \param[out] params pointer to xcoder params to fill out
4570 * \param[out] ctx pointer to session context
4571 *
4572 * \return return 0 if successful, -1 otherwise
4573 *
4574 ******************************************************************************/
4575int ni_retrieve_xcoder_gop(char xcoderGop[],
4576 ni_xcoder_params_t *params,
4578{
4579 (void)ctx;
4580 char key[64], value[64];
4581 char *curr = xcoderGop, *colon_pos;
4582 int ret = 0;
4583
4584 while (*curr)
4585 {
4586 colon_pos = strchr(curr, ':');
4587
4588 if (colon_pos)
4589 {
4590 *colon_pos = '\0';
4591 }
4592
4593 if (strlen(curr) > sizeof(key) + sizeof(value) - 1 ||
4594 ni_param_get_key_value(curr, key, value))
4595 {
4597 "Error: xcoder-params p_config key/value not "
4598 "retrieved: %s\n",
4599 curr);
4600 ret = -1;
4601 break;
4602 }
4603 ret = ni_encoder_gop_params_set_value(params, key, value);
4604 switch (ret)
4605 {
4607 ni_log(NI_LOG_ERROR, "Error: unknown option: %s.\n", key);
4608 break;
4610 ni_log(NI_LOG_ERROR, "Error: invalid value for %s: %s.\n", key,
4611 value);
4612 break;
4613 default:
4614 break;
4615 }
4616
4617 if (NI_RETCODE_SUCCESS != ret)
4618 {
4619 ni_log(NI_LOG_ERROR, "Error: gop config parsing failed %d: %s\n", ret,
4620 ni_get_rc_txt(ret));
4621 break;
4622 }
4623
4624 if (colon_pos)
4625 {
4626 curr = colon_pos + 1;
4627 } else
4628 {
4629 curr += strlen(curr);
4630 }
4631 }
4632
4633 return ret;
4634}
4635
4636/*!*****************************************************************************
4637 * \brief retrieve decoder config parameter values from --decoder-params
4638 *
4639 * \param[in] xcoderParams pointer to string containing xcoder params
4640 * \param[out] params pointer to xcoder params to fill out
4641 * \param[out] ctx pointer to session context
4642 *
4643 * \return return 0 if successful, -1 otherwise
4644 *
4645 ******************************************************************************/
4646int ni_retrieve_decoder_params(char xcoderParams[],
4647 ni_xcoder_params_t *params,
4649{
4650 char key[64], value[64];
4651 char *curr = xcoderParams, *colon_pos;
4652 int ret = 0;
4653
4654 while (*curr)
4655 {
4656 colon_pos = strchr(curr, ':');
4657
4658 if (colon_pos)
4659 {
4660 *colon_pos = '\0';
4661 }
4662
4663 if (strlen(curr) > sizeof(key) + sizeof(value) - 1 ||
4664 ni_param_get_key_value(curr, key, value))
4665 {
4667 "Error: decoder-params p_config key/value not "
4668 "retrieved: %s\n",
4669 curr);
4670 ret = -1;
4671 break;
4672 }
4673 ret = ni_decoder_params_set_value(params, key, value);
4674 switch (ret)
4675 {
4677 ni_log(NI_LOG_ERROR, "Error: unknown option: %s.\n", key);
4678 break;
4680 ni_log(NI_LOG_ERROR, "Error: invalid value for %s: %s.\n", key,
4681 value);
4682 break;
4683 default:
4684 break;
4685 }
4686
4687 if (NI_RETCODE_SUCCESS != ret)
4688 {
4689 ni_log(NI_LOG_ERROR, "Error: config parsing failed %d: %s\n", ret,
4690 ni_get_rc_txt(ret));
4691 break;
4692 }
4693
4694 if (colon_pos)
4695 {
4696 curr = colon_pos + 1;
4697 } else
4698 {
4699 curr += strlen(curr);
4700 }
4701 }
4704
4705 return ret;
4706}
4707
4708/*!*****************************************************************************
4709 * \brief initialize a mutex
4710 *
4711 * \param[in] thread mutex
4712 *
4713 * \return On success returns 0
4714 * On failure returns <0
4715 ******************************************************************************/
4716int ni_pthread_mutex_init(ni_pthread_mutex_t *mutex)
4717{
4718#ifdef _WIN32
4719 bool rc = false;
4720 // error return zero
4721 rc = InitializeCriticalSectionEx(mutex, 0, CRITICAL_SECTION_NO_DEBUG_INFO);
4722 if (rc)
4723 {
4724 return 0;
4725 }
4726 else
4727 {
4728 return -1;
4729 }
4730#else
4731 int rc;
4732 ni_pthread_mutexattr_t attr;
4733
4734 rc = pthread_mutexattr_init(&attr);
4735 if (rc != 0)
4736 {
4737 return -1;
4738 }
4739
4740 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
4741
4742 return pthread_mutex_init(mutex, &attr);
4743#endif
4744}
4745
4746/*!*****************************************************************************
4747 * \brief destory a mutex
4748 *
4749 * \param[in] thread mutex
4750 *
4751 * \return On success returns 0
4752 * On failure returns <0
4753 ******************************************************************************/
4754int ni_pthread_mutex_destroy(ni_pthread_mutex_t *mutex)
4755{
4756#ifdef _WIN32
4757 DeleteCriticalSection(mutex);
4758 return 0;
4759#else
4760 return pthread_mutex_destroy(mutex);
4761#endif
4762}
4763
4764/*!*****************************************************************************
4765 * \brief thread mutex lock
4766 *
4767 * \param[in] thread mutex
4768 *
4769 * \return On success returns 0
4770 * On failure returns <0
4771 ******************************************************************************/
4772int ni_pthread_mutex_lock(ni_pthread_mutex_t *mutex)
4773{
4774 int rc = 0;
4775 if (mutex != NULL)
4776 {
4777#ifdef _WIN32
4778 EnterCriticalSection(mutex);
4779#else
4780 rc = pthread_mutex_lock(mutex);
4781#endif
4782 } else
4783 {
4784 rc = -1;
4785 }
4786
4787 return rc;
4788}
4789
4790/*!*****************************************************************************
4791 * \brief thread mutex unlock
4792 *
4793 * \param[in] thread mutex
4794 *
4795 * \return On success returns 0
4796 * On failure returns <0
4797 ******************************************************************************/
4798int ni_pthread_mutex_unlock(ni_pthread_mutex_t *mutex)
4799{
4800 int rc = 0;
4801 if (mutex != NULL)
4802 {
4803#ifdef _WIN32
4804 LeaveCriticalSection(mutex);
4805#else
4806 rc = pthread_mutex_unlock(mutex);
4807#endif
4808 } else
4809 {
4810 rc = -1;
4811 }
4812
4813 return rc;
4814}
4815
4816#ifdef _WIN32
4817static unsigned __stdcall __thread_worker(void *arg)
4818{
4819 ni_pthread_t *t = (ni_pthread_t *)arg;
4820 t->rc = t->start_routine(t->arg);
4821 return 0;
4822}
4823#endif
4824
4825/*!*****************************************************************************
4826 * \brief create a new thread
4827 *
4828 * \param[in] thread thread id
4829 * \param[in] attr attributes to the new thread
4830 * \param[in] start_routine entry of the thread routine
4831 * \param[in] arg sole argument of the routine
4832 *
4833 * \return On success returns 0
4834 * On failure returns <0
4835 ******************************************************************************/
4836int ni_pthread_create(ni_pthread_t *thread, const ni_pthread_attr_t *attr,
4837 void *(*start_routine)(void *), void *arg)
4838{
4839#ifdef _WIN32
4840 thread->start_routine = start_routine;
4841 thread->arg = arg;
4842 thread->handle =
4843#if HAVE_WINRT
4844 (void *)CreateThread(NULL, 0, win32thread_worker, thread, 0, NULL);
4845#else
4846 (void *)_beginthreadex(NULL, 0, __thread_worker, thread, 0, NULL);
4847#endif
4848 return !thread->handle;
4849#else
4850 return pthread_create(thread, attr, start_routine, arg);
4851#endif
4852}
4853
4854/*!*****************************************************************************
4855 * \brief join with a terminated thread
4856 *
4857 * \param[in] thread thread id
4858 * \param[out] value_ptr return status
4859 *
4860 * \return On success returns 0
4861 * On failure returns <0
4862 ******************************************************************************/
4863int ni_pthread_join(ni_pthread_t thread, void **value_ptr)
4864{
4865#ifdef _WIN32
4866 DWORD rc = WaitForSingleObject(thread.handle, INFINITE);
4867 if (rc != WAIT_OBJECT_0)
4868 {
4869 if (rc == WAIT_ABANDONED)
4870 return EINVAL;
4871 else
4872 return EDEADLK;
4873 }
4874 if (value_ptr)
4875 *value_ptr = thread.rc;
4876 CloseHandle(thread.handle);
4877 return 0;
4878#else
4879 return pthread_join(thread, value_ptr);
4880#endif
4881}
4882
4883/*!*****************************************************************************
4884 * \brief initialize condition variables
4885 *
4886 * \param[in] cond condition variable
4887 * \param[in] attr attribute to the condvar
4888 *
4889 * \return On success returns 0
4890 * On failure returns <0
4891 ******************************************************************************/
4892int ni_pthread_cond_init(ni_pthread_cond_t *cond,
4893 const ni_pthread_condattr_t *attr)
4894{
4895#ifdef _WIN32
4896 InitializeConditionVariable(cond);
4897 return 0;
4898#else
4899 return pthread_cond_init(cond, attr);
4900#endif
4901}
4902
4903/*!*****************************************************************************
4904 * \brief destroy condition variables
4905 *
4906 * \param[in] cond condition variable
4907 *
4908 * \return On success returns 0
4909 * On failure returns <0
4910 ******************************************************************************/
4911int ni_pthread_cond_destroy(ni_pthread_cond_t *cond)
4912{
4913#ifdef _WIN32
4914 /* native condition variables do not destroy */
4915 return 0;
4916#else
4917 return pthread_cond_destroy(cond);
4918#endif
4919}
4920
4921/*!*****************************************************************************
4922 * \brief broadcast a condition
4923 *
4924 * \param[in] cond condition variable
4925 *
4926 * \return On success returns 0
4927 * On failure returns <0
4928 ******************************************************************************/
4929int ni_pthread_cond_broadcast(ni_pthread_cond_t *cond)
4930{
4931#ifdef _WIN32
4932 WakeAllConditionVariable(cond);
4933 return 0;
4934#else
4935 return pthread_cond_broadcast(cond);
4936#endif
4937}
4938
4939/*!*****************************************************************************
4940 * \brief wait on a condition
4941 *
4942 * \param[in] cond condition variable
4943 * \param[in] mutex mutex related to the condvar
4944 *
4945 * \return On success returns 0
4946 * On failure returns <0
4947 ******************************************************************************/
4948int ni_pthread_cond_wait(ni_pthread_cond_t *cond, ni_pthread_mutex_t *mutex)
4949{
4950#ifdef _WIN32
4951 SleepConditionVariableCS(cond, mutex, INFINITE);
4952 return 0;
4953#else
4954 return pthread_cond_wait(cond, mutex);
4955#endif
4956}
4957
4958/*!******************************************************************************
4959 * \brief signal a condition
4960 *
4961 * \param[in] cond condition variable
4962 *
4963 * \return On success returns 0
4964 * On failure returns <0
4965 *******************************************************************************/
4966int ni_pthread_cond_signal(ni_pthread_cond_t *cond)
4967{
4968#ifdef _WIN32
4969 WakeConditionVariable(cond);
4970 return 0;
4971#else
4972 return pthread_cond_signal(cond);
4973#endif
4974}
4975
4976/*!*****************************************************************************
4977 * \brief wait on a condition
4978 *
4979 * \param[in] cond condition variable
4980 * \param[in] mutex mutex related to the condvar
4981 * \param[in[ abstime abstract value of timeout
4982 *
4983 * \return On success returns 0
4984 * On failure returns <0
4985 ******************************************************************************/
4986int ni_pthread_cond_timedwait(ni_pthread_cond_t *cond,
4987 ni_pthread_mutex_t *mutex,
4988 const struct timespec *abstime)
4989{
4990#ifdef _WIN32
4991 int64_t abs_ns = abstime->tv_sec * 1000000000LL + abstime->tv_nsec;
4992 DWORD t = (uint32_t)((abs_ns - ni_gettime_ns()) / 1000000);
4993
4994 if (!SleepConditionVariableCS(cond, mutex, t))
4995 {
4996 DWORD err = GetLastError();
4997 if (err == ERROR_TIMEOUT)
4998 return ETIMEDOUT;
4999 else
5000 return EINVAL;
5001 }
5002 return 0;
5003#else
5004 return pthread_cond_timedwait(cond, mutex, abstime);
5005#endif
5006}
5007
5008/*!*****************************************************************************
5009 * \brief examine and change mask of blocked signals
5010 *
5011 * \param[in] how behavior of this call, can be value of SIG_BLOCK,
5012 * SIG_UNBLOCK and SIG_SETMASK
5013 * \param[in] set current value of the signal mask. If NULL, the mask keeps
5014 * unchanged.
5015 * \param[in] old_set previous value of the signal mask, can be NULL.
5016 *
5017 * \return On success returns 0
5018 * On failure returns <0
5019 ******************************************************************************/
5020int ni_pthread_sigmask(int how, const ni_sigset_t *set, ni_sigset_t *oldset)
5021{
5022#ifdef _WIN32
5023 return 0;
5024#else
5025 return pthread_sigmask(how, set, oldset);
5026#endif
5027}
5028
5029/*!*****************************************************************************
5030 * \brief return error string according to error code from firmware
5031 *
5032 * \param[in] rc error code return from firmware
5033 *
5034 * \return error string
5035 ******************************************************************************/
5036const char *ni_ai_errno_to_str(int rc)
5037{
5038 switch (rc)
5039 {
5041 return "Success";
5043 return "General Error";
5045 return "Not Initialized";
5047 return "Already Initialized";
5049 return "IO Busy";
5051 return "Resource Not Available";
5053 return "Create Network Failed";
5055 return "Input Buffer Full";
5057 return "Output Buffer Empty";
5059 return "Invalid Params";
5061 return "Error Start Network";
5063 return "Erorr Set Inout";
5065 return "Bad Option";
5067 return "Map Error";
5069 return "Context Not Available";
5071 return "Model Not Found";
5073 return "IO Error";
5075 return "Invalid Address";
5077 return "Out Of Memory";
5079 return "Bad Inout";
5081 return "Invalid Instance";
5083 return "IO Not Allowed";
5085 return "Network Not Ready";
5086 default:
5087 return "Other Error";
5088 }
5089}
5090/*!******************************************************************************
5091 * \brief decode the raw current obtained and determine power
5092 *
5093 * \param[in] current_value current value
5094 * \param[in] serial_number board SN
5095 *
5096 * \return On success returns power
5097 * On failure returns -1
5098 ********************************************************************************/
5099uint32_t ni_decode_power_measurement(uint32_t current_data, const uint8_t *serial_number)
5100{
5101 uint32_t power_mw;
5102 float current_ma,voltage_mv;
5103
5104 if ((!serial_number) || (current_data == NI_INVALID_POWER))
5105 {
5106 return NI_INVALID_POWER;
5107 }
5108 char pcb_config[3];
5109 (void)snprintf(pcb_config, sizeof(pcb_config), "%.2s", &serial_number[2]);
5110
5111 float current_value = (float)current_data;
5112 voltage_mv = 12000.0f;
5113 if (strncmp(pcb_config, "A1", 2) == 0)
5114 {
5115 current_ma = (((current_value * 1000) / TPS25940_R_IMON) - TPS25940_IMON_OS) / TPS25940_GAIN_IMON;
5116 }
5117 else if ((strncmp(pcb_config, "A2", 2) == 0) || (strncmp(pcb_config, "A3", 2) == 0))
5118 {
5119 current_ma = ((current_value * MAX15162AAWE_C_IRATIO) / MAX15162AAWE_R_IMON);
5120 }
5121 else if ((strncmp(pcb_config, "AA", 2) == 0) || (strncmp(pcb_config, "AB", 2) == 0))
5122 {
5123 current_ma = (((current_value * 1000) / (TPS25946_R_IMON_T2A * TPS25946_GAIN_IMON)) * 1000);
5124 }
5125 else if (strncmp(pcb_config, "U0", 2) == 0)
5126 {
5127 current_ma = ((((current_value) * MAX17613B_R_ISET_TOTAL / MAX17613B_R_ISET_R2) *
5129 }
5130 else if ((strncmp(pcb_config, "U1", 2) == 0) || (strncmp(pcb_config, "U2", 2) == 0) || (strncmp(pcb_config, "U3", 2) == 0))
5131 {
5132 current_ma = ((1 * current_value * MAX15162AAWE_C_IRATIO) / MAX15162AAWE_R_IMON);
5133 }
5134 else if (strncmp(pcb_config, "UA", 2) == 0)
5135 {
5136 current_ma = (((current_value * 1000) / (TPS25946_R_IMON_T1U_UA * TPS25946_GAIN_IMON)) * 1000);
5137 }
5138 else if (strncmp(pcb_config, "S0", 2) == 0)
5139 {
5140 current_ma = (((current_value * 1000) / (TPS25946_R_IMON_T1S * TPS25946_GAIN_IMON)) * 1000);
5141 }
5142 else if ((strncmp(pcb_config, "M0", 2) == 0) || (strncmp(pcb_config, "M1", 2) == 0))
5143 {
5144 current_ma = ((((current_value * 1000) / (TPS25974_R_IMON_T1M * TPS25974_GAIN_IMON)) * 1000) * MCU_REF_VOLTAGE) / MCU_FSR_ADC;
5145 voltage_mv = 3300.0f;
5146 }
5147 else if (strncmp(pcb_config, "M", 1) == 0) // Other than M0 and M1
5148 {
5149 current_ma = ((current_value * 1000) / (TPS25974_R_IMON_T1M * TPS25974_GAIN_IMON)) * 1000;
5150 voltage_mv = 3300.0f;
5151 }
5152 else
5153 {
5154 return NI_INVALID_POWER;
5155 }
5156 power_mw = (uint32_t)((voltage_mv * current_ma) / 1000.0);
5157 return power_mw;
5158}
5159
5160/*!******************************************************************************
5161 * \brief Check a device can be read by ni_device_capability_query()
5162 * by checking the size of the device using ioctl
5163 *
5164 * INFO OR ERROR logs will not be printed in this function
5165 *
5166 * \param[in] p_dev device path string. eg: "/dev/nvme1n2"
5167 * \param[in] size_needed The minimum required size
5168 *
5169 * \return
5170 * returns -1
5171 * when the device can not be read by ni_device_capability_query()
5172 *
5173 * returns 1
5174 * when the device can be read by ni_device_capability_query()
5175 *
5176 * returns 0 when the result can not be determined
5177 *
5178 *******************************************************************************/
5179static int ni_device_size_precheck_ioctl(const char *p_dev, const uint64_t size_needed)
5180{
5181#if defined(_WIN32) || !defined(BLKGETSIZE64)
5182 (void)p_dev;
5183 (void)size_needed;
5184 return 0;
5185#else
5186 int fd = -1;
5187 int call_ret = 0;
5188 int ret = 0;
5189 uint64_t bytes = 0;
5190
5191 if (!p_dev)
5192 {
5193 return -1;
5194 }
5195
5196 fd = open(p_dev, O_RDONLY);
5197
5198 if (fd < 0)
5199 {
5200 return 0;
5201 }
5202
5203 call_ret = ioctl(fd, BLKGETSIZE64, &bytes);
5204 if (call_ret < 0)
5205 {
5206 ret = 0;
5207 }
5208 else if (bytes < size_needed)
5209 {
5210 ret = -1;
5211 }
5212 else
5213 {
5214 ret = 1;
5215 }
5216
5217 close(fd);
5218 return ret;
5219#endif
5220}
5221
5222/*!******************************************************************************
5223 * \brief Check a device can be read by ni_device_capability_query()
5224 * by checking the vendor id
5225 *
5226 * INFO OR ERROR logs will not be printed in this function
5227 *
5228 * \param[in] p_dev device path string. eg: "/dev/nvme1n2"
5229 *
5230 * \return
5231 * returns -1
5232 * when the device can not be read by ni_device_capability_query()
5233 *
5234 * returns 1
5235 * when the device can be read by ni_device_capability_query()
5236 *
5237 * returns 0 when the result can not be determined
5238 *
5239 *******************************************************************************/
5240static int ni_device_vendor_id_precheck(const char *p_dev)
5241{
5242#ifndef __linux__
5243 (void) p_dev;
5244 return 0;
5245#else
5246
5247 int ret = 0;
5248
5249 if (!p_dev)
5250 {
5251 return -1;
5252 }
5253
5254 const char *vendor_path_devs[] = {"/sys/class/block/%s/device/vendor", "/sys/class/block/%s/device/device/vendor"};
5255
5256 const char *last_slash = strrchr(p_dev, '/');
5257 const char *device_name = (last_slash ? (last_slash + 1) : p_dev);
5258
5259 const size_t path_len = strlen(p_dev);
5260
5261 for (size_t i = 0; i < sizeof(vendor_path_devs)/sizeof(vendor_path_devs[0]); ++i)
5262 {
5263 size_t template_len = strlen(vendor_path_devs[i]);
5264 char *vendor_path = (char *)calloc(1, template_len + path_len);
5265 if (!vendor_path)
5266 {
5267 continue;
5268 }
5269 (void)snprintf(vendor_path, template_len + path_len, vendor_path_devs[i], device_name);
5270
5271 int fd = open(vendor_path, O_RDONLY);
5272 if (fd >= 0)
5273 {
5274 char vendor_id[10] = {0};
5275 ssize_t read_size = read(fd, vendor_id, sizeof(vendor_id));
5276 if (read_size >= 4 && (size_t)read_size < sizeof(vendor_id))
5277 {
5278 char *find_1d82 = strstr(vendor_id, "1d82");
5279 if (find_1d82)
5280 {
5281 ret = 1;
5282 }
5283 else
5284 {
5285 ni_log2(NULL, NI_LOG_DEBUG, "%s() vendor check failed. vendor id: %s", __func__, vendor_id);
5286 ret = -1;
5287 }
5288 }
5289
5290 close(fd);
5291 }
5292
5293 free(vendor_path);
5294
5295 if (ret != 0)
5296 {
5297 break;
5298 }
5299 }
5300
5301 return ret;
5302
5303#endif
5304}
5305
5306
5307/*!******************************************************************************
5308 * \brief Check a device can be read by ni_device_capability_query()
5309 * by reading size from /sys/class/block/<devname>/size and
5310 * /sys/class/block/<devname>/queue/logical_block_size
5311 *
5312 * INFO OR ERROR logs will not be printed in this function
5313 *
5314 * \param[in] p_dev device path string. eg: "/dev/nvme1n2"
5315 * \param[in] size_needed The minimum required size
5316 *
5317 * \return
5318 * returns -1
5319 * when the device can not be read by ni_device_capability_query()
5320 *
5321 * returns 1
5322 * when the device can be read by ni_device_capability_query()
5323 *
5324 * returns 0 when the result can not be determined
5325 *
5326 *******************************************************************************/
5327static int ni_device_size_precheck_system_information(const char *p_dev, const uint64_t size_needed)
5328{
5329#ifndef __linux__
5330 (void) p_dev;
5331 (void) size_needed;
5332 return 0;
5333#else
5334
5335 int ret = 0;
5336
5337 if (!p_dev)
5338 {
5339 return -1;
5340 }
5341
5342 const char block_path_dev[] = "/sys/class/block/%s/size";
5343 const char logical_block_size_path_dev[] = "/sys/class/block/%s/queue/logical_block_size";
5344
5345 const char *last_slash = strrchr(p_dev, '/');
5346 const char *device_name = (last_slash ? (last_slash + 1) : p_dev);
5347
5348 const size_t path_len = strlen(p_dev);
5349
5350 int size_fd = -1;
5351 int logical_block_fd = -1;
5352
5353 char *block_path = (char *)calloc(1, sizeof(block_path_dev) + path_len);
5354 char *logical_block_size_path = (char *)calloc(1, sizeof(logical_block_size_path_dev) + path_len);
5355
5356 if (!block_path || !logical_block_size_path)
5357 {
5358 LRETURN;
5359 }
5360
5361 (void)snprintf(block_path, sizeof(block_path_dev) + path_len, block_path_dev, device_name);
5362 (void)snprintf(logical_block_size_path, sizeof(logical_block_size_path_dev) + path_len, logical_block_size_path_dev, device_name);
5363
5364 size_fd = open(block_path, O_RDONLY);
5365 logical_block_fd = open(logical_block_size_path, O_RDONLY);
5366
5367 if (size_fd < 0 || logical_block_fd < 0)
5368 {
5369 LRETURN;
5370 }
5371
5372 char this_size_str [20] = {0};
5373 char this_block_size_str [20] = {0};
5374
5375 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)
5376 {
5377 ret = 0;
5378 }
5379 else
5380 {
5381 char *endptr1 = NULL;
5382 char *endptr2 = NULL;
5383 errno = 0;
5384 unsigned long long this_size = strtoull(this_size_str, &endptr1, 10);
5385 unsigned long long this_block_size = strtoull(this_block_size_str, &endptr2, 10);
5386
5387 if (errno == 0 && endptr1 != this_size_str && endptr2 != this_block_size_str)
5388 {
5389 if (this_size * this_block_size >= size_needed)
5390 {
5391 ret = 1;
5392 }
5393 else
5394 {
5395 ni_log2(NULL, NI_LOG_DEBUG, "%s() read size check failed. size: %" PRIu64 "\n", __func__, this_size * this_block_size);
5396 ret = -1;
5397 }
5398 }
5399 }
5400
5401END:
5402 if (block_path)
5403 {
5404 free(block_path);
5405 }
5406 if (logical_block_size_path)
5407 {
5408 free(logical_block_size_path);
5409 }
5410
5411 if (size_fd >= 0)
5412 {
5413 close(size_fd);
5414 }
5415 if (logical_block_fd >= 0)
5416 {
5417 close(logical_block_fd);
5418 }
5419
5420 return ret;
5421
5422#endif
5423}
5424
5425/*!******************************************************************************
5426 * \brief precheck a device can be read by ni_device_capability_query()
5427 * INFO OR ERROR logs will not be printed in this function
5428 * \param[in] p_dev device path string. eg: "/dev/nvme1n2"
5429 *
5430 * \return
5431 * returns NI_RETCODE_FAILURE
5432 * when the device can not be read by ni_device_capability_query()
5433 *
5434 * returns NI_RETCODE_SUCCESS when
5435 * 1. the device can not be read by ni_device_capability_query()
5436 * 2. the result can not be determined to prevent query failures due to
5437 * some reasons such as missing commands on the system
5438 *******************************************************************************/
5440{
5441#ifndef __linux__
5442 (void) p_dev;
5443 return 0;
5444#else
5445 int ret = 0;
5446
5447 const uint64_t SIZE_NEEDED = ((IDENTIFY_DEVICE_R) << (LBA_BIT_OFFSET)) + (NI_NVME_IDENTITY_CMD_DATA_SZ);
5448
5449 if (!p_dev)
5450 {
5451 return NI_RETCODE_FAILURE;
5452 }
5453
5454 const size_t path_len = strlen(p_dev);
5455
5456 if (path_len > NI_MAX_DEVICE_NAME_LEN)
5457 {
5458 return NI_RETCODE_FAILURE;
5459 }
5460
5461 ret = ni_device_size_precheck_ioctl(p_dev, SIZE_NEEDED);
5462 if (ret > 0)
5463 {
5464 return NI_RETCODE_SUCCESS;
5465 }
5466 if (ret < 0)
5467 {
5468 return NI_RETCODE_FAILURE;
5469 }
5470
5471 ret = ni_device_vendor_id_precheck(p_dev);
5472 if (ret > 0)
5473 {
5474 return NI_RETCODE_SUCCESS;
5475 }
5476 if (ret < 0)
5477 {
5478 return NI_RETCODE_FAILURE;
5479 }
5480
5481 ret = ni_device_size_precheck_system_information(p_dev, SIZE_NEEDED);
5482 if (ret > 0)
5483 {
5484 return NI_RETCODE_SUCCESS;
5485 }
5486 if (ret < 0)
5487 {
5488 return NI_RETCODE_FAILURE;
5489 }
5490
5491 // ret == 0 here: prechecks were inconclusive, default to success
5492 return NI_RETCODE_SUCCESS;
5493
5494#endif
5495}
#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:4110
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:4892
#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:4107
int ni_pthread_mutex_lock(ni_pthread_mutex_t *mutex)
thread mutex lock
Definition ni_util.c:4772
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:3352
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:4911
void ni_SHA256Update(SHA256CTX *psCtx, const uint8_t aui8Data[], size_t ui32Length)
Definition ni_util.c:4187
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:3106
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:4080
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:5439
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:4127
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:3186
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:4111
void ni_SHA256Final(SHA256CTX *psCtx, uint8_t aui8Hash[])
Definition ni_util.c:4205
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:2936
int ni_pthread_cond_signal(ni_pthread_cond_t *cond)
signal a condition
Definition ni_util.c:4966
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:4501
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:4836
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:2888
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:4357
const char * ni_ai_errno_to_str(int rc)
return error string according to error code from firmware
Definition ni_util.c:5036
int ni_pthread_cond_broadcast(ni_pthread_cond_t *cond)
broadcast a condition
Definition ni_util.c:4929
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:3957
int ni_param_get_key_value(char *p_str, char *key, char *value)
retrieve key and value from 'key=value' pair
Definition ni_util.c:4468
void ni_calculate_sha256(const uint8_t aui8Data[], size_t ui32DataLength, uint8_t aui8Hash[])
Definition ni_util.c:4261
int ni_pthread_mutex_destroy(ni_pthread_mutex_t *mutex)
destory a mutex
Definition ni_util.c:4754
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:4287
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:2747
char * ni_strtok(char *s, const char *delim, char **saveptr)
Definition ni_util.c:429
void ni_SHA256Init(SHA256CTX *psCtx)
Definition ni_util.c:4173
#define SIG1(x)
Definition ni_util.c:4112
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:3792
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:5020
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:4074
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:4444
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:4986
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:4646
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:4575
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:4311
#define EP0(x)
Definition ni_util.c:4109
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:4324
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:4863
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:3947
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:3299
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:2799
int ni_pthread_mutex_unlock(ni_pthread_mutex_t *mutex)
thread mutex unlock
Definition ni_util.c:4798
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:4423
int ni_pthread_mutex_init(ni_pthread_mutex_t *mutex)
initialize a mutex
Definition ni_util.c:4716
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:3967
int ni_pthread_cond_wait(ni_pthread_cond_t *cond, ni_pthread_mutex_t *mutex)
wait on a condition
Definition ni_util.c:4948
#define MAJ(x, y, z)
Definition ni_util.c:4108
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:3060
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:5099
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:4387
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:4100
uint32_t aui32State[8]
Definition ni_util.c:4101
uint8_t aui8Data[64]
Definition ni_util.c:4098
uint32_t ui32DataLength
Definition ni_util.c:4099
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:3821
uint32_t next_idx
Definition ni_util.c:3822
void * private
Definition ni_util.c:3820