libxcoder  3.5.1
ni_util_logan.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_logan.c
24 *
25 * \brief Exported utility routines
26 *
27 *******************************************************************************/
28 
29 #if defined(__linux__) || defined(__APPLE__)
30 #include <sys/ioctl.h>
31 #include <sys/stat.h>
32 #include <sys/ioctl.h>
33 #include <sys/mman.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <sys/time.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39 #include <dirent.h>
40 #endif
41 
42 #include "ni_nvme_logan.h"
43 #include "ni_util_logan.h"
44 
45 #ifdef XCODER_SIM_ENABLED
46 static int32_t sim_run_count = 0;
47 static int32_t sim_eos_flag = 0;
48 #endif
49 
56 int32_t ni_logan_gettimeofday(struct timeval *p_tp, void *p_tzp)
57 {
58 #ifdef _WIN32
59  FILETIME file_time;
60  SYSTEMTIME system_time;
61  ULARGE_INTEGER ularge;
63  static const unsigned __int64 epoch = ((unsigned __int64)116444736000000000ULL);
64 
65  (void)p_tzp;
67  GetSystemTime(&system_time);
68  SystemTimeToFileTime(&system_time, &file_time);
69  ularge.LowPart = file_time.dwLowDateTime;
70  ularge.HighPart = file_time.dwHighDateTime;
71 
72  p_tp->tv_sec = (long)((ularge.QuadPart - epoch) / 10000000L);
73  p_tp->tv_usec = (long)(system_time.wMilliseconds * 1000);
74 
75  return 0;
76 #else
77  return gettimeofday(p_tp, p_tzp);
78 #endif
79 }
80 
81 uint64_t ni_logan_gettime_ns(void)
82 {
83 #ifdef _WIN32
84  LARGE_INTEGER frequency;
85  LARGE_INTEGER count;
86  uint64_t time_sec, time_nsec;
87 
88  // Get frequency firstly
89  QueryPerformanceFrequency(&frequency);
90 
91  QueryPerformanceCounter(&count);
92 
93  time_sec = count.QuadPart / frequency.QuadPart;
94  time_nsec = (count.QuadPart - time_sec * frequency.QuadPart) * 1000000000LL / frequency.QuadPart;
95 
96  return (time_sec * 1000000000LL + time_nsec);
97 #else
98  struct timespec ts;
99  clock_gettime(CLOCK_REALTIME, &ts);
100  return ts.tv_sec * 1000000000LL + ts.tv_nsec;
101 #endif
102 }
103 
104 uint32_t ni_logan_round_up(uint32_t number_to_round, uint32_t multiple)
105 {
106  uint32_t remainder;
107 
108  if (0 == multiple)
109  {
110  return number_to_round;
111  }
112 
113  remainder = number_to_round % multiple;
114  if (0 == remainder)
115  {
116  return number_to_round;
117  }
118 
119  return number_to_round + multiple - remainder;
120 }
121 
122 int32_t ni_logan_posix_memalign(void ** pp_memptr, size_t alignment, size_t size)
123 {
124 #ifdef _WIN32
125  *pp_memptr = malloc(size);
126  if (NULL == *pp_memptr)
127  {
128  return 1;
129  }
130  else
131  {
132  ZeroMemory(*pp_memptr, size);
133  return 0;
134  }
135 #else
136  return posix_memalign(pp_memptr, alignment, size);
137 #endif
138 }
139 
140 #ifdef __linux__
141 static inline int ni_logan_min(int a, int b)
142 {
143  return a < b ? a : b;
144 }
145 
146 static inline int ni_logan_max(int a, int b)
147 {
148  return a > b ? a : b;
149 }
150 
151 /*!******************************************************************************
152 * \brief Get max io transfer size from the kernel
153 *
154 * \param
155 *
156 * \return
157 *******************************************************************************/
158 uint32_t ni_logan_get_kernel_max_io_size(const char * p_dev)
159 {
160  FILE *p_file = NULL; /* file pointer*/
161  char file_name[KERNEL_NVME_FILE_NAME_MAX_SZ];
162  uint32_t max_segments = 0, min_io_size = 0, max_hw_sectors_kb = 0;
163  uint32_t io_size = DEFAULT_IO_TRANSFER_SIZE;
164  int len = 0, err = 0;
165 
166 
167  if ( !p_dev )
168  {
169  ni_log(NI_LOG_TRACE, "Invalid Arguments\n");
170  LRETURN;
171  }
172 
173  len = strlen(p_dev) - 5;
174  if(len < MIN_NVME_BLK_NAME_LEN)
175  {
176  ni_log(NI_LOG_TRACE, "p_dev length is %d\n",len);
177  LRETURN;
178  }
179 
180  // Get Max number of segments from /sys
181  memset(file_name,0,sizeof(file_name));
182  memcpy(file_name,SYS_PARAMS_PREFIX_PATH,SYS_PREFIX_SZ);
183  //start from 5 chars ahead to not copy the "/dev/" since we only need whats after it
184  if (strstr(p_dev, "block"))
185  {
186  strncat(file_name, (char*)(p_dev + 11) , sizeof(file_name) - SYS_PREFIX_SZ);
187  }
188  else
189  {
190  strncat(file_name, (char*)(p_dev + 5) , sizeof(file_name) - SYS_PREFIX_SZ);
191  }
192  strncat(file_name, KERNEL_NVME_MAX_SEG_PATH, sizeof(file_name) - SYS_PREFIX_SZ - len);
193  ni_log(NI_LOG_TRACE, "file_name is %s\n",file_name);
194  p_file = fopen(file_name,"r");
195  if (!p_file)
196  {
197  ni_log(NI_LOG_ERROR, "Error %d: file_name failed to open: %s\n",
198  NI_ERRNO, file_name);
199  LRETURN;
200  }
201 
202  err = fscanf(p_file,"%u",&max_segments);
203  if (EOF == err)
204  {
205  ni_log(NI_LOG_ERROR, "Error %d: fscanf failed on: %s max_segments\n",
206  NI_ERRNO, file_name);
207  LRETURN;
208  }
209 
210  fclose(p_file);
211  p_file = NULL;
212  // Get Max segment size from /sys
213  memset(file_name,0,sizeof(file_name));
214  memcpy(file_name,SYS_PARAMS_PREFIX_PATH,SYS_PREFIX_SZ);
215  if (strstr(p_dev, "block"))
216  {
217  strncat(file_name, (char*)(p_dev + 11) , sizeof(file_name) - SYS_PREFIX_SZ);
218  }
219  else
220  {
221  strncat(file_name, (char*)(p_dev + 5) , sizeof(file_name) - SYS_PREFIX_SZ);
222  }
223  strncat(file_name, KERNEL_NVME_MIN_IO_SZ_PATH, sizeof(file_name) - SYS_PREFIX_SZ - len);
224  ni_log(NI_LOG_TRACE, "file_name is %s\n",file_name);
225  p_file = fopen(file_name,"r");
226  if (!p_file)
227  {
228  ni_log(NI_LOG_ERROR, "Error %d: file_name failed to open: %s\n",
229  NI_ERRNO, file_name);
230  LRETURN;
231  }
232 
233  err = fscanf(p_file,"%u",&min_io_size);
234  if (EOF == err)
235  {
236  ni_log(NI_LOG_TRACE, "fscanf failed on: %s min_io_size\n",file_name);
237  LRETURN;
238  }
239 
240  fclose(p_file);
241  p_file = NULL;
242  //Now get max_hw_sectors_kb
243  memset(file_name,0,sizeof(file_name));
244  memcpy(file_name,SYS_PARAMS_PREFIX_PATH,SYS_PREFIX_SZ);
245  if (strstr(p_dev, "block"))
246  {
247  strncat(file_name, (char*)(p_dev + 11) , sizeof(file_name) - SYS_PREFIX_SZ);
248  }
249  else
250  {
251  strncat(file_name, (char*)(p_dev + 5) , sizeof(file_name) - SYS_PREFIX_SZ);
252  }
253  strncat(file_name, KERNEL_NVME_MAX_HW_SEC_KB_PATH, sizeof(file_name) - SYS_PREFIX_SZ - len);
254  ni_log(NI_LOG_TRACE, "file_name is %s\n",file_name);
255  p_file = fopen(file_name,"r");
256  if (!p_file)
257  {
258  ni_log(NI_LOG_ERROR, "Error %d: file_name failed to open: %s\n",
259  NI_ERRNO, file_name);
260  LRETURN;
261  }
262 
263  err = fscanf(p_file,"%u",&max_hw_sectors_kb);
264  if (EOF == err)
265  {
266  ni_log(NI_LOG_TRACE, "fscanf failed on: %s min_io_size\n",file_name);
267  LRETURN;
268  }
269 
270  if( ni_logan_min(min_io_size * max_segments, max_hw_sectors_kb * 1024) > MAX_IO_TRANSFER_SIZE )
271  {
272  io_size = MAX_IO_TRANSFER_SIZE;
273  }
274  else
275  {
276  io_size = ni_logan_min( min_io_size * max_segments, max_hw_sectors_kb * 1024);
277  }
278 
279  ni_log(NI_LOG_DEBUG, "\nMAX NVMe IO Size of %d was calculated for this platform "
280  "and will be used unless overwritten by user settings\n", io_size);
281  fflush(stderr);
282 
283  END:
284 
285  if(p_file)
286  {
287  fclose(p_file);
288  }
289 
290  return io_size;
291 }
292 
293 #endif
294 
295 void ni_logan_usleep(int64_t usec)
296 {
297 #ifdef _WIN32
298  if(usec < 5000) //this will be more accurate when less than 5000
299  {
300  LARGE_INTEGER Count;
301  LARGE_INTEGER Count_;
302  LARGE_INTEGER Frequency;
303  QueryPerformanceCounter(&Count);
304  QueryPerformanceFrequency(&Frequency);
305  Count_.QuadPart = Count.QuadPart + usec*(Frequency.QuadPart/1000000);
306  do
307  {
308  QueryPerformanceCounter(&Count);
309  } while(Count.QuadPart<Count_.QuadPart);
310  }
311  else
312  {
313  HANDLE timer = NULL;
314  LARGE_INTEGER ft = { 0 };
315  BOOL retval = FALSE;
316 
317  ft.QuadPart = -(10 * usec); // Convert to 100 nanosecond interval, negative value indicates relative time
318 
319  timer = CreateWaitableTimer(NULL, TRUE, NULL);
320  if (NULL != timer)
321  {
322  retval = SetWaitableTimer(timer, &ft, 0, NULL, NULL, 0);
323  if (retval)
324  {
325  WaitForSingleObject(timer, INFINITE);
326  }
327  }
328 
329  if (timer)
330  {
331  CloseHandle(timer);
332  }
333  }
334 #else
335  if (usec < 0xFFFFFFFF) // to avoid overflow
336  {
337  usleep(usec);
338  }
339  else
340  {
341  sleep(usec >> 32);
342  }
343 #endif
344 }
345 
346 // memory buffer pool operations (one use is for decoder frame buffer pool)
347 // expand buffer pool by a pre-defined size
349 {
350  int32_t i;
351  for (i = 0; i < NI_LOGAN_DEC_FRAME_BUF_POOL_SIZE_EXPAND; i++)
352  {
353  if( NULL == ni_logan_buf_pool_allocate_buffer(pool, pool->buf_size) )
354  {
355  ni_log(NI_LOG_ERROR, "FATAL ERROR: Failed to expand allocate pool buffer for "
356  "pool :%p current size: %d\n", pool, pool->number_of_buffers);
357  return NULL;
358  }
359  }
361  return pool->p_free_head;
362 }
363 
364 // get a free memory buffer from the pool
366 {
367  ni_logan_buf_t *buf = NULL;
368 
369  if (NULL == p_buffer_pool)
370  {
371  return NULL;
372  }
373 
374  ni_logan_pthread_mutex_lock(&(p_buffer_pool->mutex));
375  buf = p_buffer_pool->p_free_head;
376 
377  // find and return a free buffer
378  if (NULL == buf)
379  {
380  ni_log(NI_LOG_ERROR, "Expanding dec fme buffer_pool from %d to %d \n",
381  p_buffer_pool->number_of_buffers,
383 
384  buf = ni_logan_buf_pool_expand(p_buffer_pool);
385 
386  if (NULL == buf)
387  {
388  ni_logan_pthread_mutex_unlock(&(p_buffer_pool->mutex));
389  return NULL;
390  }
391  }
392 
393  // remove it from free list head; reconnect the linked list, the p_next
394  // will become the new head now
395  p_buffer_pool->p_free_head = buf->p_next_buffer;
396 
397  if ( NULL != buf->p_next_buffer )
398  {
399  buf->p_next_buffer->p_previous_buffer = NULL;
400  }
401  else
402  {
403  p_buffer_pool->p_free_tail = NULL;
404  }
405 
406  // add it to the used list tail
407  buf->p_previous_buffer = p_buffer_pool->p_used_tail;
408  buf->p_next_buffer = NULL;
409 
410  if ( NULL != p_buffer_pool->p_used_tail )
411  {
412  p_buffer_pool->p_used_tail->p_next_buffer = buf;
413  }
414  else
415  {
416  p_buffer_pool->p_used_head = buf;
417  }
418 
419  p_buffer_pool->p_used_tail = buf;
420 
421  ni_logan_pthread_mutex_unlock(&(p_buffer_pool->mutex));
422 
423  ni_log(NI_LOG_TRACE, "%s ptr %p buf %p\n", __FUNCTION__, buf->buf, buf);
424  return buf;
425 }
426 
427 // return a used memory buffer to the pool
429 {
430  // p_buffer_pool could be null in case of delayed buffer return after pool
431  // has been freed
432  if(! buf)
433  {
434  return;
435  }
436 
437  ni_log(NI_LOG_TRACE, "%s ptr %p buf %p\n", __FUNCTION__, buf->buf, buf);
438 
439  if (! p_buffer_pool)
440  {
441  ni_log(NI_LOG_TRACE, "%s: pool already freed self destroy\n", __FUNCTION__);
442  free(buf->buf);
443  free(buf);
444  return;
445  }
446 
447  ni_logan_pthread_mutex_lock(&(p_buffer_pool->mutex));
448 
449  // remove buf from the used list
450  if (NULL != buf->p_previous_buffer)
451  {
453  }
454  else
455  {
456  p_buffer_pool->p_used_head = buf->p_next_buffer;
457  }
458 
459  if (NULL != buf->p_next_buffer)
460  {
462  }
463  else
464  {
465  p_buffer_pool->p_used_tail = buf->p_previous_buffer;
466  }
467 
468  // put it on the tail of free buffers list
469  buf->p_previous_buffer = p_buffer_pool->p_free_tail;
470  buf->p_next_buffer = NULL;
471 
472  if (NULL != p_buffer_pool->p_free_tail)
473  {
474  p_buffer_pool->p_free_tail->p_next_buffer = buf;
475  }
476  else
477  {
478  p_buffer_pool->p_free_head = buf;
479  }
480 
481  p_buffer_pool->p_free_tail = buf;
482 
483  // shrink the buffer pool by EXPAND size if free list size is at least
484  // 2x EXPAND to manage buffer pool expansion
485  int count = 0;
486  ni_logan_buf_t *p_tmp = p_buffer_pool->p_free_head;
487  while (p_tmp)
488  {
489  count++;
490  p_tmp = p_tmp->p_next_buffer;
491  }
492 
494  {
495  ni_log(NI_LOG_INFO, "%s shrink buf pool free size from %d by %d, "
496  "current total: %u\n",
497  __FUNCTION__, count, NI_LOGAN_DEC_FRAME_BUF_POOL_SIZE_EXPAND,
498  p_buffer_pool->number_of_buffers);
499 
500  p_tmp = p_buffer_pool->p_free_head;
501  while (p_tmp && count > NI_LOGAN_DEC_FRAME_BUF_POOL_SIZE_EXPAND)
502  {
503  p_buffer_pool->p_free_head = p_tmp->p_next_buffer;
504  free(p_tmp->buf);
505  free(p_tmp);
506  p_tmp = p_buffer_pool->p_free_head;
507  count--;
508  p_buffer_pool->number_of_buffers--;
509  }
510  }
511 
512  ni_logan_pthread_mutex_unlock(&(p_buffer_pool->mutex));
513 }
514 
515 // allocate a memory buffer and place it in the pool
517  int buffer_size)
518 {
519  ni_logan_buf_t *p_buffer = NULL;
520  void *p_buf = NULL;
521 
522  if (NULL != p_buffer_pool &&
523  (p_buffer = (ni_logan_buf_t *)malloc(sizeof(ni_logan_buf_t))) != NULL)
524  {
525  // init the struct
526  memset(p_buffer, 0, sizeof(ni_logan_buf_t));
527 
528  if (ni_logan_posix_memalign(&p_buf, sysconf(_SC_PAGESIZE), buffer_size))
529  {
530  free(p_buffer);
531  ni_log(NI_LOG_ERROR, "ERROR %d: %s() failed\n",
532  NI_ERRNO, __FUNCTION__);
533  return NULL;
534  }
535  ni_log(NI_LOG_TRACE, "%s ptr %p buf %p\n", __FUNCTION__, p_buf, p_buffer);
536  p_buffer->buf = p_buf;
537  p_buffer->pool = p_buffer_pool;
538 
539  // add buffer to the buf pool list
540  p_buffer->p_prev = NULL;
541  p_buffer->p_next = NULL;
542  p_buffer->p_previous_buffer = p_buffer_pool->p_free_tail;
543 
544  if (p_buffer_pool->p_free_tail != NULL)
545  {
546  p_buffer_pool->p_free_tail->p_next_buffer = p_buffer;
547  }
548  else
549  {
550  p_buffer_pool->p_free_head = p_buffer;
551  }
552 
553  p_buffer_pool->p_free_tail = p_buffer;
554  }
555 
556  return p_buffer;
557 }
558 
559 // decoder frame buffer pool init & free
561  int32_t number_of_buffers,
562  int width,
563  int height,
564  int height_align,
565  int factor)
566 {
567  int32_t i;
568  int width_aligned = width;
569  int height_aligned = height;
570 
571  ni_log(NI_LOG_TRACE, "%s: enter\n", __FUNCTION__);
572 
573  width_aligned = ((width + 31) / 32) * 32;
574  height_aligned = ((height + 7) / 8) * 8;
575  if (height_align)
576  {
577  height_aligned = ((height + 15) / 16) * 16;
578  }
579 
580  uint32_t luma_size = width_aligned * height_aligned * factor;
581  uint32_t chroma_b_size = luma_size / 4;
582  uint32_t chroma_r_size = chroma_b_size;
583  uint32_t buffer_size = luma_size + chroma_b_size + chroma_r_size +
585 
586  // added 2 blocks of 512 bytes buffer space to handle any extra metadata
587  // retrieval from fw
588  buffer_size = ((buffer_size + (NI_LOGAN_MEM_PAGE_ALIGNMENT - 1)) / NI_LOGAN_MEM_PAGE_ALIGNMENT) *
590 
591  if (p_ctx->dec_fme_buf_pool != NULL)
592  {
593  ni_log(NI_LOG_TRACE, "Warning init dec_fme Buf pool already with size %d\n",
595 
596  if (buffer_size > p_ctx->dec_fme_buf_pool->buf_size)
597  {
598  ni_log(NI_LOG_ERROR, "Warning resolution %dx%d memory buffer size %d > %d "
599  "(existing buffer size), re-allocating !\n", width, height,
600  buffer_size, p_ctx->dec_fme_buf_pool->buf_size);
602  }
603  else
604  {
605  ni_log(NI_LOG_ERROR, "INFO resolution %dx%d memory buffer size %d <= %d "
606  "(existing buffer size), continue !\n", width, height,
607  buffer_size, p_ctx->dec_fme_buf_pool->buf_size);
608  return 0;
609  }
610  }
611 
612  if ((p_ctx->dec_fme_buf_pool = (ni_logan_buf_pool_t *) malloc(sizeof(ni_logan_buf_pool_t))) == NULL)
613  {
614  ni_log(NI_LOG_ERROR, "Error %d: alloc for dec fme buf pool\n",
615  NI_ERRNO);
616  return -1;
617  }
618 
619  // init the struct
620  memset(p_ctx->dec_fme_buf_pool, 0, sizeof(ni_logan_buf_pool_t));
621  ni_logan_pthread_mutex_init(&(p_ctx->dec_fme_buf_pool->mutex));
622  p_ctx->dec_fme_buf_pool->number_of_buffers = number_of_buffers;
623 
624  ni_log(NI_LOG_TRACE, "%s: entries %d entry size %d\n",
625  __FUNCTION__, number_of_buffers, buffer_size);
626 
627  p_ctx->dec_fme_buf_pool->buf_size = buffer_size;
628  for (i = 0; i < number_of_buffers; i++)
629  {
630  if (NULL == ni_logan_buf_pool_allocate_buffer(p_ctx->dec_fme_buf_pool, buffer_size))
631  {
632  // release everything we have allocated so far and exit
634  return -1;
635  }
636  }
637 
638  ni_log(NI_LOG_TRACE, "%s: exit\n", __FUNCTION__);
639  return 0;
640 }
641 
643 {
644  ni_logan_buf_t *buf, *p_next;
645  int32_t count_free = 0;
646 
647  ni_log(NI_LOG_TRACE, "%s: enter.\n", __FUNCTION__);
648 
649  if (p_buffer_pool)
650  {
651  // mark used buf not returned at pool free time by setting pool ptr in used
652  // buf to NULL, so they will self-destroy when time is due eventually
653  ni_logan_pthread_mutex_lock(&(p_buffer_pool->mutex));
654 
655  if (buf = p_buffer_pool->p_used_head)
656  {
657  p_next = buf;
658  while (buf)
659  {
660  p_next = buf->p_next_buffer;
661  ni_log(NI_LOG_TRACE, "Release ownership of ptr %p buf %p\n", buf->buf, buf);
662  buf->pool = NULL;
663  buf = p_next;
664  }
665  }
666  ni_logan_pthread_mutex_unlock(&(p_buffer_pool->mutex));
667 
668  buf = p_buffer_pool->p_free_head;
669  p_next = buf;
670  // free all the buffers in the free list
671  while (buf)
672  {
673  p_next = buf->p_next_buffer;
674  free(buf->buf);
675  free(buf);
676  buf = p_next;
677  count_free++;
678  }
679 
680  if (count_free != p_buffer_pool->number_of_buffers)
681  {
682  ni_log(NI_LOG_TRACE, "%s free %d != number_of_buffers %d\n",
683  __FUNCTION__, count_free, p_buffer_pool->number_of_buffers);
684  }
685  else
686  {
687  ni_log(NI_LOG_TRACE, "%s all buffers freed: %d.\n",
688  __FUNCTION__, count_free);
689  }
690  free(p_buffer_pool);
691  p_buffer_pool = NULL;
692  }
693  else
694  {
695  ni_log(NI_LOG_INFO, "%s: NOT allocated\n", __FUNCTION__);
696  }
697 }
698 
700 {
701  ni_logan_queue_node_t *buf, *p_next;
702  int32_t count = 0;
703 
704  ni_log(NI_LOG_TRACE, "%s: enter.\n", __FUNCTION__);
705 
706  if (p_buffer_pool)
707  {
708  buf = p_buffer_pool->p_free_head;
709  p_next = buf;
710  // free all the buffers in the free and used list
711  while (buf)
712  {
713  p_next = buf->p_next_buffer;
714  free(buf);
715  buf = p_next;
716  count++;
717  }
718 
719  buf = p_buffer_pool->p_used_head;
720  p_next = buf;
721  while (buf)
722  {
723  p_next = buf->p_next_buffer;
724  free(buf);
725  buf = p_next;
726  count++;
727  }
728 
729  if (count != p_buffer_pool->number_of_buffers)
730  {
731  ni_log(NI_LOG_ERROR, "??? freed %d != number_of_buffers %d\n",
732  count, p_buffer_pool->number_of_buffers);
733  }
734  else
735  {
736  ni_log(NI_LOG_TRACE, "p_buffer_pool freed %d buffers.\n", count);
737  }
738  free(p_buffer_pool);
739  p_buffer_pool = NULL;
740  }
741  else
742  {
743  ni_log(NI_LOG_ERROR, "%s: NOT allocated\n", __FUNCTION__);
744  }
745 }
746 
748 {
749  ni_logan_queue_node_t *p_buffer = NULL;
750 
751  if (NULL != p_buffer_pool && ( (p_buffer = (ni_logan_queue_node_t *)malloc(sizeof(ni_logan_queue_node_t))) != NULL) )
752  {
753  //Inititalise the struct
754  memset(p_buffer,0,sizeof(ni_logan_queue_node_t));
755  // add buffer to the buf pool list
756  p_buffer->p_prev = NULL;
757  p_buffer->p_next = NULL;
758  p_buffer->p_previous_buffer = p_buffer_pool->p_free_tail;
759 
760  if (p_buffer_pool->p_free_tail != NULL)
761  {
762  p_buffer_pool->p_free_tail->p_next_buffer = p_buffer;
763  }
764  else
765  {
766  p_buffer_pool->p_free_head = p_buffer;
767  }
768 
769  p_buffer_pool->p_free_tail = p_buffer;
770  }
771 
772  return p_buffer;
773 }
774 
775 int32_t ni_logan_buffer_pool_initialize(ni_logan_session_context_t* p_ctx, int32_t number_of_buffers)
776 {
777  int32_t i;
778 
779  ni_log(NI_LOG_TRACE, "%s: enter\n", __FUNCTION__);
780 
781  if (p_ctx->buffer_pool != NULL)
782  {
783  ni_log(NI_LOG_TRACE, "Warn init Buf pool already with size %d\n",
785  return -1;
786  }
787 
788  if ((p_ctx->buffer_pool = (ni_logan_queue_buffer_pool_t *) malloc(sizeof(ni_logan_queue_buffer_pool_t))) == NULL)
789  {
790  ni_log(NI_LOG_ERROR, "Error %d: alloc for pool\n", NI_ERRNO);
791  return -1;
792  }
793 
794  //initialise the struct
795  memset(p_ctx->buffer_pool,0,sizeof(ni_logan_queue_buffer_pool_t));
796  p_ctx->buffer_pool->number_of_buffers = number_of_buffers;
797  //p_buffer_pool->p_free_head = NULL;
798  //p_buffer_pool->p_free_tail = NULL;
799  //p_buffer_pool->p_used_head = NULL;
800  //p_buffer_pool->p_used_tail = NULL;
801 
802  for (i = 0; i < number_of_buffers; i++)
803  {
805  {
806  //Release everything we have allocated so far and exit
808  return -1;
809  }
810  }
811 
812  return 0;
813 }
814 
816 {
817  int32_t i;
818  for (i = 0; i < 200; i++)
819  {
820  //TODO: What happens is ni_logan_buffer_pool_allocate_buffer fails and returns a NULL pointer?
821  if( NULL == ni_logan_buffer_pool_allocate_buffer(pool) )
822  {
823  ni_log(NI_LOG_ERROR, "FATAL ERROR: Failed to allocate pool buffer for pool :%p\n", pool);
824  return NULL;
825  }
826  }
827  pool->number_of_buffers += 200;
828  return pool->p_free_head;
829 }
830 
832 {
833  ni_logan_queue_node_t *buf = NULL;
834 
835  if( NULL == p_buffer_pool)
836  {
837  return NULL;
838  }
839 
840  buf = p_buffer_pool->p_free_head;
841 
842  // find and return a free buffer
843  if ( NULL == buf )
844  {
845  ni_log(NI_LOG_ERROR, "Expanding p_buffer_pool from %d to %d \n",
846  p_buffer_pool->number_of_buffers, p_buffer_pool->number_of_buffers + 200);
847  buf = ni_logan_buffer_pool_expand(p_buffer_pool);
848  if (NULL == buf)
849  {
850  return NULL; //return null otherwise there will be null derefferencing later
851  }
852  }
853 
854  buf->checkout_timestamp = time(NULL);
855  // remove it from free list head; reconnect the linked list, the p_next
856  // will become the new head now
857  p_buffer_pool->p_free_head = buf->p_next_buffer;
858 
859  if ( NULL != buf->p_next_buffer )
860  {
861  buf->p_next_buffer->p_previous_buffer = NULL;
862  }
863  else
864  {
865  p_buffer_pool->p_free_tail = NULL;
866  }
867 
868  // add it to the used list tail
869  buf->p_previous_buffer = p_buffer_pool->p_used_tail;
870  buf->p_next_buffer = NULL;
871 
872  if ( NULL != p_buffer_pool->p_used_tail )
873  {
874  p_buffer_pool->p_used_tail->p_next_buffer = buf;
875  }
876  else
877  {
878  p_buffer_pool->p_used_head = buf;
879  }
880 
881  p_buffer_pool->p_used_tail = buf;
882 
883  return buf;
884 }
885 
887  ni_logan_queue_buffer_pool_t *p_buffer_pool)
888 {
889  if( (!buf) || !(p_buffer_pool) )
890  {
891  return;
892  }
893 
894  // remove buf from the used list
895  if ( NULL != buf->p_previous_buffer )
896  {
898  }
899  else
900  {
901  p_buffer_pool->p_used_head = buf->p_next_buffer;
902  }
903 
904  if ( NULL != buf->p_next_buffer )
905  {
907  }
908  else
909  {
910  p_buffer_pool->p_used_tail = buf->p_previous_buffer;
911  }
912 
913  // put it on the tail of free buffers list
914  buf->p_previous_buffer = p_buffer_pool->p_free_tail;
915  buf->p_next_buffer = NULL;
916 
917  if ( NULL != p_buffer_pool->p_free_tail )
918  {
919  p_buffer_pool->p_free_tail->p_next_buffer = buf;
920  }
921  else
922  {
923  p_buffer_pool->p_free_head = buf;
924  }
925 
926  p_buffer_pool->p_free_tail = buf;
927 }
928 
929 /*!******************************************************************************
930 * \brief Remove a string-pattern from a string in-place.
931 *
932 * \param[in,out] str Null terminated array of characters to operate upon in-place.
933 * \param[in] pattern Null terminated array of characters to remove from str.
934 * Supports special characters '#' and '+' for digit matching and
935 * repeated matching respectively. Note, there is no way to \a escape
936 * the special characters.
937 * \b Example:
938 * char a_str[10] = "aaa123qwe";
939 * char b_str[5] = "a+#+";
940 * ni_logan_remove_substring_pattern(a_str, b_str);
941 * printf("%s\n", a_str);
942 * \b Output:
943 * qwe
944 *
945 * \return Output of the pointer to the modified str
946 *******************************************************************************/
947 static inline int char_match(char s, char p)
948 {
949  return s == p || p == '#' && isdigit(s);
950 }
951 
952 static char *ni_logan_remove_substring_pattern(char *str, char *pattern)
953 {
954  char *start = str;
955  char *end = str;
956  char *p = pattern;
957 
958  if (!str || !pattern || *start == '\0' || *p == '\0' || *p == '+')
959  {
960  // Invalid string
961  return str;
962  }
963 
964  while (*end != '\0' || *p == '+')
965  {
966  if (*p == '\0')
967  {
968  // remove pattern matched substring
969  strcpy(start, end);
970  end = start;
971  p = pattern;
972  }
973  else if (*p == '+')
974  {
975  if (char_match(end[-1], p[-1]) && char_match(end[0], p[-1]))
976  {
977  end++;
978  }
979  else
980  {
981  p++;
982  }
983  }
984  else if (char_match(end[0], p[0]))
985  {
986  end++;
987  p++;
988  }
989  else
990  {
991  end++;
992  start = end;
993  p = pattern;
994  }
995  }
996 
997  // remove trailing pattern matched substring
998  if (*p == '\0')
999  {
1000  strcpy(start, end);
1001  }
1002 
1003  return str;
1004 }
1005 
1006 #ifdef __ANDROID__
1007 /*!******************************************************************************
1008 * \brief use cmd to search nvme block file
1009 *
1010 * \param[in] p_dev Device name represented as c string. ex: "/dev/nvme0"
1011 * \param[in] search cmd
1012 * \param[in] cmd_ret length
1013 * \param[out] cmd_ret search result for nvme block file
1014 *
1015 * \return On success returns NI_LOGAN_RETCODE_SUCCESS
1016 * On failure returns NI_LOGAN_RETCODE_FAILURE
1017 * On failure returns NI_LOGAN_RETCODE_INVALID_PARAM
1018 *******************************************************************************/
1019 static ni_logan_retcode_t ni_logan_search_file(const char *p_dev, char *cmd, char *cmd_ret, int cmd_ret_len)
1020 {
1021  FILE *cmd_fp;
1022 
1023  if (access(p_dev, F_OK) == -1)
1024  {
1025  return NI_LOGAN_RETCODE_FAILURE;
1026  }
1027 
1028  // look for child block in sysfs mapping tree
1029  cmd_fp = popen(cmd, "r");
1030  if (!cmd_fp)
1031  {
1032  return NI_LOGAN_RETCODE_FAILURE;
1033  }
1034 
1035  if (fgets(cmd_ret, cmd_ret_len, cmd_fp) == NULL)
1036  {
1037  pclose(cmd_fp);
1039  }
1040 
1041  ni_logan_remove_substring_pattern(cmd_ret, "c#+");
1042 
1043  pclose(cmd_fp);
1044 
1045  return NI_LOGAN_RETCODE_SUCCESS;
1046 }
1047 #endif
1048 
1049 /*!******************************************************************************
1050 * \brief Find NVMe name space block from device name
1051 * If none is found, assume nvme multi-pathing is disabled and return /dev/nvmeXn1
1052 *
1053 * \param[in] p_dev Device name represented as c string. ex: "/dev/nvme0"
1054 * \param[out] p_out_buf Output buffer to put NVMe name space block. Must be at least length 21
1055 * \param[in] out_buf_len Length of memory allocated to p_out_buf
1056 *
1057 * \return On success returns NI_LOGAN_RETCODE_SUCCESS
1058 * On failure returns NI_LOGAN_RETCODE_FAILURE
1059 *******************************************************************************/
1060 ni_logan_retcode_t ni_logan_find_blk_name(const char *p_dev, char *p_out_buf, int out_buf_len)
1061 {
1062  FILE *cmd_fp;
1063  char cmd[128] = {'\0'};
1064  char cmd_ret[22] = {'\0'};
1065 
1066  if (!p_dev || !p_out_buf)
1067  {
1069  }
1070 
1071 #ifdef _WIN32
1072  ni_log(NI_LOG_TRACE, "In Windows block name equals to device name\n");
1073  snprintf(p_out_buf, out_buf_len, "%s", p_dev);
1074  return NI_LOGAN_RETCODE_SUCCESS;
1075 #elif defined(XCODER_LINUX_VIRTIO_DRIVER_ENABLED)
1076  ni_log(NI_LOG_TRACE, "The device is already considered as a block divice in Linux virtual machine with VirtIO driver.\n");
1077  snprintf(p_out_buf, out_buf_len, "%s", p_dev);
1078  return NI_LOGAN_RETCODE_SUCCESS;
1079 #elif defined(__APPLE__)
1080  snprintf(p_out_buf, out_buf_len, "%s", p_dev);
1081  return NI_LOGAN_RETCODE_SUCCESS;
1082 #else
1083 
1084 #ifdef __ANDROID__
1085  // assumes no indexing differences between sysfs and udev on Android (ie. no nvme multi-pathing)
1086  // p_dev[5] is p_dev without '/dev/'
1087  snprintf(cmd, sizeof(cmd) - 1, "ls /sys/class/nvme/%s/ | grep %s", &p_dev[5], NI_LOGAN_NVME_PREFIX);
1088 #else
1089  // Note, we are using udevadm through terminal instead of libudev.c to avoid requiring extra kernel dev packges
1090  snprintf(cmd, sizeof(cmd) - 1, "ls /sys/`udevadm info -q path -n %s` | grep -m 1 -P \"%s(\\d+c)?\\d+n\\d+\"",
1091  p_dev, NI_LOGAN_NVME_PREFIX);
1092 #endif
1093 
1094  // check p_dev exists in /dev/ folder. If not, return NI_LOGAN_RETCODE_FAILURE
1095  if (access(p_dev, F_OK) == -1)
1096  {
1097  return NI_LOGAN_RETCODE_FAILURE;
1098  }
1099 
1100  // look for child block in sysfs mapping tree
1101  cmd_fp = popen(cmd, "r");
1102  if (!cmd_fp)
1103  {
1104  return NI_LOGAN_RETCODE_FAILURE;
1105  }
1106 
1107  if (fgets(cmd_ret, sizeof(cmd_ret)/sizeof(cmd_ret[0]), cmd_fp) == NULL)
1108  {
1109  ni_log(NI_LOG_TRACE, "Failed to find namespaceID. Using guess.\n");
1110  snprintf(p_out_buf, out_buf_len, "%sn1", p_dev);
1111  }
1112  else
1113  {
1114  cmd_ret[strcspn(cmd_ret, "\r\n")] = 0;
1115  ni_logan_remove_substring_pattern(cmd_ret, "c#+");
1116 #ifdef __ANDROID__
1118  snprintf(cmd, sizeof(cmd) - 1, "ls /dev/ | grep %s", cmd_ret); // cmd_ret is block device name
1119  int cmd_ret_len = sizeof(cmd_ret)/sizeof(cmd_ret[0]);
1120  ret = ni_logan_search_file(p_dev, cmd, cmd_ret, cmd_ret_len);
1121  if (ret == NI_LOGAN_RETCODE_SUCCESS)
1122  {
1123  char *tmp = NULL;
1124  if ((tmp = strstr(cmd_ret, "\n")))
1125  {
1126  *tmp = '\0';
1127  }
1128  snprintf(p_out_buf, out_buf_len, "/dev/%s", cmd_ret);
1129  }
1130  else if (ret == NI_LOGAN_RETCODE_INVALID_PARAM)
1131  {
1132  snprintf(cmd, sizeof(cmd) - 1, "ls /dev/block/ | grep %s", cmd_ret); // cmd_ret is block device name
1133  ret = ni_logan_search_file(p_dev, cmd, cmd_ret, cmd_ret_len);
1134  if (ret == NI_LOGAN_RETCODE_SUCCESS)
1135  {
1136  char *tmp = NULL;
1137  if ((tmp = strstr(cmd_ret, "\n")))
1138  {
1139  *tmp = '\0';
1140  }
1141  snprintf(p_out_buf, out_buf_len, "/dev/block/%s", cmd_ret);
1142  }
1143  else if (ret == NI_LOGAN_RETCODE_INVALID_PARAM)
1144  {
1145  ni_log(NI_LOG_ERROR, "Error: %s can not find block device %s\n",
1146  __FUNCTION__, cmd_ret);
1147  }
1148  else
1149  {
1150  pclose(cmd_fp);
1151  return ret;
1152  }
1153  }
1154  else
1155  {
1156  pclose(cmd_fp);
1157  return ret;
1158  }
1159 #else
1160  // On systems with virtualized NVMe functions sysfs will include context index in namespaceID.
1161  // But, udev will not.
1162  // Thus, it will be necessary to remove the context index from the namespaceID
1163  // when mapping deviceID to namespaceID through sysfs.
1164  // ex. change "/dev/nvme0c0n2" to "/dev/nvme0n2"
1165  snprintf(p_out_buf, out_buf_len, "/dev/%s", cmd_ret);
1166 #endif
1167  }
1168 
1169  pclose(cmd_fp);
1170 
1171  return NI_LOGAN_RETCODE_SUCCESS;
1172 #endif
1173 }
1174 
1175 /*!******************************************************************************
1176 * \brief Initialize timestamp handling
1177 *
1178 * \param
1179 *
1180 * \return
1181 *******************************************************************************/
1183  ni_logan_timestamp_table_t **pp_table,
1184  const char *name)
1185 {
1187 
1188  ni_log(NI_LOG_TRACE, "%s: enter\n", __FUNCTION__);
1189 
1190  if (*pp_table != NULL)
1191  {
1192  ni_log(NI_LOG_TRACE, "%s: previously allocated, reallocating now\n", __FUNCTION__);
1193  ni_logan_queue_free(&(*pp_table)->list, p_ctx->buffer_pool);
1194  free(*pp_table);
1195  }
1196  ni_log(NI_LOG_TRACE, "%s: Malloc\n", __FUNCTION__);
1197  ptemp = (ni_logan_timestamp_table_t *)malloc(sizeof(ni_logan_timestamp_table_t));
1198  if (!ptemp)
1199  {
1200  ni_log(NI_LOG_ERROR, "Error %d: %s\n", NI_ERRNO, __FUNCTION__);
1202  }
1203 
1204  //initialise the struct
1205  memset(ptemp,0,sizeof(ni_logan_timestamp_table_t));
1206 
1207  ni_logan_queue_init(p_ctx, &ptemp->list, name); //buffer_pool_initialize runs in here
1208 
1209  *pp_table = ptemp;
1210 
1211  ni_log(NI_LOG_TRACE, "%s: success\n", __FUNCTION__);
1212 
1213  return NI_LOGAN_RETCODE_SUCCESS;
1214 }
1215 
1216 /*!******************************************************************************
1217 * \brief Clean up timestamp handling
1218 *
1219 * \param
1220 *
1221 * \return
1222 *******************************************************************************/
1224  ni_logan_queue_buffer_pool_t *p_buffer_pool)
1225 {
1226  ni_log(NI_LOG_TRACE, "%s: enter\n", __FUNCTION__);
1227 
1228  if (!p_table)
1229  {
1230  ni_log(NI_LOG_TRACE, "%s: no pts table to free\n", __FUNCTION__);
1231  return NI_LOGAN_RETCODE_SUCCESS;
1232  }
1233  ni_logan_queue_free(&p_table->list, p_buffer_pool);
1234 
1235  free(p_table);
1236  p_table = NULL;
1237  ni_log(NI_LOG_TRACE, "%s: success\n", __FUNCTION__);
1238 
1239  return NI_LOGAN_RETCODE_SUCCESS;
1240 }
1241 
1242 /*!******************************************************************************
1243 * \brief Register timestamp in timestamp/frameoffset table
1244 *
1245 * \param
1246 *
1247 * \return
1248 *******************************************************************************/
1250  ni_logan_timestamp_table_t *p_table,
1251  int64_t timestamp,
1252  uint64_t data_info)
1253 {
1255 
1256  err = ni_logan_queue_push(p_buffer_pool, &p_table->list, data_info, timestamp);
1257 
1258  if(NI_LOGAN_RETCODE_SUCCESS == err)
1259  {
1260  ni_log(NI_LOG_TRACE, "%s: success\n", __FUNCTION__);
1261  }
1262  else
1263  {
1264  ni_log(NI_LOG_TRACE, "ERROR: %s: FAILED\n", __FUNCTION__);
1265  }
1266 
1267  return err;
1268 }
1269 
1270 /*!******************************************************************************
1271 * \brief Retrieve timestamp from table based on frameoffset info
1272 *
1273 * \param
1274 *
1275 * \return
1276 *******************************************************************************/
1278  uint64_t frame_info,
1279  int64_t *p_timestamp,
1280  int32_t threshold,
1281  int32_t print,
1282  ni_logan_queue_buffer_pool_t *p_buffer_pool)
1283 {
1285 
1286  ni_log(NI_LOG_TRACE, "%s: getting timestamp with frame_info=%" PRIu64 "\n",
1287  __FUNCTION__, frame_info);
1288 
1289  err = ni_logan_queue_pop( &p_table->list, frame_info, p_timestamp, threshold, print, p_buffer_pool);
1290  if(NI_LOGAN_RETCODE_SUCCESS != err)
1291  {
1292  ni_log(NI_LOG_TRACE, "%s: error getting timestamp\n", __FUNCTION__);
1293  }
1294 
1295  ni_log(NI_LOG_TRACE, "%s: timestamp=%" PRId64 ", frame_info=%" PRIu64 ", "
1296  "err=%d\n", __FUNCTION__, *p_timestamp, frame_info, err);
1297 
1298  return err;
1299 }
1300 
1302  uint64_t frame_info,
1303  int64_t *p_timestamp,
1304  int32_t threshold,
1305  int32_t print,
1306  ni_logan_queue_buffer_pool_t *p_buffer_pool)
1307 {
1308  return ( ni_logan_queue_pop_threshold(&p_table->list, frame_info, p_timestamp, threshold, print, p_buffer_pool) );
1309 }
1310 
1312  ni_logan_timestamp_table_t *dts_list,
1313  ni_logan_queue_buffer_pool_t *p_buffer_pool)
1314 {
1315  ni_logan_queue_t *p_queue = NULL;
1316  ni_logan_queue_node_t *p = NULL;
1317  time_t now = time(NULL);
1318 
1319  if (!pts_list || !dts_list)
1320  {
1321  return;
1322  }
1323 
1324  // currently, only have dts list.
1325  // if pts list is added back, this should be modified.
1326  p_queue = &dts_list->list;
1327  p = p_queue->p_first;
1328 
1329  while (p)
1330  {
1331  if (now - p->checkout_timestamp <= 30)
1332  {
1333  break;
1334  }
1335  if (p_queue->p_first == p_queue->p_last)
1336  {
1337  ni_logan_buffer_pool_return_buffer(p_queue->p_first, p_buffer_pool);
1338  p = p_queue->p_first = p_queue->p_last = NULL;
1339  } else
1340  {
1341  p_queue->p_first = p->p_next;
1342  p->p_next->p_prev = NULL;
1343  ni_logan_buffer_pool_return_buffer(p, p_buffer_pool);
1344 
1345  p = p_queue->p_first;
1346  }
1347  p_queue->count--;
1348  }
1349 }
1350 
1351 /*!******************************************************************************
1352 * \brief Retrieve timestamp from table based on frameoffset info
1353 *
1354 * \param
1355 *
1356 * \return
1357 *******************************************************************************/
1359  uint64_t frame_offset,
1360  int64_t *p_timestamp,
1361  int32_t threshold,
1362  ni_logan_queue_buffer_pool_t *p_buffer_pool)
1363 {
1365 
1366  if( (!p_table) || (!p_timestamp) || (!p_buffer_pool) )
1367  {
1369  LRETURN;
1370  }
1371 
1372  ni_log(NI_LOG_TRACE, "%s: getting timestamp with frame_offset=%" PRIu64 "\n",
1373  __FUNCTION__, frame_offset);
1374 
1375  err = ni_logan_queue_pop(&p_table->list, frame_offset, p_timestamp, threshold, 0, p_buffer_pool);
1376  if( NI_LOGAN_RETCODE_SUCCESS != err)
1377  {
1378  ni_log(NI_LOG_TRACE, "%s: error getting timestamp\n", __FUNCTION__);
1379  }
1380 
1381  ni_log(NI_LOG_TRACE, "%s: timestamp=%" PRId64 ", frame_offset=%" PRIu64 ", "
1382  "err=%d\n", __FUNCTION__, *p_timestamp, frame_offset, err);
1383 
1384  END:
1385 
1386  return err;
1387 }
1388 
1389 /*!******************************************************************************
1390 * \brief Initialize xcoder queue
1391 *
1392 * \param
1393 *
1394 * \return
1395 *******************************************************************************/
1397  ni_logan_queue_t *p_queue,
1398  const char *name)
1399 {
1400  ni_log(NI_LOG_TRACE, "%s: enter\n", __FUNCTION__);
1401 
1402  if (!p_queue || !name)
1403  {
1405  }
1406  p_queue->name[0] = '\0';
1407  strncat(p_queue->name, name, strlen(name));
1409 
1410  p_queue->p_first = NULL;
1411  p_queue->p_last = NULL;
1412  p_queue->count = 0;
1413 
1414  ni_log(NI_LOG_TRACE, "%s: exit\n", __FUNCTION__);
1415 
1416  return NI_LOGAN_RETCODE_SUCCESS;
1417 }
1418 
1419 /*!******************************************************************************
1420 * \brief Push into xcoder queue
1421 *
1422 * \param
1423 *
1424 * \return
1425 *******************************************************************************/
1427  ni_logan_queue_t *p_queue,
1428  uint64_t frame_info,
1429  int64_t timestamp)
1430 {
1432  ni_logan_queue_node_t *temp = NULL;
1433 
1434  if ( !p_queue )
1435  {
1436  ni_log(NI_LOG_TRACE, "%s: error, null pointer parameters passed\n",
1437  __FUNCTION__);
1439  LRETURN;
1440  }
1441 
1442  temp = ni_logan_buffer_pool_get_queue_buffer(p_buffer_pool);
1443 
1444  if (!temp)
1445  {
1446  ni_log(NI_LOG_TRACE, "%s: error, cannot allocate memory\n", __FUNCTION__);
1448  LRETURN;
1449  }
1450 
1451  temp->timestamp = timestamp;
1452  temp->frame_info = frame_info;
1453 
1454  temp->p_next = NULL;
1455 
1456  if (!p_queue->p_first)
1457  {
1458  p_queue->p_first = p_queue->p_last = temp;
1459  p_queue->p_first->p_prev = NULL;
1460  }
1461  else
1462  {
1463  p_queue->p_last->p_next = temp;
1464  temp->p_prev = p_queue->p_last;
1465  p_queue->p_last = temp;
1466  }
1467 
1468  p_queue->count++;
1469 
1471  {
1472  ni_log(NI_LOG_DEBUG, "%s: queue overflow, remove oldest entry, count=%d\n",
1473  __FUNCTION__, p_queue->count);
1474  // ni_logan_assert(0);
1475  //Remove oldest one
1476  temp = p_queue->p_first->p_next;
1477  // free(p_queue->p_first);
1478  ni_logan_buffer_pool_return_buffer(p_queue->p_first, p_buffer_pool);
1479  p_queue->p_first = temp;
1480  p_queue->p_first->p_prev = NULL;
1481  p_queue->count--;
1482  }
1483 
1484  END:
1485 
1486  return err;
1487 }
1488 
1489 /*!******************************************************************************
1490 * \brief Pop from the xcoder queue
1491 *
1492 * \param
1493 *
1494 * \return
1495 *******************************************************************************/
1497  uint64_t frame_info,
1498  int64_t *p_timestamp,
1499  int32_t threshold,
1500  int32_t print,
1501  ni_logan_queue_buffer_pool_t *p_buffer_pool)
1502 {
1503  ni_logan_queue_node_t *temp;
1504  ni_logan_queue_node_t *temp_prev = NULL;
1505  int32_t found = 0;
1506  int32_t count = 0;
1508 
1509  if (!p_queue || !p_timestamp)
1510  {
1511  ni_log(NI_LOG_TRACE, "%s: error, null pointer parameters passed\n",
1512  __FUNCTION__);
1514  LRETURN;
1515  }
1516 
1517  if ( NULL == p_queue->p_first )
1518  {
1519  ni_log(NI_LOG_TRACE, "%s: queue is empty...\n", __FUNCTION__);
1520  retval = NI_LOGAN_RETCODE_FAILURE;
1521  LRETURN;
1522  }
1523 
1524  if (p_queue->p_first == p_queue->p_last)
1525  {
1527  *p_timestamp = p_queue->p_first->timestamp;
1528  // free(p_queue->p_first);
1529  ni_logan_buffer_pool_return_buffer(p_queue->p_first, p_buffer_pool);
1530 
1531  p_queue->p_first = NULL;
1532  p_queue->p_last = NULL;
1533  p_queue->count--;
1534  ni_logan_assert(p_queue->count == 0);
1535  found = 1;
1536  }
1537  else
1538  {
1539  temp = p_queue->p_first;
1540  while (temp && !found)
1541  {
1542  if (frame_info < temp->frame_info)
1543  {
1544  if (!temp->p_prev)
1545  {
1546  ni_log(NI_LOG_TRACE, "First in ts list, return it\n");
1547  *p_timestamp = temp->timestamp;
1548 
1549  p_queue->p_first = temp->p_next;
1550  temp->p_next->p_prev = NULL;
1551 
1552  ni_logan_buffer_pool_return_buffer(temp, p_buffer_pool);
1553  p_queue->count--;
1554  found = 1;
1555  break;
1556  }
1557 
1558  // retrieve from p_prev and delete p_prev !
1559  *p_timestamp = temp->p_prev->timestamp;
1560  temp = temp->p_prev;
1561  temp_prev = temp->p_prev;
1562 
1563  if (!temp_prev)
1564  {
1565  p_queue->p_first = temp->p_next;
1566  temp->p_next->p_prev = NULL;
1567  }
1568  else
1569  {
1570  temp_prev->p_next = temp->p_next;
1571  if (temp->p_next)
1572  {
1573  temp->p_next->p_prev = temp_prev;
1574  }
1575  else
1576  {
1577  p_queue->p_last = temp_prev;
1578  }
1579  }
1580  //free(temp);
1581  ni_logan_buffer_pool_return_buffer(temp, p_buffer_pool);
1582  p_queue->count--;
1583  found = 1;
1584  break;
1585  }
1586  temp_prev = temp;
1587  temp = temp->p_next;
1588  count++;
1589  }
1590  }
1591 
1592  if (print)
1593  {
1594  ni_log(NI_LOG_TRACE, "%s %s %d iterations ..\n",
1595  __FUNCTION__, p_queue->name, count);
1596  }
1597  if (p_queue->count < 0)
1598  {
1599  ni_log(NI_LOG_TRACE, "%s: error p_queue->count=%d\n",
1600  __FUNCTION__, p_queue->count);
1601  ni_logan_assert(0);
1602  }
1603 
1604  if (!found)
1605  {
1606  retval = NI_LOGAN_RETCODE_FAILURE;
1607  }
1608 
1609  END:
1610 
1611  return retval;
1612 }
1613 
1615  uint64_t frame_info,
1616  int64_t *p_timestamp,
1617  int32_t threshold,
1618  int32_t print,
1619  ni_logan_queue_buffer_pool_t *p_buffer_pool)
1620 {
1621  ni_logan_queue_node_t *temp;
1622  ni_logan_queue_node_t *temp_prev = NULL;
1623  int32_t found = 0;
1624  int32_t count = 0;
1626 
1627  if ( (!p_queue) || (!p_timestamp) )
1628  {
1629  ni_log(NI_LOG_TRACE, "%s: error, null pointer parameters passed\n",
1630  __FUNCTION__);
1632  LRETURN;
1633  }
1634 
1635  if (p_queue->p_first == NULL)
1636  {
1637  ni_log(NI_LOG_TRACE, "%s: queue is empty...\n", __FUNCTION__);
1638  retval = NI_LOGAN_RETCODE_FAILURE;
1639  LRETURN;
1640  }
1641 
1642  if (p_queue->p_first == p_queue->p_last)
1643  {
1645  *p_timestamp = p_queue->p_first->timestamp;
1646  // free(p_queue->p_first);
1647  ni_logan_buffer_pool_return_buffer(p_queue->p_first, p_buffer_pool);
1648  p_queue->p_first = NULL;
1649  p_queue->p_last = NULL;
1650  p_queue->count--;
1651  found = 1;
1652  }
1653  else
1654  {
1655  temp = p_queue->p_first;
1656  while (temp && !found)
1657  {
1658  if (llabs(frame_info - temp->frame_info) <= threshold)
1659  {
1660  *p_timestamp = temp->timestamp;
1661  if (!temp_prev)
1662  {
1663  p_queue->p_first = temp->p_next;
1664  temp->p_next->p_prev = NULL;
1665  }
1666  else
1667  {
1668  temp_prev->p_next = temp->p_next;
1669  if (temp->p_next)
1670  {
1671  temp->p_next->p_prev = temp_prev;
1672  }
1673  else
1674  {
1675  p_queue->p_last = temp_prev;
1676  }
1677  }
1678  // free(temp);
1679  ni_logan_buffer_pool_return_buffer(temp, p_buffer_pool);
1680  p_queue->count--;
1681  found = 1;
1682  break;
1683  }
1684  temp_prev = temp;
1685  temp = temp->p_next;
1686  count++;
1687  }
1688  }
1689  if (print)
1690  {
1691  ni_log(NI_LOG_TRACE, "%s %s %d iterations ..\n",
1692  __FUNCTION__, p_queue->name, count);
1693  }
1694 
1695  if (p_queue->count < 0)
1696  {
1697  ni_log(NI_LOG_TRACE, "%s: error p_queue->count=%d\n",
1698  __FUNCTION__, p_queue->count);
1699  }
1700 
1701  if (!found)
1702  {
1703  retval = NI_LOGAN_RETCODE_FAILURE;
1704  }
1705 
1706  END:
1707 
1708  return retval;
1709 }
1710 
1711 /*!******************************************************************************
1712 * \brief Free xcoder queue
1713 *
1714 * \param
1715 *
1716 * \return
1717 *******************************************************************************/
1719 {
1720  ni_logan_queue_node_t *temp = NULL;
1721  ni_logan_queue_node_t *temp_next;
1722  int32_t left = 0;
1723 
1724  if (!p_queue)
1725  {
1726  return NI_LOGAN_RETCODE_SUCCESS;
1727  }
1728 
1729  ni_log(NI_LOG_TRACE, "Entries before clean up: \n");
1730  ni_logan_queue_print(p_queue);
1731 
1732  temp = p_queue->p_first;
1733  while (temp)
1734  {
1735  temp_next = temp->p_next;
1736  //free(temp);
1737  ni_logan_buffer_pool_return_buffer(temp, p_buffer_pool);
1738  temp = temp_next;
1739  left++;
1740  }
1741  ni_log(NI_LOG_TRACE, "Entries cleaned up at ni_logan_queue_free: %d, count: %d\n",
1742  left, p_queue->count);
1743 
1744  //ni_logan_queue_print(p_queue);
1745 
1746  p_queue->count = 0;
1747 
1748  return NI_LOGAN_RETCODE_SUCCESS;
1749 }
1750 
1751 /*!******************************************************************************
1752 * \brief Print xcoder queue info
1753 *
1754 * \param
1755 *
1756 * \return
1757 *******************************************************************************/
1759 {
1760  ni_logan_queue_node_t *temp = NULL;
1761  struct tm* ltime = NULL;
1762  char buff[20] = { 0 };
1763 
1764  ni_log(NI_LOG_TRACE, "%s: enter\n", __FUNCTION__);
1765 
1766  if (!p_queue)
1767  {
1768  return NI_LOGAN_RETCODE_SUCCESS;
1769  }
1770 
1771  ni_log(NI_LOG_TRACE, "Queue [%s] Count: %d\n", p_queue->name, p_queue->count);
1772 
1773  ni_log(NI_LOG_TRACE, "\nForward:\n");
1774 
1775  temp = p_queue->p_first;
1776 
1777  ni_log(NI_LOG_TRACE, "%s: p_first=%p, p_last=%p, count=%d, temp=%p\n",
1778  __FUNCTION__, p_queue->p_first, p_queue->p_last, p_queue->count, temp);
1779 
1780  while (temp)
1781  {
1782  ltime = localtime(&temp->checkout_timestamp);
1783  if (ltime)
1784  {
1785  strftime(buff, 20, "%Y-%m-%d %H:%M:%S", ltime);
1786  ni_log(NI_LOG_TRACE, " %s [%" PRIu64 ", %" PRIu64 "]", buff, temp->timestamp, temp->frame_info);
1787  }
1788  temp = temp->p_next;
1789  }
1790 
1791  ni_log(NI_LOG_TRACE, "\nBackward:");
1792 
1793  temp = p_queue->p_last;
1794  while (temp)
1795  {
1796  ni_log(NI_LOG_TRACE, " [%" PRIu64 ", %" PRIu64 "]\n", temp->timestamp, temp->frame_info);
1797  temp = temp->p_prev;
1798  }
1799  ni_log(NI_LOG_TRACE, "\n");
1800 
1801  return NI_LOGAN_RETCODE_SUCCESS;
1802 }
1803 
1804 /*!******************************************************************************
1805  * \brief Initialize a fifo buffer
1806  *
1807  * \param[in] number_of_buffers Total number of buffers in this fifo
1808  * \param[in] size The size of every buffer
1809  *
1810  * \return On success return fifo pointer, On failure return NULL
1811  *******************************************************************************/
1813  uint32_t size)
1814 {
1815  ni_logan_fifo_buffer_t *p_fifo = NULL;
1816 
1817  ni_log(NI_LOG_TRACE, "%s: enter\n", __FUNCTION__);
1818 
1819  if ((p_fifo = (ni_logan_fifo_buffer_t *) malloc(sizeof(ni_logan_fifo_buffer_t))) == NULL)
1820  {
1821  ni_log(NI_LOG_ERROR, "Error %d: %s alloc for fifo\n", NI_ERRNO, __FUNCTION__);
1822  return NULL;
1823  }
1824 
1825  //initialise the struct
1826  memset(p_fifo,0,sizeof(ni_logan_fifo_buffer_t));
1827  ni_logan_pthread_mutex_init(&(p_fifo->mutex));
1828  p_fifo->number_of_buffers = number_of_buffers;
1829  p_fifo->buffer_size = size;
1830 
1831  // alloc fifo buffer
1832  p_fifo->buffer = malloc(number_of_buffers * size);
1833  if (p_fifo->buffer == NULL)
1834  {
1835  free(p_fifo);
1836  p_fifo = NULL;
1837  ni_log(NI_LOG_ERROR, "Error %d: %s alloc for fifo buffer\n", NI_ERRNO, __FUNCTION__);
1838  return NULL;
1839  }
1840  memset(p_fifo->buffer,0,(number_of_buffers * size));
1841 
1842  return p_fifo;
1843 }
1844 
1845 /*!******************************************************************************
1846  * \brief Free a fifo
1847  *
1848  * \param[in] p_fifo The pointer of ni_logan_fifo_buffer_t
1849  *
1850  * \return
1851  *******************************************************************************/
1853 {
1854  ni_log(NI_LOG_TRACE, "%s: enter\n", __FUNCTION__);
1855 
1856  if (!p_fifo)
1857  {
1858  ni_log(NI_LOG_TRACE, "%s: null fifo, return\n", __FUNCTION__);
1859  return;
1860  }
1861  ni_logan_pthread_mutex_destroy(&(p_fifo->mutex));
1862 
1863  free(p_fifo->buffer);
1864  p_fifo->buffer = NULL;
1865 
1866  free(p_fifo);
1867 
1868  return;
1869 }
1870 
1871 /*!******************************************************************************
1872  * \brief Check if a fifo is full
1873  *
1874  * \param[in] p_fifo The pointer of ni_logan_fifo_buffer_t
1875  *
1876  * \return 1 is full; 0 is not full
1877  *******************************************************************************/
1879 {
1880  return (p_fifo->number_of_buffers_used == p_fifo->number_of_buffers);
1881 }
1882 
1883 /*!******************************************************************************
1884  * \brief Check if a fifo is empty
1885  *
1886  * \param[in] p_fifo The pointer of ni_logan_fifo_buffer_t
1887  *
1888  * \return 1 is empty; 0 is not empty
1889  *******************************************************************************/
1891 {
1892  return (p_fifo->number_of_buffers_used == 0);
1893 }
1894 
1895 /*!******************************************************************************
1896  * \brief Get free buffer to write in the fifo
1897  *
1898  * \param[in] p_fifo The pointer of ni_logan_fifo_buffer_t
1899  *
1900  * \return On success return the pointer of free buffer,
1901  * On failure return NULL
1902  *******************************************************************************/
1904 {
1905  uint8_t *p_buffer;
1906  ni_log(NI_LOG_TRACE, "%s: enter\n", __FUNCTION__);
1907 
1908  if (NULL == p_fifo || ni_logan_fifo_is_full(p_fifo))
1909  {
1910  ni_log(NI_LOG_TRACE, "Warning pointer is null or fifo is full, %p\n", p_fifo);
1911  return NULL;
1912  }
1913 
1914  ni_logan_pthread_mutex_lock(&(p_fifo->mutex));
1915 
1916  p_buffer = p_fifo->buffer + p_fifo->wndx * p_fifo->buffer_size;
1917  p_fifo->wndx = (p_fifo->wndx + 1) % p_fifo->number_of_buffers;
1918  p_fifo->number_of_buffers_used++;
1919 
1920  ni_logan_pthread_mutex_unlock(&(p_fifo->mutex));
1921  return p_buffer;
1922 }
1923 
1924 /*!******************************************************************************
1925  * \brief Get first filled buffer to read in the fifo
1926  *
1927  * \param[in] p_fifo The pointer of ni_logan_fifo_buffer_t
1928  *
1929  * \return On success return the pointer of filled buffer in fifo,
1930  * On failure return NULL
1931  *******************************************************************************/
1933 {
1934  uint8_t *p_buffer;
1935  ni_log(NI_LOG_TRACE, "%s: enter\n", __FUNCTION__);
1936 
1937  if (NULL == p_fifo || ni_logan_fifo_is_empty(p_fifo))
1938  {
1939  ni_log(NI_LOG_TRACE, "Warning pointer is null or fifo is empty, %p\n", p_fifo);
1940  return NULL;
1941  }
1942 
1943  ni_logan_pthread_mutex_lock(&(p_fifo->mutex));
1944  p_buffer = p_fifo->buffer + p_fifo->rndx * p_fifo->buffer_size;
1945  p_fifo->rndx = (p_fifo->rndx + 1) % p_fifo->number_of_buffers;
1946  p_fifo->number_of_buffers_used--;
1947 
1948  ni_logan_pthread_mutex_unlock(&(p_fifo->mutex));
1949  return p_buffer;
1950 }
1951 
1952 /*!******************************************************************************
1953  * \brief Push back the last read buffer to the fifo
1954  *
1955  * \param[in] p_fifo The pointer of ni_logan_fifo_buffer_t
1956  *
1957  * \return On success return 0,
1958  * On failure return -1
1959  *******************************************************************************/
1961 {
1962  ni_log(NI_LOG_TRACE, "%s: enter\n", __FUNCTION__);
1963 
1964  if (NULL == p_fifo || ni_logan_fifo_is_full(p_fifo))
1965  {
1966  ni_log(NI_LOG_TRACE, "Warning pointer is null or fifo is full, %p\n", p_fifo);
1967  return -1;
1968  }
1969 
1970  ni_logan_pthread_mutex_lock(&(p_fifo->mutex));
1971 
1972  p_fifo->rndx = p_fifo->rndx > 0 ? (p_fifo->rndx - 1) : (p_fifo->number_of_buffers - 1);
1973  p_fifo->number_of_buffers_used++;
1974 
1975  ni_logan_pthread_mutex_unlock(&(p_fifo->mutex));
1976  return 0;
1977 }
1978 
1979 /*!******************************************************************************
1980 * \brief Convert string to boolean
1981 *
1982 * \param
1983 *
1984 * \return
1985 *******************************************************************************/
1986 int32_t ni_logan_atobool(const char *p_str, bool *b_error)
1987 {
1988  if (!strcmp(p_str, "1") ||
1989  !strcmp(p_str, "true") ||
1990  !strcmp(p_str, "yes"))
1991  {
1992  return 1;
1993  }
1994 
1995  if (!strcmp(p_str, "0") ||
1996  !strcmp(p_str, "false") ||
1997  !strcmp(p_str, "no"))
1998  {
1999  return 0;
2000  }
2001 
2002  *b_error = true;
2003  return 0;
2004 }
2005 
2006 /*!******************************************************************************
2007 * \brief Convert string to integer
2008 *
2009 * \param
2010 *
2011 * \return
2012 *******************************************************************************/
2013 int32_t ni_logan_atoi(const char *p_str, bool *b_error)
2014 {
2015  char *end;
2016  int32_t v = strtol(p_str, &end, 0);
2017 
2018  if (end == p_str || *end != '\0')
2019  {
2020  *b_error = true;
2021  }
2022 
2023  return v;
2024 }
2025 
2026 /*!******************************************************************************
2027 * \brief Convert string to floating
2028 *
2029 * \param
2030 *
2031 * \return
2032 *******************************************************************************/
2033 double ni_logan_atof(const char *p_str, bool *b_error)
2034 {
2035  char *end;
2036  double v = strtod(p_str, &end);
2037 
2038  if (end == p_str || *end != '\0')
2039  {
2040  *b_error = true;
2041  }
2042 
2043  return v;
2044 }
2045 
2046 /*!******************************************************************************
2047 * \brief Parse name
2048 *
2049 * \param
2050 *
2051 * \return
2052 *******************************************************************************/
2053 int32_t ni_logan_parse_name(const char *arg, const char *const *names, bool *b_error)
2054 {
2055  int32_t i;
2056  for (i = 0; names[i]; i++)
2057  {
2058  if (!strcmp(arg, names[i]))
2059  {
2060  return i;
2061  }
2062  }
2063 
2064  return ni_logan_atoi(arg, b_error);
2065 }
2066 
2067 /*!*****************************************************************************
2068 * \brief threadpool control
2069 *
2070 * \param[in] params
2071 *
2072 * \return NULL
2073 *
2074 *
2075 ******************************************************************************/
2076 void *thread_routine(void *arg)
2077 {
2078  // ni_logan_pthread create start
2079  threadpool_t *pool = (threadpool_t *)arg;
2080  // Loop the pool fetch the thread to run
2081  ni_log(NI_LOG_TRACE, "thread is starting\n");
2082  for (; ;)
2083  {
2084  //set mutex
2085  ni_logan_pthread_mutex_lock(&pool->pmutex);
2086  pool->idle++;
2087  //pool is empty and pool is not quit then wait add timeout,timeout=1
2088  while (pool->first == NULL && !pool->quit)
2089  {
2090  ni_log(NI_LOG_TRACE, "thread_routine is waiting\n");
2091  ni_logan_pthread_cond_wait(&pool->pcond, &pool->pmutex);
2092  }
2093 
2094  // the pool is not empty
2095  // idle--,start run the task
2096  pool->idle--;
2097  if (pool->first != NULL)
2098  {
2099  ni_task_t *t = pool->first;
2100  pool->first = t->next;
2101  ni_logan_pthread_mutex_unlock(&pool->pmutex);
2102  t->run(t->arg);
2103  free(t);
2104  ni_logan_pthread_mutex_lock(&pool->pmutex);
2105  }
2106  // pool is quit and the pool is empty, break
2107  if (pool->quit && pool->first == NULL)
2108  {
2109  pool->counter--;
2110  if (pool->counter == 0)
2111  {
2112  ni_logan_pthread_cond_signal(&pool->pcond);
2113  }
2114  ni_logan_pthread_mutex_unlock(&pool->pmutex);
2115  break;
2116  }
2117  ni_logan_pthread_mutex_unlock(&pool->pmutex);
2118  }
2119 
2120  ni_log(NI_LOG_TRACE, "thread_routine is exiting\n");
2121  return NULL;
2122 }
2123 
2124 /*!*****************************************************************************
2125 * \brief Init the threadpool
2126 *
2127 * \param[in] pool threadpool address
2128 *
2129 * \return NULL
2130 *
2131 *
2132 ******************************************************************************/
2134 {
2135  ni_logan_pthread_mutex_init(&pool->pmutex);
2136  ni_logan_pthread_cond_init(&pool->pcond, NULL);
2137  pool->first = NULL;
2138  pool->last = NULL;
2139  pool->counter = 0;
2140  pool->idle = 0;
2141  pool->max_threads = MAX_THREADS;
2142  pool->quit = 0;
2143 }
2144 
2145 /*!*****************************************************************************
2146 * \brief add task to threadpool using newThread control it
2147 *
2148 * \param[in] pool threadpool address
2149 * \param[in] run run function
2150 * \param[in] arg run function params
2151 * \param[in] newThread 1: create a new thread.
2152 * 0: do not create a new thread.
2153 *
2154 * \return 0 success
2155 * <0 failed
2156 *
2157 *
2158 ******************************************************************************/
2160  void *(*run)(void *arg),
2161  void *arg,
2162  int newThread)
2163 {
2164  int ret = 0;
2165  // create new task
2166  ni_task_t *newtask = (ni_task_t *)malloc(sizeof(ni_task_t));
2167  if (!newtask)
2168  {
2169  ni_log(NI_LOG_ERROR, "ERROR %d: %s Failed to allocate memory\n",
2170  NI_ERRNO, __FUNCTION__);
2171  return -1;
2172  }
2173  newtask->run = run;
2174  newtask->arg = arg;
2175  newtask->next = NULL;
2176 
2177  // add mutex
2178  ni_logan_pthread_mutex_lock(&pool->pmutex);
2179  // add newtask to the pool
2180  if (pool->first == NULL)
2181  {
2182  pool->first = newtask;
2183  }
2184  else
2185  {
2186  pool->last->next = newtask;
2187  }
2188  pool->last = newtask;
2189 
2190  // If their are idle tasks, wake up the tasks
2191  ni_log(NI_LOG_TRACE, "%s pool->idle %d\n", __FUNCTION__, pool->idle);
2192  if (pool->idle > 0)
2193  {
2194  ni_logan_pthread_cond_signal(&pool->pcond);
2195  }
2196  // no idle tasks,create a new thread,run the thread_routine
2197  else
2198  {
2199  if (pool->counter < pool->max_threads)
2200  {
2201  if (newThread == 1)
2202  {
2203  ni_pthread_t tid;
2204  ni_logan_pthread_create(&tid, NULL, thread_routine, pool);
2205  if (ret)
2206  {
2207  ni_log(NI_LOG_ERROR, "ERROR %d: %s ni_logan_pthread_create failed : %d\n",
2208  NI_ERRNO, __FUNCTION__, ret);
2209  return -1;
2210  }
2211  pool->counter++;
2212  }
2213  }
2214  else
2215  {
2216  while (pool->idle == 0)
2217  {
2218  ni_logan_usleep(1000);
2219  }
2220  ni_logan_pthread_cond_signal(&pool->pcond);
2221  }
2222  }
2223  ni_log(NI_LOG_TRACE, "%s pool->counter %d\n", __FUNCTION__, pool->counter);
2224  ni_logan_pthread_mutex_unlock(&pool->pmutex);
2225  return ret;
2226 }
2227 
2228 
2229 /*!*****************************************************************************
2230 * \brief add task to threadpool
2231 *
2232 * \param[in] pool threadpool address
2233 * \param[in] run run function
2234 * \param[in] arg run function params
2235 *
2236 * \return 0 success
2237 * <0 failed
2238 *
2239 *
2240 ******************************************************************************/
2241 int threadpool_add_task(threadpool_t *pool, void *(*run)(void *arg), void *arg)
2242 {
2243  int ret = 0;
2244  // create new task
2245  ni_task_t *newtask = (ni_task_t *)malloc(sizeof(ni_task_t));
2246  if (!newtask)
2247  {
2248  ni_log(NI_LOG_ERROR, "ERROR %d: %s Failed to allocate memory\n",
2249  NI_ERRNO, __FUNCTION__);
2250  return -1;
2251  }
2252  newtask->run = run;
2253  newtask->arg = arg;
2254  newtask->next = NULL;
2255 
2256  // add mutex
2257  ni_logan_pthread_mutex_lock(&pool->pmutex);
2258  // add newtask to the pool
2259  if (pool->first == NULL)
2260  {
2261  pool->first = newtask;
2262  }
2263  else
2264  {
2265  pool->last->next = newtask;
2266  }
2267  pool->last = newtask;
2268 
2269  // If their are idle tasks, wake up the tasks
2270  ni_log(NI_LOG_TRACE, "%s pool->idle %d\n", __FUNCTION__, pool->idle);
2271  if (pool->idle > 0)
2272  {
2273  ni_logan_pthread_cond_signal(&pool->pcond);
2274  }
2275  // no idle tasks,create a new thread,run the thread_routine
2276  else if (pool->counter < pool->max_threads)
2277  {
2278  ni_pthread_t tid;
2279  ret = ni_logan_pthread_create(&tid, NULL, thread_routine, pool);
2280  if (ret)
2281  {
2282  ni_log(NI_LOG_ERROR, "ERROR %d: %s ni_logan_pthread_create failed : %d\n",
2283  NI_ERRNO, __FUNCTION__, ret);
2284  return -1;
2285  }
2286  pool->counter++;
2287  }
2288  ni_log(NI_LOG_TRACE, "%s pool->counter %d\n", __FUNCTION__, pool->counter);
2289  ni_logan_pthread_mutex_unlock(&pool->pmutex);
2290  return ret;
2291 }
2292 
2293 
2294 /*!*****************************************************************************
2295 * \brief destroy threadpool
2296 *
2297 * \param[in] pool threadpool address
2298 *
2299 * \return NULL
2300 *
2301 *
2302 ******************************************************************************/
2304 {
2305  ni_log(NI_LOG_TRACE, "destroy start!\n");
2306  if (pool->quit)
2307  {
2308  return;
2309  }
2310  // add mutex
2311  ni_logan_pthread_mutex_lock(&pool->pmutex);
2312  pool->quit = 1;
2313 
2314  if (pool->counter > 0)
2315  {
2316  // if has idle task, wake up them
2317  if (pool->idle > 0)
2318  {
2319  ni_log(NI_LOG_TRACE, "destroy broadcast!\n");
2320  // wake up all the idle tasks
2321  ni_logan_pthread_cond_broadcast(&pool->pcond);
2322  }
2323  // if the process is running, wait it finish
2324  while (pool->counter)
2325  {
2326  ni_logan_pthread_cond_wait(&pool->pcond, &pool->pmutex);
2327  }
2328  }
2329  ni_logan_pthread_mutex_unlock(&pool->pmutex);
2330  ni_logan_pthread_mutex_destroy(&pool->pmutex);
2331  ni_logan_pthread_cond_destroy(&pool->pcond);
2332 }
2333 
2334 // Netint HW YUV420p data layout related utility functions
2335 
2336 /*!*****************************************************************************
2337 * \brief Get dimension information of Netint HW YUV420p frame to be sent
2338 * to encoder for encoding. Caller usually retrieves this info and
2339 * uses it in the call to ni_logan_encoder_frame_buffer_alloc for buffer
2340 * allocation.
2341 *
2342 * \param[in] width source YUV frame width
2343 * \param[in] height source YUV frame height
2344 * \param[in] bit_depth_factor 1 for 8 bit, 2 for 10 bit
2345 * \param[in] is_h264 non-0 for H.264 codec, 0 otherwise (H.265)
2346 * \param[out] plane_stride size (in bytes) of each plane width
2347 * \param[out] plane_height size of each plane height
2348 *
2349 * \return Y/Cb/Cr stride and height info
2350 *
2351 ******************************************************************************/
2352 void ni_logan_get_hw_yuv420p_dim(int width, int height, int bit_depth_factor,
2353  int is_h264,
2354  int plane_stride[NI_LOGAN_MAX_NUM_DATA_POINTERS],
2355  int plane_height[NI_LOGAN_MAX_NUM_DATA_POINTERS])
2356 {
2357  // width (in pixels) is multiples of 32
2358  plane_stride[0] = ((width + 31) / 32) * 32;
2359  if (plane_stride[0] < NI_LOGAN_MIN_WIDTH)
2360  {
2361  plane_stride[0] = NI_LOGAN_MIN_WIDTH;
2362  }
2363  plane_stride[0] *= bit_depth_factor;
2364  plane_stride[1] = plane_stride[2] = plane_stride[0] / 2;
2365 
2366  // height (in lines) is multiples of 8 for H.265, 16 for H.264
2367  plane_height[0] = ((height + 7) / 8) * 8;
2368  if (is_h264)
2369  {
2370  plane_height[0] = ((height + 15) / 16) * 16;
2371  }
2372  if (plane_height[0] < NI_LOGAN_MIN_HEIGHT)
2373  {
2374  plane_height[0] = NI_LOGAN_MIN_HEIGHT;
2375  }
2376  plane_height[1] = plane_height[2] = plane_height[0] / 2;
2377 }
2378 
2379 /*!*****************************************************************************
2380 * \brief Copy YUV data to Netint HW YUV420p frame layout to be sent
2381 * to encoder for encoding. Data buffer (dst) is usually allocated by
2382 * ni_logan_encoder_frame_buffer_alloc.
2383 *
2384 * \param[out] p_dst pointers of Y/Cb/Cr to which data is copied
2385 * \param[in] p_src pointers of Y/Cb/Cr from which data is copied
2386 * \param[in] width source YUV frame width
2387 * \param[in] height source YUV frame height
2388 * \param[in] bit_depth_factor 1 for 8 bit, 2 for 10 bit
2389 * \param[in] dst_stride size (in bytes) of each plane width in destination
2390 * \param[in] dst_height size of each plane height in destination
2391 * \param[in] src_stride size (in bytes) of each plane width in source
2392 * \param[in] src_height size of each plane height in source
2393 *
2394 * \return Y/Cb/Cr data
2395 *
2396 ******************************************************************************/
2398  uint8_t *p_src[NI_LOGAN_MAX_NUM_DATA_POINTERS],
2399  int frame_width, int frame_height, int bit_depth_factor,
2400  int dst_stride[NI_LOGAN_MAX_NUM_DATA_POINTERS],
2401  int dst_height[NI_LOGAN_MAX_NUM_DATA_POINTERS],
2402  int src_stride[NI_LOGAN_MAX_NUM_DATA_POINTERS],
2403  int src_height[NI_LOGAN_MAX_NUM_DATA_POINTERS])
2404 {
2405  // return to avoid self copy
2406  if (p_dst[0] == p_src[0] && p_dst[1] == p_src[1] && p_dst[2] == p_src[2])
2407  {
2408  ni_log(NI_LOG_TRACE, "%s: src and dst identical, return\n", __FUNCTION__);
2409  return;
2410  }
2411 
2412  ni_log(NI_LOG_TRACE, "%s dst_stride %d/%d/%d src_stride %d/%d/%d dst_height "
2413  "%d/%d/%d src_height %d/%d/%d\n", __FUNCTION__,
2414  dst_stride[0], dst_stride[1], dst_stride[2],
2415  src_stride[0], src_stride[1], src_stride[2],
2416  dst_height[0], dst_height[1], dst_height[2],
2417  src_height[0], src_height[1], src_height[2]);
2418 
2419  // width padding length in pixels and bytes, if needed
2420  int pad_len = 0, pad_len_bytes;
2421  int i;
2422 
2423  for (i = 0; i < NI_LOGAN_MAX_NUM_DATA_POINTERS; i++)
2424  {
2425  int height = src_height[i] < dst_height[i] ? src_height[i] : dst_height[i];
2426  uint8_t *dst = p_dst[i];
2427  const uint8_t *src = (const uint8_t *)p_src[i];
2428 
2429  if (0 == i) // Y
2430  {
2431  pad_len = dst_stride[i] / bit_depth_factor - frame_width;
2432  }
2433  else if (1 == i)
2434  {
2435  // U/V share the same padding length; Y padding could be odd value
2436  // so make it even
2437  pad_len = ((pad_len + 1) / 2) * 2;
2438  }
2439 
2440  pad_len_bytes = (i == 0 ? pad_len * bit_depth_factor :
2441  pad_len * bit_depth_factor / 2);
2442  ni_log(NI_LOG_TRACE, "%s plane %d stride padding: %d pixel (%d bytes), "
2443  "copy height: %d.\n", __FUNCTION__, i, pad_len, pad_len_bytes, height);
2444 
2445  if(pad_len || src_stride[i] != dst_stride[i])
2446  {
2447  for (; height > 0; height--)
2448  {
2449  memcpy(dst, src, (src_stride[i] < dst_stride[i] ?
2450  src_stride[i] : dst_stride[i]));
2451  dst += dst_stride[i];
2452 
2453  // dst is now at the line end
2454  // repeat last pixel
2455  if (2 == bit_depth_factor)
2456  {
2457  // for 10 bit it's 2 bytes
2458  int j;
2459  uint8_t *tmp_dst = dst - pad_len_bytes;
2460  for (j = 0; j < pad_len_bytes / 2; j++)
2461  {
2462  memcpy(tmp_dst, dst - pad_len_bytes - 2, 2);
2463  tmp_dst += 2;
2464  }
2465  }
2466  else
2467  {
2468  memset(dst - pad_len_bytes, *(dst - pad_len_bytes - 1),
2469  pad_len_bytes);
2470  }
2471  src += src_stride[i];
2472  }
2473  }
2474  else
2475  {
2476  int copy_stride = dst_stride[i];
2477  memcpy(dst, src, copy_stride * height);
2478  dst += copy_stride * height;
2479  }
2480 
2481  // height padding/cropping if needed
2482  int padding_height = dst_height[i] - src_height[i];
2483  if (padding_height > 0)
2484  {
2485  ni_log(NI_LOG_TRACE, "%s plane %d padding height: %d\n",
2486  __FUNCTION__, i, padding_height);
2487  src = dst - dst_stride[i];
2488  for (; padding_height > 0; padding_height--)
2489  {
2490  memcpy(dst, src, dst_stride[i]);
2491  dst += dst_stride[i];
2492  }
2493  }
2494  }
2495 }
2496 
2497 // NAL operations
2498 
2499 /*!*****************************************************************************
2500 * \brief Insert emulation prevention byte(s) as needed into the data buffer
2501 *
2502 * \param buf data buffer to be worked on - new byte(s) will be inserted
2503 * size number of bytes starting from buf to check
2504 *
2505 * \return the number of emulation prevention bytes inserted into buf, 0 if
2506 * none.
2507 *
2508 * Note: caller *MUST* ensure for newly inserted bytes, buf has enough free
2509 * space starting from buf + size
2510 ******************************************************************************/
2511 int ni_logan_insert_emulation_prevent_bytes(uint8_t *buf, int size)
2512 {
2513  int insert_bytes = 0;
2514  uint8_t *buf_curr = buf;
2515  uint8_t *buf_end = buf + size - 1;
2516  int zeros = 0, insert_ep3_byte = 0;
2517 
2518  ni_log(NI_LOG_TRACE, "%s: enter\n", __FUNCTION__);
2519 
2520  for (; buf_curr <= buf_end; buf_curr++)
2521  {
2522  if (zeros == 2)
2523  {
2524  insert_ep3_byte = (*buf_curr <= 3);
2525  if (insert_ep3_byte)
2526  {
2527  // move bytes from curr to end 1 position to make space for ep3
2528  memmove(buf_curr + 1, buf_curr, buf_end - buf_curr + 1);
2529  *buf_curr = 0x3;
2530  buf_curr++;
2531  buf_end++;
2532  insert_bytes++;
2533  }
2534 
2535  zeros = 0;
2536  }
2537 
2538  if (! *buf_curr)
2539  {
2540  zeros++;
2541  }
2542  else
2543  {
2544  zeros = 0;
2545  }
2546  }
2547 
2548  ni_log(NI_LOG_TRACE, "%s: %d, exit\n", __FUNCTION__, insert_bytes);
2549  return insert_bytes;
2550 }
2551 
2552 /*!*****************************************************************************
2553  * \brief Remove emulation prevention byte(s) as needed from the data buffer
2554  *
2555  * \param buf data buffer to be worked on - emu prevent byte(s) will be
2556  * removed from.
2557  * size number of bytes starting from buf to check
2558  *
2559  * \return the number of emulation prevention bytes removed from buf, 0 if
2560  * none.
2561  *
2562  * Note: buf will be modified if emu prevent byte(s) found and removed.
2563  ******************************************************************************/
2564 LIB_API int ni_logan_remove_emulation_prevent_bytes(uint8_t *buf, int size)
2565 {
2566  int remove_bytes = 0;
2567  uint8_t *buf_curr = buf;
2568  uint8_t *buf_end = buf + size - 1;
2569  int zeros = 0, remove_ep3_byte;
2570 
2571  ni_log(NI_LOG_TRACE, "%s: enter\n", __func__);
2572 
2573  for (; buf_curr < buf_end; buf_curr++)
2574  {
2575  if (zeros == 2)
2576  {
2577  remove_ep3_byte = (*buf_curr == 0x03 && *(buf_curr + 1) <= 3);
2578  if (remove_ep3_byte)
2579  {
2580  // move bytes after curr to end, 1 position forward to overwrite ep3
2581  memmove(buf_curr, buf_curr + 1, buf_end - buf_curr);
2582 
2583  // buf_curr unchanged
2584  buf_end--;
2585  remove_bytes++;
2586  }
2587 
2588  zeros = 0;
2589  }
2590 
2591  if (!*buf_curr)
2592  {
2593  zeros++;
2594  } else
2595  {
2596  zeros = 0;
2597  }
2598  }
2599 
2600  ni_log(NI_LOG_TRACE, "%s: %d, exit\n", __func__, remove_bytes);
2601  return remove_bytes;
2602 }
2603 
2604 /*!******************************************************************************
2605 * \brief overwrite the 32 bits of integer value at bit position pos
2606 *
2607 * \param buf data buffer to be worked on
2608 * pos the position to be modified
2609 * value The value that needs to be modified to
2610 *
2611 * \return void
2612 *
2613 * Note: caller *MUST* ensure that the pos and value won't go beyond the memory
2614 * boundary of data. otherwise memory corruption would occur.
2615 ******************************************************************************/
2616 void ni_logan_overwrite_specified_pos(uint8_t *buf, int pos, int value)
2617 {
2618  int pos_byte = (pos/8);
2619  int pos_in_byte = pos%8;
2620  int remaining_bytes_in_current_byte = 8 - pos_in_byte;
2621 
2622  if (pos_in_byte == 0) // at beginning of the byte
2623  {
2624  buf[pos_byte] = (uint8_t)(value >> 24);
2625  buf[pos_byte+1] = (uint8_t)(value >> 16);
2626  buf[pos_byte+2] = (uint8_t)(value >> 8);
2627  buf[pos_byte+3] = (uint8_t)(value);
2628  }
2629  else
2630  {
2631  buf[pos_byte] = buf[pos_byte] + (uint8_t)(value >> (32-remaining_bytes_in_current_byte));
2632  buf[pos_byte+1] = (uint8_t)(value >> (32-remaining_bytes_in_current_byte-8));
2633  buf[pos_byte+2] = (uint8_t)(value >> (32-remaining_bytes_in_current_byte-16));
2634  buf[pos_byte+3] = (uint8_t)(value >> (32-remaining_bytes_in_current_byte-24));
2635  buf[pos_byte+4] = buf[pos_byte+4] + ((uint8_t)(value << remaining_bytes_in_current_byte));
2636  }
2637 }
2638 
2639 #ifdef MEASURE_LATENCY
2640 /*!******************************************************************************
2641 * \brief Create a latency measurement queue object of a given capacity
2642 *
2643 * \param capacity maximum size of queue
2644 *
2645 * \return ni_logan_lat_meas_q_t latency measurement queue structure
2646 *
2647 *******************************************************************************/
2648 ni_logan_lat_meas_q_t * ni_logan_lat_meas_q_create(unsigned capacity)
2649 {
2651  if (!queue)
2652  {
2653  ni_log(NI_LOG_ERROR, "ERROR %d: Failed to allocate memory for lat_meas-queue queue",
2654  NI_ERRNO);
2655  return NULL;
2656  }
2657  queue->capacity = capacity;
2658  queue->front = queue->size = 0;
2659  queue->rear = capacity - 1;
2660  queue->array = (ni_logan_lat_meas_q_entry_t*) malloc(queue->capacity * sizeof(ni_logan_lat_meas_q_entry_t));
2661  if(!queue->array)
2662  {
2663  ni_log(NI_LOG_ERROR, "ERROR %d: Failed to allocate memory for lat_meas_queue queue->array",
2664  NI_ERRNO);
2665  return NULL;
2666  }
2667  return queue;
2668 }
2669 
2670 /*!******************************************************************************
2671 * \brief Push an item onto the queue
2672 *
2673 * \param queue pointer to latency queue
2674 * \param item ni_logan_lat_meas_q_entry_t item to push onto the queue
2675 *
2676 * \return void 1 if success, NULL if failed
2677 *
2678 *******************************************************************************/
2679 void * ni_logan_lat_meas_q_enqueue(ni_logan_lat_meas_q_t* queue, ni_logan_lat_meas_q_entry_t item)
2680 {
2681  if (queue->size == queue->capacity)
2682  {
2683  return NULL;
2684  }
2685  queue->rear = (queue->rear + 1) % queue->capacity;
2686  queue->array[queue->rear] = item;
2687  queue->size = queue->size + 1;
2688  return (void *) 1;
2689 }
2690 
2691 /*!******************************************************************************
2692 * \brief Pop an item from the queue
2693 *
2694 * \param queue pointer to latency queue
2695 *
2696 * \return void pointer to popped item
2697 *
2698 *******************************************************************************/
2699 void * ni_logan_lat_meas_q_dequeue(ni_logan_lat_meas_q_t* queue)
2700 {
2701  ni_logan_lat_meas_q_entry_t *dequeue_item;
2702  if (queue->size == 0)
2703  {
2704  return NULL;
2705  }
2706  dequeue_item = &queue->array[queue->front];
2707  queue->front = (queue->front + 1)%queue->capacity;
2708  queue->size = queue->size - 1;
2709  return dequeue_item;
2710 }
2711 
2712 /*!******************************************************************************
2713 * \brief Get a pointer to rear of queue
2714 *
2715 * \param queue pointer to latency queue
2716 *
2717 * \return void pointer to rear of queue
2718 *
2719 *******************************************************************************/
2720 void * ni_logan_lat_meas_q_rear(ni_logan_lat_meas_q_t* queue)
2721 {
2722  return queue->size == 0 ? NULL : &queue->array[queue->rear];
2723 }
2724 
2725 /*!******************************************************************************
2726 * \brief Get a pointer to front of queue
2727 *
2728 * \param queue pointer to latency queue
2729 *
2730 * \return void pointer to front of queue
2731 *
2732 *******************************************************************************/
2733 void * ni_logan_lat_meas_q_front(ni_logan_lat_meas_q_t* queue)
2734 {
2735  return queue->size == 0 ? NULL : &queue->array[queue->front];
2736 }
2737 
2738 /*!******************************************************************************
2739 * \brief Add a new entry to latency queue
2740 *
2741 * \param dec_frame_time_q pointer to latency queue
2742 * \param abs_time frame start time for latency comparison
2743 * \param ts_time reference frame timestamp time
2744 *
2745 * \return void 1 if success, NULL if failed
2746 *
2747 *******************************************************************************/
2748 void * ni_logan_lat_meas_q_add_entry(ni_logan_lat_meas_q_t *dec_frame_time_q,
2749  uint64_t abs_time,
2750  int64_t ts_time)
2751 {
2752  // ni_log(NI_LOG_INFO, "ni_logan_lat_meas_q_add_entry abs_time=%lu ts_time=%ld\n");
2753  ni_logan_lat_meas_q_entry_t entry = {.abs_timenano = abs_time, .ts_time = ts_time};
2754  return ni_logan_lat_meas_q_enqueue(dec_frame_time_q, entry);
2755 }
2756 
2757 /*!******************************************************************************
2758 * \brief Check latency of a frame referenced by its timestamp
2759 *
2760 * \param dec_frame_time_q pointer to latency queue
2761 * \param abs_time frame end time for latency comparison
2762 * \param ts_time reference frame timestamp time
2763 *
2764 * \return uint64_t value of latency if suceeded, -1 if failed
2765 *
2766 *******************************************************************************/
2767 uint64_t ni_logan_lat_meas_q_check_latency(ni_logan_lat_meas_q_t *dec_frame_time_q,
2768  uint64_t abs_time,
2769  int64_t ts_time)
2770 {
2771  // ni_log(NI_LOG_INFO, "ni_logan_lat_meas_q_check_latency abs_time=%lu ts_time=%ld\n");
2772  uint32_t dequeue_count = 0;
2773  ni_logan_lat_meas_q_entry_t * entry = ni_logan_lat_meas_q_front(dec_frame_time_q);
2774 
2775  if (entry == NULL)
2776  {
2777  return -1;
2778  }
2779 
2780  if (entry->ts_time == ts_time)
2781  {
2782  ni_logan_lat_meas_q_dequeue(dec_frame_time_q);
2783  dequeue_count++;
2784  }
2785  else
2786  {
2787  while (entry->ts_time < ts_time)
2788  {
2789  // queue miss, perhaps frame was not decoded properly or TS was offset
2790  entry = ni_logan_lat_meas_q_dequeue(dec_frame_time_q);
2791  dequeue_count++;
2792  if (entry == NULL)
2793  {
2794  return -1;
2795  }
2796  }
2797  }
2798  // ni_log(NI_LOG_INFO, "DQ_CNT:%d,QD:%d,", dequeue_count, dec_frame_time_q->size);
2799 
2800  if (entry == NULL)
2801  {
2802  // queue overrun
2803  return -1;
2804  }
2805  else if (entry->ts_time > ts_time)
2806  {
2807  // queue miss, perhaps frame was not enqueued properly or TS was offset
2808  return -1;
2809  }
2810  else if (entry->ts_time == ts_time)
2811  {
2812  // queue item is perfectly matched, calculate latency
2813  return (abs_time - entry->abs_timenano);
2814  }
2815 }
2816 #endif
ni_logan_retcode_t
@ NI_LOGAN_RETCODE_INVALID_PARAM
@ NI_LOGAN_RETCODE_ERROR_MEM_ALOC
@ NI_LOGAN_RETCODE_SUCCESS
@ NI_LOGAN_RETCODE_FAILURE
#define END
#define NI_LOGAN_MAX_NUM_DATA_POINTERS
#define ni_logan_assert(expression)
#define NI_ERRNO
#define NI_LOGAN_MEM_PAGE_ALIGNMENT
#define LRETURN
#define NI_LOGAN_FW_META_DATA_SZ
#define NI_LOGAN_MIN_WIDTH
#define NI_LOGAN_MAX_SEI_DATA
#define NI_LOGAN_MIN_HEIGHT
void ni_log(ni_log_level_t level, const char *fmt,...)
print log message using ni_log_callback
Definition: ni_log_logan.c:120
@ NI_LOG_DEBUG
Definition: ni_log_logan.h:66
@ NI_LOG_TRACE
Definition: ni_log_logan.h:67
@ NI_LOG_ERROR
Definition: ni_log_logan.h:64
@ NI_LOG_INFO
Definition: ni_log_logan.h:65
Definitions related to working with NI T-408 over NVME interface.
ni_logan_buf_t * ni_logan_buf_pool_expand(ni_logan_buf_pool_t *pool)
ni_logan_buf_t * ni_logan_buf_pool_allocate_buffer(ni_logan_buf_pool_t *p_buffer_pool, int buffer_size)
allocate a memory buffer and place it in the pool
uint8_t * ni_logan_fifo_generic_read(ni_logan_fifo_buffer_t *p_fifo)
Get first filled buffer to read in the fifo.
uint32_t ni_logan_round_up(uint32_t number_to_round, uint32_t multiple)
ni_logan_retcode_t ni_logan_timestamp_get(ni_logan_timestamp_table_t *p_table, uint64_t frame_info, int64_t *p_timestamp, int32_t threshold, int32_t print, ni_logan_queue_buffer_pool_t *p_buffer_pool)
Retrieve timestamp from table based on frameoffset info.
uint8_t * ni_logan_fifo_generic_write(ni_logan_fifo_buffer_t *p_fifo)
Get free buffer to write in the fifo.
int threadpool_auto_add_task_thread(threadpool_t *pool, void *(*run)(void *arg), void *arg, int newThread)
add task to threadpool using newThread control it
ni_logan_queue_node_t * ni_logan_buffer_pool_expand(ni_logan_queue_buffer_pool_t *pool)
ni_logan_retcode_t ni_logan_queue_push(ni_logan_queue_buffer_pool_t *p_buffer_pool, ni_logan_queue_t *p_queue, uint64_t frame_info, int64_t timestamp)
Push into xcoder queue.
void ni_logan_timestamp_scan_cleanup(ni_logan_timestamp_table_t *pts_list, ni_logan_timestamp_table_t *dts_list, ni_logan_queue_buffer_pool_t *p_buffer_pool)
Timestamp queue clean up.
int32_t ni_logan_dec_fme_buffer_pool_initialize(ni_logan_session_context_t *p_ctx, int32_t number_of_buffers, int width, int height, int height_align, int factor)
decoder frame buffer pool init & free
int32_t ni_logan_posix_memalign(void **pp_memptr, size_t alignment, size_t size)
ni_logan_retcode_t ni_logan_queue_free(ni_logan_queue_t *p_queue, ni_logan_queue_buffer_pool_t *p_buffer_pool)
Free xcoder queue.
int32_t ni_logan_atobool(const char *p_str, bool *b_error)
Convert string to boolean.
ni_logan_retcode_t ni_logan_queue_pop(ni_logan_queue_t *p_queue, uint64_t frame_info, int64_t *p_timestamp, int32_t threshold, int32_t print, ni_logan_queue_buffer_pool_t *p_buffer_pool)
Pop from the xcoder queue.
ni_logan_retcode_t ni_logan_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...
void ni_logan_copy_hw_yuv420p(uint8_t *p_dst[NI_LOGAN_MAX_NUM_DATA_POINTERS], uint8_t *p_src[NI_LOGAN_MAX_NUM_DATA_POINTERS], int frame_width, int frame_height, int bit_depth_factor, int dst_stride[NI_LOGAN_MAX_NUM_DATA_POINTERS], int dst_height[NI_LOGAN_MAX_NUM_DATA_POINTERS], int src_stride[NI_LOGAN_MAX_NUM_DATA_POINTERS], int src_height[NI_LOGAN_MAX_NUM_DATA_POINTERS])
Copy YUV data to Netint HW YUV420p frame layout to be sent to encoder for encoding....
int ni_logan_fifo_return_read(ni_logan_fifo_buffer_t *p_fifo)
Push back the last read buffer to the fifo.
void ni_logan_buffer_pool_free(ni_logan_queue_buffer_pool_t *p_buffer_pool)
free buffer memory pool
ni_logan_queue_node_t * ni_logan_buffer_pool_allocate_buffer(ni_logan_queue_buffer_pool_t *p_buffer_pool)
int32_t ni_logan_parse_name(const char *arg, const char *const *names, bool *b_error)
Parse name.
ni_logan_retcode_t ni_logan_timestamp_done(ni_logan_timestamp_table_t *p_table, ni_logan_queue_buffer_pool_t *p_buffer_pool)
Clean up timestamp handling.
int ni_logan_fifo_is_empty(ni_logan_fifo_buffer_t *p_fifo)
Check if a fifo is empty.
uint64_t ni_logan_gettime_ns(void)
Definition: ni_util_logan.c:81
void ni_logan_get_hw_yuv420p_dim(int width, int height, int bit_depth_factor, int is_h264, int plane_stride[NI_LOGAN_MAX_NUM_DATA_POINTERS], int plane_height[NI_LOGAN_MAX_NUM_DATA_POINTERS])
Get dimension information of Netint HW YUV420p frame to be sent to encoder for encoding....
ni_logan_queue_node_t * ni_logan_buffer_pool_get_queue_buffer(ni_logan_queue_buffer_pool_t *p_buffer_pool)
ni_logan_retcode_t ni_logan_timestamp_register(ni_logan_queue_buffer_pool_t *p_buffer_pool, ni_logan_timestamp_table_t *p_table, int64_t timestamp, uint64_t data_info)
Register timestamp in timestamp/frameoffset table.
void ni_logan_usleep(int64_t usec)
void ni_logan_buffer_pool_return_buffer(ni_logan_queue_node_t *buf, ni_logan_queue_buffer_pool_t *p_buffer_pool)
ni_logan_retcode_t ni_logan_timestamp_init(ni_logan_session_context_t *p_ctx, ni_logan_timestamp_table_t **pp_table, const char *name)
Initialize timestamp handling.
int ni_logan_fifo_is_full(ni_logan_fifo_buffer_t *p_fifo)
Check if a fifo is full.
ni_logan_retcode_t ni_logan_queue_pop_threshold(ni_logan_queue_t *p_queue, uint64_t frame_info, int64_t *p_timestamp, int32_t threshold, int32_t print, ni_logan_queue_buffer_pool_t *p_buffer_pool)
Pop from the xcoder queue with respect to threshold.
void ni_logan_buf_pool_return_buffer(ni_logan_buf_t *buf, ni_logan_buf_pool_t *p_buffer_pool)
return a used memory buffer to the pool
ni_logan_retcode_t ni_logan_queue_print(ni_logan_queue_t *p_queue)
Print xcoder queue info.
void ni_logan_dec_fme_buffer_pool_free(ni_logan_buf_pool_t *p_buffer_pool)
free decoder frame buffer pool
int ni_logan_insert_emulation_prevent_bytes(uint8_t *buf, int size)
Insert emulation prevention byte(s) as needed into the data buffer.
int32_t ni_logan_atoi(const char *p_str, bool *b_error)
Convert string to integer.
LIB_API int ni_logan_remove_emulation_prevent_bytes(uint8_t *buf, int size)
Remove emulation prevention byte(s) as needed from the data buffer.
void ni_logan_overwrite_specified_pos(uint8_t *buf, int pos, int value)
overwrite the 32 bits of integer value at bit position pos
ni_logan_fifo_buffer_t * ni_logan_fifo_initialize(uint32_t number_of_buffers, uint32_t size)
Initialize a fifo buffer.
int32_t ni_logan_gettimeofday(struct timeval *p_tp, void *p_tzp)
Definition: ni_util_logan.c:56
ni_logan_retcode_t ni_logan_queue_init(ni_logan_session_context_t *p_ctx, ni_logan_queue_t *p_queue, const char *name)
Initialize xcoder queue.
void ni_logan_fifo_free(ni_logan_fifo_buffer_t *p_fifo)
Free a fifo.
void threadpool_destroy(threadpool_t *pool)
destroy threadpool
void * thread_routine(void *arg)
threadpool control
int32_t ni_logan_buffer_pool_initialize(ni_logan_session_context_t *p_ctx, int32_t number_of_buffers)
ni_logan_buf_t * ni_logan_buf_pool_get_buffer(ni_logan_buf_pool_t *p_buffer_pool)
get a free memory buffer from the pool
ni_logan_retcode_t ni_logan_timestamp_get_v2(ni_logan_timestamp_table_t *p_table, uint64_t frame_offset, int64_t *p_timestamp, int32_t threshold, ni_logan_queue_buffer_pool_t *p_buffer_pool)
Retrieve timestamp from table based on frameoffset info.
void threadpool_init(threadpool_t *pool)
Init the threadpool.
double ni_logan_atof(const char *p_str, bool *b_error)
Convert string to floating.
int threadpool_add_task(threadpool_t *pool, void *(*run)(void *arg), void *arg)
add task to threadpool
ni_logan_retcode_t ni_logan_timestamp_get_with_threshold(ni_logan_timestamp_table_t *p_table, uint64_t frame_info, int64_t *p_timestamp, int32_t threshold, int32_t print, ni_logan_queue_buffer_pool_t *p_buffer_pool)
Retrieve timestamp from table based on frame offset info with respect to threshold.
Exported utility routines definition.
#define LOGAN_BUFFER_POOL_SZ_PER_CONTEXT
Definition: ni_util_logan.h:63
#define MAX_THREADS
Definition: ni_util_logan.h:78
#define NI_LOGAN_NVME_PREFIX
Definition: ni_util_logan.h:54
#define NI_LOGAN_DEC_FRAME_BUF_POOL_SIZE_EXPAND
Definition: ni_util_logan.h:72
#define LOGAN_XCODER_MAX_NUM_QUEUE_ENTRIES
Definition: ni_util_logan.h:61
ni_pthread_mutex_t mutex
ni_logan_buf_t * p_free_head
ni_logan_buf_t * p_free_tail
ni_logan_buf_t * p_used_head
ni_logan_buf_t * p_used_tail
struct _ni_logan_buf_pool_t * pool
struct _ni_logan_buf_t * p_next
struct _ni_logan_buf_t * p_previous_buffer
struct _ni_logan_buf_t * p_prev
struct _ni_logan_buf_t * p_next_buffer
int64_t ts_time
uint64_t abs_timenano
ni_logan_lat_meas_q_entry_t * array
ni_logan_queue_node_t * p_used_head
ni_logan_queue_node_t * p_used_tail
ni_logan_queue_node_t * p_free_tail
ni_logan_queue_node_t * p_free_head
struct _ni_logan_queue_node_t * p_previous_buffer
struct _ni_logan_queue_node_t * p_next_buffer
struct _ni_logan_queue_node_t * p_next
struct _ni_logan_queue_node_t * p_prev
ni_logan_queue_node_t * p_last
Definition: ni_util_logan.h:91
ni_logan_queue_node_t * p_first
Definition: ni_util_logan.h:90
ni_logan_queue_buffer_pool_t * buffer_pool
ni_logan_buf_pool_t * dec_fme_buf_pool
void *(* run)(void *args)
void * arg
struct ni_task * next
ni_pthread_cond_t pcond
ni_pthread_mutex_t pmutex
ni_task_t * last
ni_task_t * first