libxcoder  3.5.4
ni_device_test_logan.c
Go to the documentation of this file.
1 /*!****************************************************************************
2 *
3 * Copyright (C) 2018 NETINT Technologies.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted.
7 *
8 *******************************************************************************/
9 
10 /*!*****************************************************************************
11 * \file ni_device_test_logan.c
12 *
13 * \brief Example code on how to programmatically work with NI T-408 using
14 * libxcoder API
15 *
16 *******************************************************************************/
17 
18 #include <stdio.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <stdint.h>
22 
23 #ifdef _WIN32
24 #include <windows.h>
25 #include <io.h>
26 #include "ni_getopt_logan.h"
27 #elif defined(__linux__) || defined(__APPLE__)
28 #define _POSIX_C_SOURCE 200809L
29 #include <getopt.h>
30 #include <unistd.h>
31 #include <sys/ioctl.h>
32 #include <sys/mman.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <sys/time.h>
36 #include <time.h>
37 #endif
38 
39 #include <fcntl.h>
40 #include <errno.h>
41 #include "ni_device_api_logan.h"
42 #include "ni_rsrc_api_logan.h"
43 #include "ni_util_logan.h"
44 #include "ni_device_test_logan.h"
45 #include "ni_bitstream_logan.h"
46 
48 {
50  const char *txt;
52 
53 static const ni_logan_err_rc_txt_entry_t ni_logan_err_rc_description[] =
54 {
55  NI_LOGAN_RETCODE_SUCCESS, "SUCCESS",
56  NI_LOGAN_RETCODE_FAILURE, "FAILURE",
57  NI_LOGAN_RETCODE_INVALID_PARAM, "INVALID_PARAM",
58  NI_LOGAN_RETCODE_ERROR_MEM_ALOC, "ERROR_MEM_ALOC",
59  NI_LOGAN_RETCODE_ERROR_NVME_CMD_FAILED, "ERROR_NVME_CMD_FAILED",
60  NI_LOGAN_RETCODE_ERROR_INVALID_SESSION, "ERROR_INVALID_SESSION",
61  NI_LOGAN_RETCODE_ERROR_RESOURCE_UNAVAILABLE, "ERROR_RESOURCE_UNAVAILABLE",
62  NI_LOGAN_RETCODE_PARAM_INVALID_NAME, "PARAM_INVALID_NAME",
63  NI_LOGAN_RETCODE_PARAM_INVALID_VALUE, "PARAM_INVALID_VALUE",
64  NI_LOGAN_RETCODE_PARAM_ERROR_FRATE, "PARAM_ERROR_FRATE",
65  NI_LOGAN_RETCODE_PARAM_ERROR_BRATE, "PARAM_ERROR_BRATE",
66  NI_LOGAN_RETCODE_PARAM_ERROR_TRATE, "PARAM_ERROR_TRATE",
67  NI_LOGAN_RETCODE_PARAM_ERROR_RC_INIT_DELAY, "PARAM_ERROR_RC_INIT_DELAY",
68  NI_LOGAN_RETCODE_PARAM_ERROR_INTRA_PERIOD, "PARAM_ERROR_INTRA_PERIOD",
69  NI_LOGAN_RETCODE_PARAM_ERROR_INTRA_QP, "PARAM_ERROR_INTRA_QP",
70  NI_LOGAN_RETCODE_PARAM_ERROR_GOP_PRESET, "PARAM_ERROR_GOP_PRESET",
71  NI_LOGAN_RETCODE_PARAM_ERROR_CU_SIZE_MODE, "PARAM_ERROR_CU_SIZE_MODE",
72  NI_LOGAN_RETCODE_PARAM_ERROR_MX_NUM_MERGE, "PARAM_ERROR_MX_NUM_MERGE",
73  NI_LOGAN_RETCODE_PARAM_ERROR_DY_MERGE_8X8_EN, "PARAM_ERROR_DY_MERGE_8X8_EN",
74  NI_LOGAN_RETCODE_PARAM_ERROR_DY_MERGE_16X16_EN, "PARAM_ERROR_DY_MERGE_16X16_EN",
75  NI_LOGAN_RETCODE_PARAM_ERROR_DY_MERGE_32X32_EN, "PARAM_ERROR_DY_MERGE_32X32_EN",
76  NI_LOGAN_RETCODE_PARAM_ERROR_CU_LVL_RC_EN, "PARAM_ERROR_CU_LVL_RC_EN",
77  NI_LOGAN_RETCODE_PARAM_ERROR_HVS_QP_EN, "PARAM_ERROR_HVS_QP_EN",
78  NI_LOGAN_RETCODE_PARAM_ERROR_HVS_QP_SCL, "PARAM_ERROR_HVS_QP_SCL",
79  NI_LOGAN_RETCODE_PARAM_ERROR_MN_QP, "PARAM_ERROR_MN_QP",
80  NI_LOGAN_RETCODE_PARAM_ERROR_MX_QP, "PARAM_ERROR_MX_QP",
81  NI_LOGAN_RETCODE_PARAM_ERROR_MX_DELTA_QP, "PARAM_ERROR_MX_DELTA_QP",
82  NI_LOGAN_RETCODE_PARAM_ERROR_CONF_WIN_TOP, "PARAM_ERROR_CONF_WIN_TOP",
83  NI_LOGAN_RETCODE_PARAM_ERROR_CONF_WIN_BOT, "PARAM_ERROR_CONF_WIN_BOT",
84  NI_LOGAN_RETCODE_PARAM_ERROR_CONF_WIN_L, "PARAM_ERROR_CONF_WIN_L",
85  NI_LOGAN_RETCODE_PARAM_ERROR_CONF_WIN_R, "PARAM_ERROR_CONF_WIN_R",
86  NI_LOGAN_RETCODE_PARAM_ERROR_USR_RMD_ENC_PARAM, "PARAM_ERROR_USR_RMD_ENC_PARAM",
87  NI_LOGAN_RETCODE_PARAM_ERROR_BRATE_LT_TRATE, "PARAM_ERROR_BRATE_LT_TRATE",
88  NI_LOGAN_RETCODE_PARAM_ERROR_RCINITDELAY, "PARAM_ERROR_RCINITDELAY",
89  NI_LOGAN_RETCODE_PARAM_ERROR_RCENABLE, "PARAM_ERROR_RCENABLE",
90  NI_LOGAN_RETCODE_PARAM_ERROR_MAXNUMMERGE, "PARAM_ERROR_MAXNUMMERGE",
91  NI_LOGAN_RETCODE_PARAM_ERROR_CUSTOM_GOP, "PARAM_ERROR_CUSTOM_GOP",
92  NI_LOGAN_RETCODE_PARAM_ERROR_PIC_WIDTH, "PARAM_ERROR_PIC_WIDTH",
93  NI_LOGAN_RETCODE_PARAM_ERROR_PIC_HEIGHT, "PARAM_ERROR_PIC_HEIGHT",
94  NI_LOGAN_RETCODE_PARAM_ERROR_DECODING_REFRESH_TYPE, "PARAM_ERROR_DECODING_REFRESH_TYPE",
95  NI_LOGAN_RETCODE_PARAM_ERROR_CUSIZE_MODE_8X8_EN, "PARAM_ERROR_CUSIZE_MODE_8X8_EN",
96  NI_LOGAN_RETCODE_PARAM_ERROR_CUSIZE_MODE_16X16_EN, "PARAM_ERROR_CUSIZE_MODE_16X16_EN",
97  NI_LOGAN_RETCODE_PARAM_ERROR_CUSIZE_MODE_32X32_EN, "PARAM_ERROR_CUSIZE_MODE_32X32_EN",
98  NI_LOGAN_RETCODE_PARAM_ERROR_TOO_BIG, "PARAM_ERROR_TOO_BIG",
99  NI_LOGAN_RETCODE_PARAM_ERROR_TOO_SMALL, "PARAM_ERROR_TOO_SMALL",
100  NI_LOGAN_RETCODE_PARAM_ERROR_ZERO, "PARAM_ERROR_ZERO",
101  NI_LOGAN_RETCODE_PARAM_ERROR_OOR, "PARAM_ERROR_OOR",
102  NI_LOGAN_RETCODE_PARAM_ERROR_WIDTH_TOO_BIG, "PARAM_ERROR_WIDTH_TOO_BIG",
103  NI_LOGAN_RETCODE_PARAM_ERROR_WIDTH_TOO_SMALL, "PARAM_ERROR_WIDTH_TOO_SMALL",
104  NI_LOGAN_RETCODE_PARAM_ERROR_HEIGHT_TOO_BIG, "PARAM_ERROR_HEIGHT_TOO_BIG",
105  NI_LOGAN_RETCODE_PARAM_ERROR_HEIGHT_TOO_SMALL, "PARAM_ERROR_HEIGHT_TOO_SMALL",
106  NI_LOGAN_RETCODE_PARAM_ERROR_AREA_TOO_BIG, "PARAM_ERROR_AREA_TOO_BIG",
107  NI_LOGAN_RETCODE_ERROR_EXCEED_MAX_NUM_SESSIONS, "ERROR_EXCEED_MAX_NUM_SESSIONS",
108  NI_LOGAN_RETCODE_ERROR_GET_DEVICE_POOL, "ERROR_GET_DEVICE_POOL",
109  NI_LOGAN_RETCODE_ERROR_LOCK_DOWN_DEVICE, "ERROR_LOCK_DOWN_DEVICE",
110  NI_LOGAN_RETCODE_ERROR_UNLOCK_DEVICE, "ERROR_UNLOCK_DEVICE",
111  NI_LOGAN_RETCODE_ERROR_OPEN_DEVICE, "ERROR_OPEN_DEVICE",
112  NI_LOGAN_RETCODE_ERROR_INVALID_HANDLE, "ERROR_INVALID_HANDLE",
113  NI_LOGAN_RETCODE_ERROR_INVALID_ALLOCATION_METHOD, "ERROR_INVALID_ALLOCATION_METHOD",
114  NI_LOGAN_RETCODE_ERROR_VPU_RECOVERY, "ERROR_VPU_RECOVERY",
115  NI_LOGAN_RETCODE_PARAM_GOP_INTRA_INCOMPATIBLE, "PARAM_GOP_INTRA_INCOMPATIBLE",
116 
117  NI_LOGAN_RETCODE_NVME_SC_WRITE_BUFFER_FULL, "NVME_SC_WRITE_BUFFER_FULL",
118  NI_LOGAN_RETCODE_NVME_SC_RESOURCE_UNAVAILABLE, "NVME_SC_RESOURCE_UNAVAILABLE",
119  NI_LOGAN_RETCODE_NVME_SC_RESOURCE_IS_EMPTY, "NVME_SC_RESOURCE_IS_EMPTY",
120  NI_LOGAN_RETCODE_NVME_SC_RESOURCE_NOT_FOUND, "NVME_SC_RESOURCE_NOT_FOUND",
121  NI_LOGAN_RETCODE_NVME_SC_REQUEST_NOT_COMPLETED, "NVME_SC_REQUEST_NOT_COMPLETED",
122  NI_LOGAN_RETCODE_NVME_SC_REQUEST_IN_PROGRESS, "NVME_SC_REQUEST_IN_PROGRESS",
123  NI_LOGAN_RETCODE_NVME_SC_INVALID_PARAMETER, "NVME_SC_INVALID_PARAMETER",
124  NI_LOGAN_RETCODE_NVME_SC_VPU_RECOVERY, "NVME_SC_VPU_RECOVERY",
125  NI_LOGAN_RETCODE_NVME_SC_VPU_RSRC_INSUFFICIENT, "NVME_SC_VPU_RSRC_INSUFFICIENT",
126  NI_LOGAN_RETCODE_NVME_SC_VPU_GENERAL_ERROR, "NVME_SC_VPU_GENERAL_ERROR",
127 
128  NI_LOGAN_RETCODE_DEFAULT_SESSION_ERR_NO, "DEFAULT_SESSION_ERR_NO",
129 };
130 
131 #define MAX_LOG2_MAX_FRAME_NUM (12 + 4)
132 #define MIN_LOG2_MAX_FRAME_NUM 4
133 #define EXTENDED_SAR 255
134 #define QP_MAX_NUM (51 + 6*6) // The maximum supported qp
135 
139 typedef struct _ni_logan_h264_pps_t
140 {
141  unsigned int sps_id;
142  int cabac;
146  unsigned int ref_count[2];
149  int init_qp;
150  int init_qs;
156  uint8_t scaling_matrix4[6][16];
157  uint8_t scaling_matrix8[6][64];
158  uint8_t chroma_qp_table[2][QP_MAX_NUM+1];
160  uint8_t data[4096];
161  size_t data_size;
162 
163  uint32_t dequant4_buffer[6][QP_MAX_NUM + 1][16];
164  uint32_t dequant8_buffer[6][QP_MAX_NUM + 1][64];
165  uint32_t(*dequant4_coeff[6])[16];
166  uint32_t(*dequant8_coeff[6])[64];
168 
169 volatile int send_fin_flag = 0, receive_fin_flag = 0, flush_fin_flag = 0, err_flag = 0;
170 volatile uint32_t number_of_frames = 0;
171 volatile uint32_t number_of_packets = 0;
172 static volatile uint32_t dec_flush_sec = 0;
173 static volatile uint32_t dec_flush_cnt = 0;
174 static volatile uint32_t dec_flush_pkt = 0;
175 static int g_file_loop = 1;
176 struct timeval start_time, previous_time, current_time;
178 static int g_reconfigCount = 0;
179 
180 // max YUV frame size
181 #define MAX_YUV_FRAME_SIZE (7680 * 4320 * 3 / 2)
182 
183 static uint8_t *g_file_cache = NULL;
184 static uint8_t *g_curr_cache_pos = NULL;
185 
186 volatile long total_file_size = 0;
187 volatile uint32_t data_left_size = 0;
188 
189 static const char* ni_logan_get_rc_txt(ni_logan_retcode_t rc)
190 {
191  int i;
192  for (i = 0; i < sizeof(ni_logan_err_rc_description) / sizeof(ni_logan_err_rc_txt_entry_t);
193  i++)
194  {
195  if (rc == ni_logan_err_rc_description[i].rc)
196  {
197  return ni_logan_err_rc_description[i].txt;
198  }
199  }
200  return "rc not supported";
201 }
202 
203 void arg_error_exit(char* arg_name, char* param)
204 {
205  fprintf(stderr, "Error: unrecognized argument for %s, \"%s\"\n",
206  arg_name, param);
207  exit(-1);
208 }
209 
210 // return actual bytes copied from cache, in requested size
211 int read_next_chunk(uint8_t *p_dst, uint32_t to_read)
212 {
213  int to_copy = to_read;
214 
215  if (data_left_size == 0)
216  {
217  return 0;
218  }
219  else if (data_left_size < to_read)
220  {
221  to_copy = data_left_size;
222  }
223 
224  memcpy(p_dst, g_curr_cache_pos, to_copy);
225  g_curr_cache_pos += to_copy;
226  data_left_size -= to_copy;
227 
228  return to_copy;
229 }
230 
231 // current position of the input data buffer
232 static int curr_nal_start = 0;
233 static int curr_found_pos = 0;
234 
235 // reset input data buffer position to the start
237 {
238  curr_nal_start = 0;
239  curr_found_pos = 0;
240 }
241 
242 // rewind input data buffer position by a number of bytes, if possible
243 void rewind_data_buf_pos_by(int nb_bytes)
244 {
245  if (curr_found_pos > nb_bytes)
246  {
247  curr_found_pos -= nb_bytes;
248  }
249  else
250  {
251  ni_log(NI_LOG_ERROR, "Error %s %d bytes!\n", __FUNCTION__, nb_bytes);
252  }
253 }
254 
255 // find/copy next H.264 NAL unit (including start code) and its type;
256 // return NAL data size if found, 0 otherwise
257 int find_h264_next_nalu(uint8_t *p_dst, int *nal_type)
258 {
259  int data_size;
260 
261  int i = curr_found_pos;
262 
263  if (i + 3 >= total_file_size)
264  {
265  ni_log(NI_LOG_TRACE, "%s reaching end, curr_pos %d total input size %lu\n",
266  __FUNCTION__, curr_found_pos, total_file_size);
267  return 0;
268  }
269 
270  // search for start code 0x000001 or 0x00000001
271  while ((g_curr_cache_pos[i] != 0x00 || g_curr_cache_pos[i+1] != 0x00 ||
272  g_curr_cache_pos[i+2] != 0x01) &&
273  (g_curr_cache_pos[i] != 0x00 || g_curr_cache_pos[i+1] != 0x00 ||
274  g_curr_cache_pos[i+2] != 0x00 || g_curr_cache_pos[i+3] != 0x01))
275  {
276  i++;
277  if (i + 3 > total_file_size)
278  {
279  return 0;
280  }
281  }
282 
283  // found start code, advance to NAL unit start depends on actual start code
284  if (g_curr_cache_pos[i] != 0x00 || g_curr_cache_pos[i+1] != 0x00 ||
285  g_curr_cache_pos[i+2] != 0x01)
286  {
287  i++;
288  }
289 
290  i += 3;
291  curr_nal_start = i;
292 
293  // get the NAL type
294  *nal_type = (g_curr_cache_pos[i] & 0x1f);
295 
296  // advance to the end of NAL, or stream
297  while ((g_curr_cache_pos[i] != 0x00 || g_curr_cache_pos[i+1] != 0x00 ||
298  g_curr_cache_pos[i+2] != 0x00) &&
299  (g_curr_cache_pos[i] != 0x00 || g_curr_cache_pos[i+1] != 0x00 ||
300  g_curr_cache_pos[i+2] != 0x01))
301  {
302  i++;
303  // if reaching the stream end
304  if (i + 3 > total_file_size)
305  {
306  data_size = total_file_size - curr_found_pos;
307  memcpy(p_dst, &g_curr_cache_pos[curr_found_pos], data_size);
308  curr_found_pos = total_file_size;
309  return data_size;
310  }
311  }
312 
313  data_size = i - curr_found_pos;
314  memcpy(p_dst, &g_curr_cache_pos[curr_found_pos], data_size);
315  curr_found_pos = i;
316  return data_size;
317 }
318 
319 static const uint8_t default_scaling4[2][16] =
320 {
321  { 6, 13, 20, 28, 13, 20, 28, 32,
322  20, 28, 32, 37, 28, 32, 37, 42 },
323  { 10, 14, 20, 24, 14, 20, 24, 27,
324  20, 24, 27, 30, 24, 27, 30, 34 }
325 };
326 
327 static const uint8_t default_scaling8[2][64] =
328 {
329  { 6, 10, 13, 16, 18, 23, 25, 27,
330  10, 11, 16, 18, 23, 25, 27, 29,
331  13, 16, 18, 23, 25, 27, 29, 31,
332  16, 18, 23, 25, 27, 29, 31, 33,
333  18, 23, 25, 27, 29, 31, 33, 36,
334  23, 25, 27, 29, 31, 33, 36, 38,
335  25, 27, 29, 31, 33, 36, 38, 40,
336  27, 29, 31, 33, 36, 38, 40, 42 },
337  { 9, 13, 15, 17, 19, 21, 22, 24,
338  13, 13, 17, 19, 21, 22, 24, 25,
339  15, 17, 19, 21, 22, 24, 25, 27,
340  17, 19, 21, 22, 24, 25, 27, 28,
341  19, 21, 22, 24, 25, 27, 28, 30,
342  21, 22, 24, 25, 27, 28, 30, 32,
343  22, 24, 25, 27, 28, 30, 32, 33,
344  24, 25, 27, 28, 30, 32, 33, 35 }
345 };
346 
347 const uint8_t ni_logan_zigzag_direct[64] =
348 {
349  0, 1, 8, 16, 9, 2, 3, 10,
350  17, 24, 32, 25, 18, 11, 4, 5,
351  12, 19, 26, 33, 40, 48, 41, 34,
352  27, 20, 13, 6, 7, 14, 21, 28,
353  35, 42, 49, 56, 57, 50, 43, 36,
354  29, 22, 15, 23, 30, 37, 44, 51,
355  58, 59, 52, 45, 38, 31, 39, 46,
356  53, 60, 61, 54, 47, 55, 62, 63
357 };
358 
359 const uint8_t ni_logan_zigzag_scan[16+1] =
360 {
361  0 + 0 * 4, 1 + 0 * 4, 0 + 1 * 4, 0 + 2 * 4,
362  1 + 1 * 4, 2 + 0 * 4, 3 + 0 * 4, 2 + 1 * 4,
363  1 + 2 * 4, 0 + 3 * 4, 1 + 3 * 4, 2 + 2 * 4,
364  3 + 1 * 4, 3 + 2 * 4, 2 + 3 * 4, 3 + 3 * 4,
365 };
366 
367 // HRD parsing: return 0 if parsing ok, -1 otherwise
369 {
370  int cpb_count, i;
371  unsigned int dummy;
372 
373  cpb_count = ni_bs_reader_get_ue(br) + 1;
374  if (cpb_count > 32U)
375  {
376  ni_log(NI_LOG_ERROR, "%s invalid cpb_count %d\n", __FUNCTION__, cpb_count);
377  return -1;
378  }
379 
380  ni_bs_reader_get_bits(br, 4); // bit_rate_scale
381  ni_bs_reader_get_bits(br, 4); // cpb_size_scale
382  for (i = 0; i < cpb_count; i++)
383  {
384  dummy = ni_bs_reader_get_ue(br); // bit_rate_value_minus1
385  dummy = ni_bs_reader_get_ue(br); // cpb_size_value_minus1
386  dummy = ni_bs_reader_get_bits(br, 1); // cbr_flag
387  }
392  sps->cpb_cnt = cpb_count;
393  return 0;
394 }
395 
396 // VUI parsing: return 0 if parsing ok, -1 otherwise
398 {
399  int ret = -1, aspect_ratio_info_present_flag;
400  unsigned int aspect_ratio_idc, dummy;
401 
402  aspect_ratio_info_present_flag = ni_bs_reader_get_bits(br, 1);
403  if (aspect_ratio_info_present_flag)
404  {
405  aspect_ratio_idc = ni_bs_reader_get_bits(br, 8);
406  if (EXTENDED_SAR == aspect_ratio_idc)
407  {
408  sps->sar.num = ni_bs_reader_get_bits(br, 16);
409  sps->sar.den = ni_bs_reader_get_bits(br, 16);
410  }
411  else if (aspect_ratio_idc < NI_NUM_PIXEL_ASPECT_RATIO)
412  {
413  sps->sar = ni_h264_pixel_aspect_list[aspect_ratio_idc];
414  }
415  else
416  {
417  ni_log(NI_LOG_ERROR, "%s: illegal aspect ratio %u\n",
418  __FUNCTION__, aspect_ratio_idc);
419  goto end;
420  }
421  }
422  else
423  {
424  sps->sar.num = sps->sar.den = 0;
425  }
426 
427  if (ni_bs_reader_get_bits(br, 1)) // overscan_info_present_flag
428  {
429  ni_bs_reader_get_bits(br, 1); // overscan_appropriate_flag
430  }
433  {
434  ni_bs_reader_get_bits(br, 3); // video_format
435  sps->full_range = ni_bs_reader_get_bits(br, 1); // video_full_range_flag
436 
439  {
441  sps->color_trc = ni_bs_reader_get_bits(br, 8);
442  sps->colorspace = ni_bs_reader_get_bits(br, 8);
445  {
447  }
448  if (sps->color_trc < NI_COL_TRC_RESERVED0 ||
449  sps->color_trc >= NI_COL_TRC_NB)
450  {
452  }
453  if (sps->colorspace < NI_COL_SPC_RGB ||
454  sps->colorspace >= NI_COL_SPC_NB)
455  {
457  }
458  }
459  }
460 
461  if (ni_bs_reader_get_bits(br, 1)) // chroma_location_info_present_flag
462  {
463  dummy = ni_bs_reader_get_ue(br); // chroma_sample_location_type_top_field
464  dummy = ni_bs_reader_get_ue(br); // chroma_sample_location_type_bottom_field
465  }
466 
468  if (sps->timing_info_present_flag)
469  {
470  unsigned num_units_in_tick = ni_bs_reader_get_bits(br, 32);
471  unsigned time_scale = ni_bs_reader_get_bits(br, 32);
472  if (! num_units_in_tick || ! time_scale)
473  {
474  ni_log(NI_LOG_ERROR, "%s: error num_units_in_tick/time_scale (%u/%u)\n",
475  __FUNCTION__, num_units_in_tick, time_scale);
476  sps->timing_info_present_flag = 0;
477  }
479  }
480 
482  if (sps->nal_hrd_parameters_present_flag && parse_hrd(br, sps) < 0)
483  {
484  ni_log(NI_LOG_ERROR, "%s: nal_hrd_parameters_present and error "
485  "parse_hrd !\n", __FUNCTION__);
486  goto end;
487  }
488 
490  if (sps->vcl_hrd_parameters_present_flag && parse_hrd(br, sps) < 0)
491  {
492  ni_log(NI_LOG_ERROR, "%s: vcl_hrd_parameters_present and error "
493  "parse_hrd !\n", __FUNCTION__);
494  goto end;
495  }
496 
499  {
500  ni_bs_reader_get_bits(br, 1); // low_delay_hrd_flag
501  }
502 
504 
507  {
508  ni_bs_reader_get_bits(br, 1); // motion_vectors_over_pic_boundaries_flag
509  ni_bs_reader_get_ue(br); // max_bytes_per_pic_denom
510  ni_bs_reader_get_ue(br); // max_bits_per_mb_denom
511  ni_bs_reader_get_ue(br); // log2_max_mv_length_horizontal
512  ni_bs_reader_get_ue(br); // log2_max_mv_length_vertical
515 
516  if (sps->num_reorder_frames > 16U)
517  {
518  ni_log(NI_LOG_ERROR, "%s: clip illegal num_reorder_frames %d !\n",
519  __FUNCTION__, sps->num_reorder_frames);
520  sps->num_reorder_frames = 16;
521  goto end;
522  }
523  }
524 
525  // everything is fine
526  ret = 0;
527 
528 end:
529  return ret;
530 }
531 
532 int parse_scaling_list(ni_bitstream_reader_t *br, uint8_t *factors, int size,
533  const uint8_t *jvt_list, const uint8_t *fallback_list)
534 {
535  int i, last = 8, next = 8;
536  const uint8_t *scan = (size == 16 ? ni_logan_zigzag_scan : ni_logan_zigzag_direct);
537 
538  // matrix not written, we use the predicted one */
539  if (! ni_bs_reader_get_bits(br, 1))
540  {
541  memcpy(factors, fallback_list, size * sizeof(uint8_t));
542  }
543  else
544  {
545  for (i = 0; i < size; i++)
546  {
547  if (next)
548  {
549  int v = ni_bs_reader_get_se(br);
550  if (v < -128 || v > 127)
551  {
552  ni_log(NI_LOG_ERROR, "delta scale %d is invalid\n", v);
553  return -1;
554  }
555  next = (last + v) & 0xff;
556  }
557  if (! i && ! next)
558  { // matrix not written, we use the preset one
559  memcpy(factors, jvt_list, size * sizeof(uint8_t));
560  break;
561  }
562  last = (factors[scan[i]] = next ? next : last);
563  }
564  }
565  return 0;
566 }
567 
568 // SPS seq scaling matrices parsing: return 0 if parsing ok, -1 otherwise
570  const ni_logan_h264_pps_t *pps, int is_sps,
571  uint8_t(*scaling_matrix4)[16],
572  uint8_t(*scaling_matrix8)[64])
573 {
574  int ret = 0;
575  int fallback_sps = !is_sps && sps->scaling_matrix_present;
576  const uint8_t *fallback[4] = {
577  fallback_sps ? sps->scaling_matrix4[0] : default_scaling4[0],
578  fallback_sps ? sps->scaling_matrix4[3] : default_scaling4[1],
579  fallback_sps ? sps->scaling_matrix8[0] : default_scaling8[0],
580  fallback_sps ? sps->scaling_matrix8[3] : default_scaling8[1]
581  };
582 
583  if (ni_bs_reader_get_bits(br, 1)) // scaling_matrix_present
584  {
585  // retrieve matrices
586  ret |= parse_scaling_list(br, scaling_matrix4[0], 16, default_scaling4[0],
587  fallback[0]); // Intra, Y
588  ret |= parse_scaling_list(br, scaling_matrix4[1], 16, default_scaling4[0],
589  scaling_matrix4[0]); // Intra, Cr
590  ret |= parse_scaling_list(br, scaling_matrix4[2], 16, default_scaling4[0],
591  scaling_matrix4[1]); // Intra, Cb
592  ret |= parse_scaling_list(br, scaling_matrix4[3], 16, default_scaling4[1],
593  fallback[1]); // Inter, Y
594  ret |= parse_scaling_list(br, scaling_matrix4[4], 16, default_scaling4[1],
595  scaling_matrix4[3]); // Inter, Cr
596  ret |= parse_scaling_list(br, scaling_matrix4[5], 16, default_scaling4[1],
597  scaling_matrix4[4]); // Inter, Cb
598 
599  if (is_sps || pps->transform_8x8_mode)
600  {
601  ret |= parse_scaling_list(br, scaling_matrix8[0], 64,
602  default_scaling8[0], fallback[2]); // Intra, Y
603  ret |= parse_scaling_list(br, scaling_matrix8[3], 64,
604  default_scaling8[1], fallback[3]); // Inter, Y
605  if (sps->chroma_format_idc == 3)
606  {
607  ret |= parse_scaling_list(br, scaling_matrix8[1], 64, // Intra, Cr
608  default_scaling8[0], scaling_matrix8[0]);
609  ret |= parse_scaling_list(br, scaling_matrix8[4], 64, // Inter, Cr
610  default_scaling8[1], scaling_matrix8[3]);
611  ret |= parse_scaling_list(br, scaling_matrix8[2], 64, // Intra, Cb
612  default_scaling8[0], scaling_matrix8[1]);
613  ret |= parse_scaling_list(br, scaling_matrix8[5], 64, // Inter, Cb
614  default_scaling8[1], scaling_matrix8[4]);
615  }
616  }
617  if (! ret)
618  {
619  ret = is_sps;
620  }
621  }
622  return ret;
623 }
624 
625 // SPS parsing: return 0 if parsing ok, -1 otherwise
626 int parse_sps(uint8_t *buf, int size_bytes, ni_logan_h264_sps_t *sps)
627 {
628  int ret = -1;
630  int profile_idc, level_idc, constraint_set_flags = 0;
631  uint32_t sps_id;
632  int i, log2_max_frame_num_minus4;
633 
634  ni_bitstream_reader_init(&br, buf, 8 * size_bytes);
635  // skip NAL header
636  ni_bs_reader_skip_bits(&br, 8);
637 
638  profile_idc = ni_bs_reader_get_bits(&br, 8);
639  // from constraint_set0_flag to constraint_set5_flag
640  constraint_set_flags |= ni_bs_reader_get_bits(&br, 1) << 0;
641  constraint_set_flags |= ni_bs_reader_get_bits(&br, 1) << 1;
642  constraint_set_flags |= ni_bs_reader_get_bits(&br, 1) << 2;
643  constraint_set_flags |= ni_bs_reader_get_bits(&br, 1) << 3;
644  constraint_set_flags |= ni_bs_reader_get_bits(&br, 1) << 4;
645  constraint_set_flags |= ni_bs_reader_get_bits(&br, 1) << 5;
646  ni_bs_reader_skip_bits(&br, 2); // reserved_zero_2bits
647  level_idc = ni_bs_reader_get_bits(&br, 8);
648  sps_id = ni_bs_reader_get_ue(&br);
649 
650  sps->sps_id = sps_id;
651  sps->profile_idc = profile_idc;
652  sps->constraint_set_flags = constraint_set_flags;
653  sps->level_idc = level_idc;
654  sps->full_range = -1;
655 
656  memset(sps->scaling_matrix4, 16, sizeof(sps->scaling_matrix4));
657  memset(sps->scaling_matrix8, 16, sizeof(sps->scaling_matrix8));
658  sps->scaling_matrix_present = 0;
659  sps->colorspace = 2; // NI_COL_SPC_UNSPECIFIED
660 
661  if (100 == profile_idc || 110 == profile_idc || 122 == profile_idc ||
662  244 == profile_idc || 44 == profile_idc || 83 == profile_idc ||
663  86 == profile_idc || 118 == profile_idc || 128 == profile_idc ||
664  138 == profile_idc || 139 == profile_idc || 134 == profile_idc ||
665  135 == profile_idc || 144 == profile_idc /* old High444 profile */)
666  {
668  if (sps->chroma_format_idc > 3U)
669  {
670  ni_log(NI_LOG_ERROR, "%s error: chroma_format_idc > 3!\n", __FUNCTION__);
671  goto end;
672  }
673  else if (3 == sps->chroma_format_idc)
674  {
677  {
678  ni_log(NI_LOG_ERROR, "%s error: residual_color_transform not "
679  "supported !\n", __FUNCTION__);
680  goto end;
681  }
682  }
683  sps->bit_depth_luma = ni_bs_reader_get_ue(&br) + 8;
684  sps->bit_depth_chroma = ni_bs_reader_get_ue(&br) + 8;
685  if (sps->bit_depth_luma != sps->bit_depth_chroma)
686  {
687  ni_log(NI_LOG_ERROR, "%s error: different luma %d & chroma %d bit depth !\n",
688  __FUNCTION__, sps->bit_depth_luma, sps->bit_depth_chroma);
689  goto end;
690  }
691  if (sps->bit_depth_luma < 8 || sps->bit_depth_luma > 12 ||
692  sps->bit_depth_chroma < 8 || sps->bit_depth_chroma > 12)
693  {
694  ni_log(NI_LOG_ERROR, "%s error: illegal luma/chroma bit depth value (%d %d)!\n",
695  __FUNCTION__, sps->bit_depth_luma, sps->bit_depth_chroma);
696  goto end;
697  }
698 
700  ret = parse_scaling_matrices(&br, sps, NULL, 1,
701  sps->scaling_matrix4, sps->scaling_matrix8);
702  if (ret < 0)
703  {
704  ni_log(NI_LOG_ERROR, "%s error scaling matrices parse failed !\n", __FUNCTION__);
705  goto end;
706  }
707  sps->scaling_matrix_present |= ret;
708  } // profile_idc
709  else
710  {
711  sps->chroma_format_idc = 1;
712  sps->bit_depth_luma = 8;
713  sps->bit_depth_chroma = 8;
714  }
715 
716  log2_max_frame_num_minus4 = ni_bs_reader_get_ue(&br);
717  if (log2_max_frame_num_minus4 < MIN_LOG2_MAX_FRAME_NUM - 4 ||
718  log2_max_frame_num_minus4 > MAX_LOG2_MAX_FRAME_NUM - 4)
719  {
720  ni_log(NI_LOG_ERROR, "%s error: log2_max_frame_num_minus4 %d out of "
721  "range (0-12)!\n", __FUNCTION__, log2_max_frame_num_minus4);
722  goto end;
723  }
724  sps->log2_max_frame_num = log2_max_frame_num_minus4 + 4;
725 
726  sps->poc_type = ni_bs_reader_get_ue(&br);
727  if (0 == sps->poc_type)
728  {
729  uint32_t v = ni_bs_reader_get_ue(&br);
730  if (v > 12)
731  {
732  ni_log(NI_LOG_ERROR, "%s error: log2_max_poc_lsb %d out of range!\n",
733  __FUNCTION__, v);
734  goto end;
735  }
736  sps->log2_max_poc_lsb = v + 4;
737  }
738  else if (1 == sps->poc_type)
739  {
744  if ((unsigned)sps->poc_cycle_length >= 256)
745  {
746  ni_log(NI_LOG_ERROR, "%s error: poc_cycle_length %d out of range!\n", __FUNCTION__, sps->poc_cycle_length);
747  goto end;
748  }
749  for (i = 0; i < sps->poc_cycle_length; i++)
750  {
752  }
753  }
754  else if (2 != sps->poc_type)
755  {
756  ni_log(NI_LOG_ERROR, "%s error: illegal PIC type %d!\n",
757  __FUNCTION__, sps->poc_type);
758  goto end;
759  }
762  sps->mb_width = ni_bs_reader_get_ue(&br) + 1;
763  sps->mb_height = ni_bs_reader_get_ue(&br) + 1;
764 
766  sps->mb_height *= 2 - sps->frame_mbs_only_flag;
767 
768  if (! sps->frame_mbs_only_flag)
769  {
770  sps->mb_aff = ni_bs_reader_get_bits(&br, 1);
771  }
772  else
773  {
774  sps->mb_aff = 0;
775  }
776 
778 
779  sps->crop = ni_bs_reader_get_bits(&br, 1);
780  if (sps->crop)
781  {
782  unsigned int crop_left = ni_bs_reader_get_ue(&br);
783  unsigned int crop_right = ni_bs_reader_get_ue(&br);
784  unsigned int crop_top = ni_bs_reader_get_ue(&br);
785  unsigned int crop_bottom = ni_bs_reader_get_ue(&br);
786 
787  // no range checking
788  int vsub = (sps->chroma_format_idc == 1) ? 1 : 0;
789  int hsub = (sps->chroma_format_idc == 1 ||
790  sps->chroma_format_idc == 2) ? 1 : 0;
791  int step_x = 1 << hsub;
792  int step_y = (2 - sps->frame_mbs_only_flag) << vsub;
793 
794  sps->crop_left = crop_left * step_x;
795  sps->crop_right = crop_right * step_x;
796  sps->crop_top = crop_top * step_y;
797  sps->crop_bottom = crop_bottom * step_y;
798  }
799  else
800  {
801  sps->crop_left =
802  sps->crop_right =
803  sps->crop_top =
804  sps->crop_bottom =
805  sps->crop = 0;
806  }
807 
808  // deduce real width/heigh
809  sps->width = 16 * sps->mb_width - sps->crop_left - sps->crop_right;
810  sps->height = 16 * sps->mb_height - sps->crop_top - sps->crop_bottom;
811 
814  {
815  int ret = parse_vui(&br, sps);
816  if (ret < 0)
817  {
818  ni_log(NI_LOG_ERROR, "%s error: parse_vui failed %d!\n", __FUNCTION__, ret);
819  goto end;
820  }
821  }
822 
823  // everything is fine
824  ret = 0;
825 
826 end:
827 
828  return ret;
829 }
830 
831 int parse_sei(uint8_t *buf, int size_bytes, ni_logan_h264_sps_t *sps,
832  int *sei_type, int *is_interlaced)
833 {
835  *is_interlaced = 0;
836  int ret = -1, dummy;
837  int cpb_dpb_delays_present_flag = (sps->nal_hrd_parameters_present_flag ||
839  //pic_struct_present_flag
840 
841  ni_bitstream_reader_init(&br, buf, 8 * size_bytes);
842  // skip NAL header
843  ni_bs_reader_skip_bits(&br, 8);
844 
845  while (ni_bs_reader_get_bits_left(&br) > 16)
846  {
847  int type = 0;
848  int size = 0, tmp, next;
849 
850  do
851  {
852  if (ni_bs_reader_get_bits_left(&br) < 8)
853  {
854  ni_log(NI_LOG_ERROR, "%s type parse error !\n", __FUNCTION__);
855  goto end;
856  }
857  tmp = ni_bs_reader_get_bits(&br, 8);
858  type += tmp;
859  } while (tmp == 0xFF);
860 
861  *sei_type = type;
862  do
863  {
864  if (ni_bs_reader_get_bits_left(&br) < 8)
865  {
866  ni_log(NI_LOG_ERROR, "%s type %d size parse error!\n",
867  __FUNCTION__, type);
868  goto end;
869  }
870  tmp = ni_bs_reader_get_bits(&br, 8);
871  size += tmp;
872  } while (tmp == 0xFF);
873 
874  if (size > ni_bs_reader_get_bits_left(&br) / 8)
875  {
876  ni_log(NI_LOG_ERROR, "%s SEI type %d size %u truncated at %d\n",
877  __FUNCTION__, type, size, ni_bs_reader_get_bits_left(&br));
878  goto end;
879  }
880  next = ni_bs_reader_bits_count(&br) + 8 * size;
881 
882  switch (type)
883  {
885  if (cpb_dpb_delays_present_flag)
886  {
889  }
890  if (sps->pic_struct_present_flag)
891  {
892  dummy = ni_bs_reader_get_bits(&br, 4);
893  if (dummy < NI_H264_SEI_PIC_STRUCT_FRAME ||
895  {
896  ni_log(NI_LOG_ERROR, "%s pic_timing SEI invalid pic_struct: %d\n",
897  __FUNCTION__, dummy);
898  goto end;
899  }
900  if (dummy > NI_H264_SEI_PIC_STRUCT_FRAME)
901  {
902  *is_interlaced = 1;
903  }
904  goto success;
905  }
906  break;
907  default:
908  // skip all other SEI types
909  ;
910  }
912  } // while in SEI
913 
914 success:
915  ret = 0;
916 
917 end:
918  return ret;
919 }
920 
921 // probe h.264 stream info; return 0 if stream can be decoded, -1 otherwise
923 {
924  int ret = -1;
925  uint8_t *buf = NULL;
926  uint8_t *p_buf = buf;
927  int nal_size, ep3_removed = 0, vcl_nal_count = 0;
928  int nal_type = -1, sei_type = -1;
929  int sps_parsed = 0, is_interlaced = 0;
930 
931  if (NULL == (buf = calloc(1, NI_LOGAN_MAX_TX_SZ)))
932  {
933  ni_log(NI_LOG_ERROR, "Error %s: allocate stream buf\n", __FUNCTION__);
934  goto end;
935  }
936 
938  // probe at most 100 VCL before stops
939  while ((! sps_parsed || ! is_interlaced) && vcl_nal_count < 100 &&
940  (nal_size = find_h264_next_nalu(buf, &nal_type)) > 0)
941  {
942  ni_log(NI_LOG_TRACE, "nal %d nal_size %d\n", nal_type, nal_size);
943  p_buf = buf;
944 
945  // skip the start code
946  while (! (p_buf[0] == 0x00 && p_buf[1] == 0x00 && p_buf[2] == 0x01) &&
947  nal_size > 3)
948  {
949  p_buf++;
950  nal_size--;
951  }
952  if (nal_size <= 3)
953  {
954  ni_log(NI_LOG_ERROR, "Error %s NAL has no header\n", __FUNCTION__);
955  continue;
956  }
957 
958  p_buf += 3;
959  nal_size -= 3;
960 
961  ep3_removed = ni_logan_remove_emulation_prevent_bytes(p_buf, nal_size);
962  nal_size -= ep3_removed;
963 
964  if (NI_LOGAN_H264_NAL_SPS == nal_type && ! sps_parsed)
965  {
966  if (vcl_nal_count > 0)
967  {
968  ni_log(NI_LOG_INFO, "Warning: %s has %d slice NAL units ahead of SPS!\n",
969  __FUNCTION__, vcl_nal_count);
970  }
971 
972  if (parse_sps(p_buf, nal_size, sps))
973  {
974  ni_log(NI_LOG_ERROR, "%s: parse_sps error\n", __FUNCTION__);
975  break;
976  }
977  sps_parsed = 1;
978  }
979  else if (NI_LOGAN_H264_NAL_SEI == nal_type)
980  {
981  parse_sei(p_buf, nal_size, sps, &sei_type, &is_interlaced);
982  }
983  else if (NI_LOGAN_H264_NAL_SLICE == nal_type || NI_LOGAN_H264_NAL_IDR_SLICE == nal_type)
984  {
985  vcl_nal_count++;
986  }
987 
988  if (sps_parsed &&
991  NI_H264_SEI_TYPE_PIC_TIMING == sei_type && is_interlaced)
992  {
993  ni_log(NI_LOG_ERROR, "probe_h264_stream_info interlaced NOT supported!\n", __FUNCTION__);
994  break;
995  }
996  } // while for each NAL unit
997 
999 
1000  ni_log(NI_LOG_INFO, "VCL NAL parsed: %d, SPS parsed: %s, is interlaced: %s\n",
1001  vcl_nal_count, sps_parsed ? "Yes":"No", is_interlaced ? "Yes":"No");
1002  if (sps_parsed && ! is_interlaced)
1003  {
1004  ret = 0;
1005  }
1006  else
1007  {
1008  ni_log(NI_LOG_ERROR, "Input is either interlaced, or unable to determine, "
1009  "probing failed.\n");
1010  }
1011 
1012  static const char csp[4][5] = { "Gray", "420", "422", "444" };
1013  ni_log(NI_LOG_INFO, "H.264 stream probed %d VCL NAL units, sps:%u "
1014  "profile:%d/%d poc %d ref:%d %dx%d [SAR: %d:%d] %s %s "
1015  "%"PRId32"/%"PRId32" %d bits max_reord:%d max_dec_buf:"
1016  "%d\n",
1017  vcl_nal_count, sps->sps_id, sps->profile_idc, sps->level_idc,
1018  sps->poc_type, sps->ref_frame_count, sps->width, sps->height,
1019  /*sps->crop_left, sps->crop_right, sps->crop_top, sps->crop_bottom,*/
1020  sps->sar.num, sps->sar.den,
1021  sps->vui_parameters_present_flag ? "VUI" : "no-VUI",
1022  csp[sps->chroma_format_idc],
1024  sps->timing_info_present_flag ? sps->time_scale : 0,
1025  sps->bit_depth_luma,
1028 
1029 end:
1030  free(buf);
1031  buf = NULL;
1032  return ret;
1033 }
1034 
1035 // parse H.264 slice header to get frame_num; return 0 if success, -1 otherwise
1036 int parse_h264_slice_header(uint8_t *buf, int size_bytes, ni_logan_h264_sps_t *sps,
1037  int32_t *frame_num, unsigned int *first_mb_in_slice)
1038 {
1040  uint8_t *p_buf = buf;
1041  unsigned int slice_type, pps_id;
1042 
1043  // skip the start code
1044  while (! (p_buf[0] == 0x00 && p_buf[1] == 0x00 && p_buf[2] == 0x01) &&
1045  size_bytes > 3)
1046  {
1047  p_buf++;
1048  size_bytes--;
1049  }
1050  if (size_bytes <= 3)
1051  {
1052  ni_log(NI_LOG_ERROR, "Error %s slice has no header\n", __FUNCTION__);
1053  return -1;
1054  }
1055 
1056  p_buf += 3;
1057  size_bytes -= 3;
1058 
1059  ni_bitstream_reader_init(&br, p_buf, 8 * size_bytes);
1060 
1061  // skip NAL header
1062  ni_bs_reader_skip_bits(&br, 8);
1063 
1064  *first_mb_in_slice = ni_bs_reader_get_ue(&br);
1065  slice_type = ni_bs_reader_get_ue(&br);
1066  if (slice_type > 9)
1067  {
1068  ni_log(NI_LOG_ERROR, "%s error: slice type %u too large at %u\n",
1069  __FUNCTION__, slice_type, *first_mb_in_slice);
1070  return -1;
1071  }
1072  pps_id = ni_bs_reader_get_ue(&br);
1073  *frame_num = ni_bs_reader_get_bits(&br, sps->log2_max_frame_num);
1074 
1075  ni_log(NI_LOG_TRACE, "%s slice type %u frame_num %d pps_id %u size %d first_mb %u\n",
1076  __FUNCTION__, slice_type, *frame_num, pps_id, size_bytes, *first_mb_in_slice);
1077 
1078  return 0;
1079 }
1080 
1081 /*!*****************************************************************************
1082  * \brief Scan the input and find the next non VCL NAL and return its size
1083  * and type if found.
1084  * Note: To speed up checking, the parsing stops as soon as a VCL NAL is
1085  * encountered.
1086  *
1087  * \param[in] in data input
1088  * \param[in] in_size size of input data
1089  * \param[in] codec codec type, H.264 or H.265
1090  * \param[out] nal_type NAL type in H.264 or H.265
1091  *
1092  * \return NAL size (including start code) if found, 0 otherwise
1093  ******************************************************************************/
1094 static int ni_find_next_non_vcl_nalu(const uint8_t *in, int in_size,
1095  ni_logan_codec_format_t codec, int *nal_type)
1096 {
1097  int data_size = 0;
1098  int i = 0;
1099 
1100  *nal_type = -1;
1101 
1102  if (i + 3 >= in_size)
1103  {
1104  return 0;
1105  }
1106 
1107  // search for start code 0x000001 or 0x00000001
1108  while ((in[i] != 0x00 || in[i+1] != 0x00 || in[i+2] != 0x01) &&
1109  (in[i] != 0x00 || in[i+1] != 0x00 || in[i+2] != 0x00 ||
1110  in[i+3] != 0x01))
1111  {
1112  i++;
1113  if (i + 3 > in_size)
1114  {
1115  return 0;
1116  }
1117  }
1118 
1119  // found start code, advance to NAL unit start based on actual start code
1120  if (in[i] != 0x00 || in[i+1] != 0x00 || in[i+2] != 0x01)
1121  {
1122  i++;
1123  }
1124 
1125  i += 3;
1126 
1127  // get the NAL type
1128  if (NI_LOGAN_CODEC_FORMAT_H264 == codec)
1129  {
1130  *nal_type = (in[i] & 0x1f);
1131  if (*nal_type >= NI_LOGAN_H264_NAL_SLICE && *nal_type <= NI_LOGAN_H264_NAL_IDR_SLICE)
1132  {
1133  return 0;
1134  }
1135  }
1136  else if (NI_LOGAN_CODEC_FORMAT_H265 == codec)
1137  {
1138  *nal_type = (in[i] >> 1);
1139  }
1140  else
1141  {
1142  return 0;
1143  }
1144 
1145  // advance to the end of NAL or stream
1146  while ((in[i] != 0x00 || in[i+1] != 0x00 || in[i+2] != 0x00) &&
1147  (in[i] != 0x00 || in[i+1] != 0x00 || in[i+2] != 0x01))
1148  {
1149  i++;
1150  // if reaching/passing the stream end, return the whole data chunk size
1151  if (i + 3 > in_size)
1152  {
1153  data_size = in_size;
1154  return data_size;
1155  }
1156  }
1157 
1158  data_size = i;
1159  return data_size;
1160 }
1161 
1162 /*!*****************************************************************************
1163  * \brief Sends data to decoder device. The data is assumed to be a full
1164  * encoded frame that will be scanned, and stream headers if available
1165  * will be saved/updated in the session context, to be used for contin-
1166  * uous decoding once ni_logan_device_dec_session_flush is executed.
1167  *
1168  * \param[in] p_ctx Pointer to a caller allocated
1169  * ni_logan_session_context_t struct
1170  * \param[in] p_data Pointer to a caller allocated
1171  * ni_logan_session_data_io_t struct which contains a
1172  * ni_logan_packet_t data packet to send
1173  *
1174  * \return On success
1175  * Total number of bytes written
1176  * On failure
1177  * NI_LOGAN_RETCODE_INVALID_PARAM
1178  * NI_LOGAN_RETCODE_ERROR_NVME_CMD_FAILED
1179  * NI_LOGAN_RETCODE_ERROR_INVALID_SESSION
1180  ******************************************************************************/
1183 {
1184  uint8_t stream_headers[4 * 1024];
1185  uint8_t *hdr_ptr = stream_headers;
1186  uint8_t *buf = (uint8_t *)(p_data->data.packet.p_data);
1187  int data_size = (int)(p_data->data.packet.data_len);
1188  int nal_type = -1, nal_size, header_size = 0;
1189  int sps_found = 0, pps_found = 0, vps_found = 0, headers_found = 0;
1190 
1191  // parse the packet and when SPS/PPS/VPS are found, save/update the stream
1192  // header info; stop searching as soon as VCL is encountered
1193  while (data_size > 3 && (nal_size = ni_find_next_non_vcl_nalu(
1194  buf, data_size, p_ctx->codec_format, &nal_type)) > 0)
1195  {
1197  {
1198  sps_found = (sps_found || (NI_LOGAN_H264_NAL_SPS == nal_type));
1199  pps_found = (pps_found || (NI_LOGAN_H264_NAL_PPS == nal_type));
1200  headers_found = (headers_found || (sps_found && pps_found));
1201  }
1202  else if (NI_LOGAN_CODEC_FORMAT_H265 == p_ctx->codec_format)
1203  {
1204  vps_found = (vps_found || (NI_LOGAN_HEVC_NAL_VPS == nal_type));
1205  sps_found = (sps_found || (NI_LOGAN_HEVC_NAL_SPS == nal_type));
1206  pps_found = (pps_found || (NI_LOGAN_HEVC_NAL_PPS == nal_type));
1207  headers_found = (headers_found || (vps_found && sps_found && pps_found));
1208  }
1209 
1210  if ((NI_LOGAN_CODEC_FORMAT_H264 == p_ctx->codec_format &&
1211  (NI_LOGAN_H264_NAL_SPS == nal_type || NI_LOGAN_H264_NAL_PPS == nal_type)) ||
1213  (NI_LOGAN_HEVC_NAL_VPS == nal_type || NI_LOGAN_HEVC_NAL_SPS == nal_type ||
1214  NI_LOGAN_HEVC_NAL_PPS == nal_type)))
1215  {
1216  header_size += nal_size;
1217  memcpy(hdr_ptr, buf, nal_size);
1218  hdr_ptr += nal_size;
1219  }
1220 
1221  buf += nal_size;
1222  data_size -= nal_size;
1223 
1224  if (headers_found)
1225  {
1227  p_ctx, stream_headers, header_size))
1228  {
1229  ni_log(NI_LOG_ERROR, "ni_logan_device_dec_session_write save_hdrs failed!\n");
1230  }
1231  break;
1232  }
1233  }
1235 }
1236 
1237 /*!*****************************************************************************
1238  * \brief Send decoder input data
1239  *
1240  * \param
1241  *
1242  * \return
1243  ******************************************************************************/
1245  ni_logan_session_data_io_t* p_in_data,
1246  int input_video_width,
1247  int input_video_height,
1248  int packet_size,
1249  unsigned long *total_bytes_sent,
1250  int print_time,
1251  device_state_t *p_device_state,
1252  ni_logan_h264_sps_t *sps)
1253 {
1254  static int sos_flag = 1;
1255  static uint8_t tmp_buf[NI_LOGAN_MAX_TX_SZ] = { 0 };
1256  uint8_t *tmp_buf_ptr = tmp_buf;
1257  int chunk_size = 0;
1258  int frame_pkt_size = 0, nal_size;
1259  int nal_type = -1;
1260  int tx_size = 0;
1261  int send_size = 0;
1262  int new_packet = 0;
1263  int saved_prev_size = 0;
1264  int32_t frame_num = -1, curr_frame_num;
1265  unsigned int first_mb_in_slice = 0;
1266  ni_logan_packet_t * p_in_pkt = &(p_in_data->data.packet);
1268 
1269  ni_log(NI_LOG_TRACE, "===> %s <===\n", __FUNCTION__);
1270 
1271  if (p_device_state->dec_eos_sent)
1272  {
1273  ni_log(NI_LOG_TRACE, "%s: ALL data (incl. eos) sent already!\n", __FUNCTION__);
1274  LRETURN;
1275  }
1276 
1277  // demo usage of ni_device_dec_session_flush()
1278  if (dec_flush_cnt > 0 && dec_flush_pkt == p_dec_ctx->pkt_num)
1279  {
1280  ni_log(NI_LOG_INFO, "calling ni_device_dec_session_flush() at packet "
1281  "%" PRId64 "\n", p_dec_ctx->pkt_num);
1283  {
1284  ni_log(NI_LOG_ERROR, "%s: mid-flush failed!\n", __FUNCTION__);
1285  exit(-1);
1286  }
1287  dec_flush_cnt--;
1288  }
1289 
1290  if (0 == p_in_pkt->data_len)
1291  {
1292  memset(p_in_pkt, 0, sizeof(ni_logan_packet_t));
1293 
1294  if (NI_LOGAN_CODEC_FORMAT_H264 == p_dec_ctx->codec_format)
1295  {
1296  // send whole encoded packet which ends with a slice NAL
1297  while ((nal_size = find_h264_next_nalu(tmp_buf_ptr, &nal_type)) > 0)
1298  {
1299  frame_pkt_size += nal_size;
1300  tmp_buf_ptr += nal_size;
1301  ni_log(NI_LOG_TRACE, "%s nal %d nal_size %d\n", __FUNCTION__,
1302  nal_type, nal_size);
1303 
1304  // save parsed out sps/pps as stream headers in the decode session
1305  if (NI_LOGAN_H264_NAL_PPS == nal_type)
1306  {
1308  p_dec_ctx, tmp_buf, frame_pkt_size))
1309  {
1310  ni_log(NI_LOG_ERROR, "%s: save_hdr failed!\n", __FUNCTION__);
1311  }
1312  }
1313 
1314  if (NI_LOGAN_H264_NAL_SLICE == nal_type || NI_LOGAN_H264_NAL_IDR_SLICE == nal_type)
1315  {
1316  if (! parse_h264_slice_header(tmp_buf_ptr - nal_size, nal_size, sps,
1317  &curr_frame_num, &first_mb_in_slice))
1318  {
1319  if (-1 == frame_num)
1320  {
1321  // first slice, continue to check
1322  frame_num = curr_frame_num;
1323  }
1324  else if (curr_frame_num != frame_num || 0 == first_mb_in_slice)
1325  {
1326  // this slice has diff. frame_num or first_mb_in_slice addr is
1327  // 0: not the same frame and return
1328  rewind_data_buf_pos_by(nal_size);
1329  frame_pkt_size -= nal_size;
1330  break;
1331  }
1332  // this slice is in the same frame, so continue to check and see
1333  // if there is more
1334  }
1335  else
1336  {
1337  ni_log(NI_LOG_ERROR, "%s: parse_slice_header error NAL type %d "
1338  "size %d, continue\n", __FUNCTION__, nal_type, nal_size);
1339  }
1340  }
1341  else if (-1 != frame_num)
1342  {
1343  // already got a slice and this is non-slice NAL: return
1344  rewind_data_buf_pos_by(nal_size);
1345  frame_pkt_size -= nal_size;
1346  break;
1347  }
1348  // otherwise continue until a slice is found
1349  } // while there is still NAL
1350  }
1351  else
1352  {
1353  frame_pkt_size = chunk_size = read_next_chunk(tmp_buf, packet_size);
1354  }
1355  ni_log(NI_LOG_TRACE, "%s * frame_pkt_size %d\n", __FUNCTION__, frame_pkt_size);
1356 
1357  p_in_pkt->p_data = NULL;
1358  p_in_pkt->data_len = frame_pkt_size;
1359 
1360  if (frame_pkt_size + p_dec_ctx->prev_size > 0)
1361  {
1362  ni_logan_packet_buffer_alloc(p_in_pkt, frame_pkt_size + p_dec_ctx->prev_size);
1363  }
1364 
1365  new_packet = 1;
1366  send_size = frame_pkt_size + p_dec_ctx->prev_size;
1367  saved_prev_size = p_dec_ctx->prev_size;
1368  }
1369  else
1370  {
1371  send_size = p_in_pkt->data_len;
1372  }
1373 
1374  p_in_pkt->start_of_stream = sos_flag;
1375  p_in_pkt->end_of_stream = 0;
1376  p_in_pkt->video_width = input_video_width;
1377  p_in_pkt->video_height = input_video_height;
1378  if (sos_flag)
1379  {
1380  sos_flag = 0;
1381  }
1382 
1383  if (send_size == 0)
1384  {
1385  if (new_packet)
1386  {
1387  send_size = ni_logan_packet_copy(p_in_pkt->p_data, tmp_buf, 0,
1388  p_dec_ctx->p_leftover, &p_dec_ctx->prev_size);
1389  // todo save offset
1390  }
1391  p_in_pkt->data_len = send_size;
1392 
1393  if (--g_file_loop > 0)
1394  {
1396  return 0;
1397  }
1398  else
1399  {
1400  p_in_pkt->end_of_stream = 1;
1401  ni_log(NI_LOG_TRACE, "%s sending p_last packet (size %d) + eos\n",
1402  __FUNCTION__, p_in_pkt->data_len);
1403  }
1404  }
1405  else
1406  {
1407  if (new_packet)
1408  {
1409  send_size = ni_logan_packet_copy(p_in_pkt->p_data, tmp_buf, frame_pkt_size,
1410  p_dec_ctx->p_leftover, &p_dec_ctx->prev_size);
1411  // todo: update offset with send_size
1412  // p_in_pkt->data_len is the actual packet size to be sent to decoder
1413  p_in_pkt->data_len += saved_prev_size;
1414  }
1415  }
1416 
1417  if (dec_flush_cnt > 0 || dec_flush_sec > 0) {
1418  // send packet to decoder, with stream headers being scanned/saved if
1419  // available, in this API call
1420  tx_size = ni_logan_device_dec_session_write(p_dec_ctx, p_in_data);
1421  } else {
1422  // send packet to decoder *without* scanning/saving stream headers in the API
1423  // call: it's done by ni_logan_device_dec_session_save_hdrs separately
1424  tx_size = ni_logan_device_session_write(p_dec_ctx, p_in_data,
1426  }
1427 
1428  if (tx_size < 0)
1429  {
1430  // Error
1431  fprintf(stderr, "Error: sending data error. rc:%d\n", tx_size);
1432  retval = NI_LOGAN_RETCODE_FAILURE;
1433  LRETURN;
1434  }
1435  else if (tx_size == 0)
1436  {
1437  ni_log(NI_LOG_TRACE, "0 byte sent this time, sleep and will re-try.\n");
1438  ni_logan_usleep(10000);
1439  }
1440  else if (tx_size < send_size)
1441  {
1442  if (print_time)
1443  {
1444  //printf("Sent %d < %d , re-try next time ?\n", tx_size, send_size);
1445  }
1446  }
1447 
1448  *total_bytes_sent += tx_size;
1449 
1450  if (p_dec_ctx->ready_to_close)
1451  {
1452  p_device_state->dec_eos_sent = 1;
1453  }
1454 
1455  if (print_time)
1456  {
1457  printf("%s: success, total sent: %ld\n", __FUNCTION__, *total_bytes_sent);
1458  }
1459 
1460  if (tx_size > 0)
1461  {
1462  ni_log(NI_LOG_TRACE, "%s: reset packet_buffer.\n", __FUNCTION__);
1463  ni_logan_packet_buffer_free(p_in_pkt);
1464  }
1465 
1466  retval = NI_LOGAN_RETCODE_SUCCESS;
1467 
1468  END:
1469 
1470  return retval;
1471 
1472 }
1473 
1474 /*!*****************************************************************************
1475  * \brief Receive decoded output data from decoder
1476  *
1477  * \param
1478  *
1479  * \return 0: got YUV frame; 1: end-of-stream; 2: got nothing
1480  ******************************************************************************/
1482  ni_logan_session_data_io_t* p_out_data,
1483  int output_video_width,
1484  int output_video_height,
1485  FILE* p_file,
1486  unsigned long long *total_bytes_received,
1487  int print_time,
1488  device_state_t *p_device_state)
1489 {
1490 
1491  int rc = NI_LOGAN_RETCODE_FAILURE;
1492  int end_flag = 0;
1493  int rx_size = 0;
1494  ni_logan_frame_t * p_out_frame = &(p_out_data->data.frame);
1495  int width, height;
1496 
1497  ni_log(NI_LOG_TRACE, "===> %s <===\n", __FUNCTION__);
1498 
1499  if (p_device_state->dec_eos_received)
1500  {
1501  ni_log(NI_LOG_TRACE, "%s eos received already, Done!\n", __FUNCTION__);
1502  rc = 2;
1503  LRETURN;
1504  }
1505 
1506  // prepare memory buffer for receiving decoded frame
1507  width = p_dec_ctx->active_video_width > 0 ?
1508  p_dec_ctx->active_video_width : output_video_width;
1509  height = p_dec_ctx->active_video_height > 0 ?
1510  p_dec_ctx->active_video_height : output_video_height;
1511 
1512  // allocate memory only after resolution is known (for buffer pool set up)
1513  int alloc_mem = (p_dec_ctx->active_video_width > 0 &&
1514  p_dec_ctx->active_video_height > 0 ? 1 : 0);
1516  p_dec_ctx->dec_fme_buf_pool, &(p_out_data->data.frame), alloc_mem,
1517  width, height,
1519  p_dec_ctx->bit_depth_factor);
1520 
1521  if (NI_LOGAN_RETCODE_SUCCESS != rc)
1522  {
1523  LRETURN;
1524  }
1525 
1526  rx_size = ni_logan_device_session_read(p_dec_ctx, p_out_data,
1528 
1529  end_flag = p_out_frame->end_of_stream;
1530 
1531  if (rx_size < 0)
1532  {
1533  // Error
1534  fprintf(stderr, "Error: receiving data error. rc:%d\n", rx_size);
1537  LRETURN;
1538  }
1539  else if (rx_size > 0)
1540  {
1541  number_of_frames++;
1542  ni_log(NI_LOG_TRACE, "Got frame # %"PRIu64" bytes %d\n",
1543  p_dec_ctx->frame_num, rx_size);
1544 
1545  ni_logan_dec_retrieve_aux_data(p_out_frame);
1546  }
1547  // rx_size == 0 means no decoded frame is available now
1548 
1549  if (rx_size > 0 && p_file)
1550  {
1551  int i, j;
1552  for (i = 0; i < 3; i++)
1553  {
1554  uint8_t *src = p_out_frame->p_data[i];
1555  int plane_height = p_dec_ctx->active_video_height;
1556  int plane_width = p_dec_ctx->active_video_width;
1557  int write_height = output_video_height;
1558  int write_width = output_video_width;
1559  if (i == 1 || i == 2)
1560  {
1561  plane_height /= 2;
1562  plane_width /= 2;
1563  write_height /= 2;
1564  write_width /= 2;
1565  }
1566 
1567  // support for 8/10 bit depth
1568  plane_width *= p_dec_ctx->bit_depth_factor;
1569  write_width *= p_dec_ctx->bit_depth_factor;
1570 
1571  // apply the cropping windown in writing out the YUV frame
1572  // for now the windown is usually crop-left = crop-top = 0, and we use
1573  // this to simplify the cropping logic
1574  for (j = 0; j < plane_height; j++)
1575  {
1576  if (j < write_height && fwrite(src, write_width, 1, p_file) != 1)
1577  {
1578  fprintf(stderr, "Error: writing data plane %d: height %d error!\n",
1579  i, plane_height);
1580  fprintf(stderr, "Error: ferror rc = %d\n", ferror(p_file));
1581  }
1582  src += plane_width;
1583  }
1584  }
1585  if (fflush(p_file))
1586  {
1587  fprintf(stderr, "Error: writing data frame flush failed! errno %d\n", errno);
1588  }
1589  }
1590 
1591  *total_bytes_received += rx_size;
1592 
1593  if (print_time)
1594  {
1595  printf("[R] Got:%d Frames= %u fps=%lu Total bytes %llu\n", rx_size,
1596  number_of_frames, (unsigned long) (number_of_frames/
1597  (current_time.tv_sec - start_time.tv_sec)),
1598  (unsigned long long) *total_bytes_received);
1599  }
1600 
1601  if (end_flag)
1602  {
1603  printf("Decoder Receiving done.\n");
1604  p_device_state->dec_eos_received = 1;
1605  rc = 1;
1606  }
1607  else if (0 == rx_size)
1608  {
1609  rc = 2;
1610  }
1611 
1612  ni_log(NI_LOG_TRACE, "%s: success\n", __FUNCTION__);
1613 
1614  END:
1615 
1616  return rc;
1617 }
1618 
1619 /*!*****************************************************************************
1620  * \brief Send encoder input data, read from input file
1621  *
1622  * \param
1623  *
1624  * \return
1625  ******************************************************************************/
1627  ni_logan_session_data_io_t* p_in_data,
1628  int input_video_width,
1629  int input_video_height,
1630  unsigned long *bytes_sent,
1631  device_state_t *p_device_state)
1632 {
1633  static uint8_t tmp_buf[MAX_YUV_FRAME_SIZE];
1634  volatile static int started = 0;
1635  volatile static int need_to_resend = 0;
1636  int chunk_size;
1637  int oneSent;
1638  int ret;
1639  ni_logan_encoder_params_t *p_param =
1641  ni_logan_frame_t * p_in_frame = &(p_in_data->data.frame);
1642 
1643  ni_log(NI_LOG_TRACE, "===> %s <===\n", __FUNCTION__);
1644 
1645  if (p_device_state->enc_eos_sent == 1)
1646  {
1647  ni_log(NI_LOG_TRACE, "%s: ALL data (incl. eos) sent already!\n", __FUNCTION__);
1648  return 0;
1649  }
1650 
1651  if (need_to_resend)
1652  {
1653  goto send_frame;
1654  }
1655 
1656  int video_width = NI_LOGAN_ODD2EVEN(input_video_width);
1657  int video_height = NI_LOGAN_ODD2EVEN(input_video_height);
1658 
1659  //Y data size
1660  int frame_size = input_video_width * input_video_height * p_enc_ctx->bit_depth_factor;
1661  //U and V data size
1662  frame_size += (video_width / 2) * (video_height / 2) * 2 * p_enc_ctx->bit_depth_factor;
1663 
1664  chunk_size = read_next_chunk(tmp_buf, frame_size);
1665 
1666  p_in_frame->start_of_stream = 0;
1667  if (! started)
1668  {
1669  started = 1;
1670  p_in_frame->start_of_stream = 1;
1671  }
1672  p_in_frame->end_of_stream = 0;
1673  p_in_frame->force_key_frame = 0;
1674  if (chunk_size == 0)
1675  {
1676  p_in_frame->end_of_stream = 1;
1677  ni_log(NI_LOG_TRACE, "%s: read chunk size 0, eos!\n", __FUNCTION__);
1678  }
1679  p_in_frame->video_width = video_width;
1680  p_in_frame->video_height = video_height;
1681 
1682  p_in_frame->ni_logan_pict_type = 0;
1683  p_in_frame->roi_len = 0;
1684  p_in_frame->reconf_len = 0;
1685  p_in_frame->force_pic_qp = 0;
1686  // only metadata header for now
1687  p_in_frame->extra_data_len = NI_LOGAN_APP_ENC_FRAME_META_DATA_SIZE;
1688 
1689  // NETINT_INTERNAL - currently only for internal testing
1690  if (p_param->reconf_demo_mode)
1691  {
1692  ret = ni_logan_enc_fill_reconfig_params(p_param, p_enc_ctx,
1693  p_in_frame, g_reconfigCount);
1694  if (ret < 0)
1695  {
1696  return ret;
1697  }
1698  else
1699  {
1700  g_reconfigCount = ret;
1701  }
1702  }
1703 
1704  uint8_t mdcv_data[NI_LOGAN_MAX_SEI_DATA];
1705  uint8_t cll_data[NI_LOGAN_MAX_SEI_DATA];
1706  uint8_t cc_data[NI_LOGAN_MAX_SEI_DATA];
1707  uint8_t udu_data[NI_LOGAN_MAX_SEI_DATA];
1708  uint8_t hdrp_data[NI_LOGAN_MAX_SEI_DATA];
1709  ni_logan_frame_t dec_frame = {0};
1710 
1711  ni_logan_enc_prep_aux_data(p_enc_ctx, p_in_frame, &dec_frame,
1712  p_enc_ctx->codec_format, 1,
1713  mdcv_data, cll_data, cc_data, udu_data, hdrp_data);
1714  if (p_in_frame->sei_total_len > NI_LOGAN_ENC_MAX_SEI_BUF_SIZE)
1715  {
1716  ni_log(NI_LOG_ERROR, "%s: sei total length %u exceeds maximum sei "
1717  "size %u.\n", __FUNCTION__, p_in_frame->sei_total_len,
1719 
1720  return -1;
1721  }
1722 
1723  p_in_frame->extra_data_len += p_in_frame->sei_total_len;
1724  // FW layout requirement: leave space for reconfig data if SEI and/or ROI
1725  // is present
1726  if ((p_in_frame->sei_total_len ||
1727  p_in_frame->roi_len)
1728  && !p_in_frame->reconf_len)
1729  {
1730  p_in_frame->extra_data_len += sizeof(ni_logan_encoder_change_params_t);
1731  }
1732 
1733  int dst_stride[NI_LOGAN_MAX_NUM_DATA_POINTERS] = {0};
1734  int dst_height_aligned[NI_LOGAN_MAX_NUM_DATA_POINTERS] = {0};
1735  ni_logan_get_hw_yuv420p_dim(video_width, video_height,
1736  p_enc_ctx->bit_depth_factor,
1738  dst_stride, dst_height_aligned);
1739 
1740  ni_logan_encoder_frame_buffer_alloc(p_in_frame, video_width,
1741  video_height,
1742  dst_stride,
1744  p_in_frame->extra_data_len,
1745  p_enc_ctx->bit_depth_factor);
1746  if (! p_in_frame->p_data[0])
1747  {
1748  fprintf(stderr, "Error: could not allocate YUV frame buffer!");
1749  return -1;
1750  }
1751 
1752  ni_log(NI_LOG_TRACE, "p_dst alloc linesize = %d/%d/%d src height=%d "
1753  "dst height aligned = %d/%d/%d \n",
1754  dst_stride[0], dst_stride[1], dst_stride[2], input_video_height,
1755  dst_height_aligned[0], dst_height_aligned[1], dst_height_aligned[2]);
1756 
1757  uint8_t *p_src[NI_LOGAN_MAX_NUM_DATA_POINTERS] = { NULL };
1758  int src_stride[NI_LOGAN_MAX_NUM_DATA_POINTERS] = { 0 };
1759  int src_height[NI_LOGAN_MAX_NUM_DATA_POINTERS] = { 0 };
1760 
1761  src_stride[0] = input_video_width * p_enc_ctx->bit_depth_factor;
1762  src_stride[1] =
1763  src_stride[2] = video_width / 2 * p_enc_ctx->bit_depth_factor;
1764  src_height[0] = input_video_height;
1765  src_height[1] =
1766  src_height[2] = video_height / 2;
1767  p_src[0] = tmp_buf;
1768  p_src[1] = tmp_buf + src_stride[0] * src_height[0];
1769  p_src[2] = p_src[1] + src_stride[1] * src_height[1];
1770 
1771  ni_logan_copy_hw_yuv420p((uint8_t **)(p_in_frame->p_data), p_src,
1772  input_video_width, input_video_height,
1773  p_enc_ctx->bit_depth_factor,
1774  dst_stride, dst_height_aligned,
1775  src_stride, src_height);
1776 
1777  ni_logan_enc_copy_aux_data(p_enc_ctx, p_in_frame, &dec_frame,
1778  p_enc_ctx->codec_format, mdcv_data, cll_data,
1779  cc_data, udu_data, hdrp_data);
1780  ni_logan_frame_buffer_free(&dec_frame);
1781 
1782 send_frame: oneSent = ni_logan_device_session_write(
1783  p_enc_ctx, p_in_data, NI_LOGAN_DEVICE_TYPE_ENCODER);
1784  if (oneSent < 0)
1785  {
1786  fprintf(stderr, "Error: failed ni_logan_device_session_write() for encoder\n");
1787  need_to_resend = 1;
1788  return -1;
1789  }
1790  else if (oneSent == 0 && ! p_enc_ctx->ready_to_close)
1791  {
1792  need_to_resend = 1;
1793  }
1794  else
1795  {
1796  need_to_resend = 0;
1797 
1798  *bytes_sent += p_in_frame->data_len[0] + p_in_frame->data_len[1] +
1799  p_in_frame->data_len[2];
1800  ni_log(NI_LOG_TRACE, "%s: total sent data size=%lu\n",
1801  __FUNCTION__, *bytes_sent);
1802  ni_log(NI_LOG_TRACE, "%s: success\n", __FUNCTION__);
1803 
1804  if (p_enc_ctx->ready_to_close)
1805  {
1806  p_device_state->enc_eos_sent = 1;
1807  }
1808 
1809  }
1810 
1811  return 0;
1812 }
1813 
1814 /*******************************************************************************
1815  * @brief Send encoder input data, directly after receiving from decoder
1816  *
1817  * @param p_enc_ctx encoder context
1818  * p_dec_ctx decoder context
1819  * p_dec_out_data frame returned by decoder
1820  * p_enc_in_data frame to be sent to encoder
1821  *
1822  * @return
1823  ******************************************************************************/
1825  ni_logan_session_context_t* p_dec_ctx,
1826  ni_logan_session_data_io_t* p_dec_out_data,
1827  ni_logan_session_data_io_t* p_enc_in_data,
1828  int input_video_width, int input_video_height,
1829  unsigned long *bytes_sent,
1830  device_state_t *p_device_state)
1831 {
1832  volatile static int started = 0;
1833  volatile static int need_to_resend_2 = 0;
1834  int oneSent;
1835  // pointer to data struct to be sent
1836  ni_logan_session_data_io_t* p_to_send = NULL;
1837  // frame pointer to data frame struct to be sent
1838  ni_logan_frame_t * p_in_frame = NULL;
1839  ni_logan_encoder_params_t *api_params =
1841 
1842  ni_log(NI_LOG_TRACE, "===> %s <===\n", __FUNCTION__);
1843 
1844  if (p_device_state->enc_eos_sent == 1)
1845  {
1846  ni_log(NI_LOG_TRACE, "%s: ALL data (incl. eos) sent already!\n", __FUNCTION__);
1847  return 1;
1848  }
1849 
1850  if (need_to_resend_2)
1851  {
1852  goto send_frame;
1853  }
1854 
1855  // if the source and target are of the same codec type, AND there is no
1856  // other aux data such as close caption, HDR10 etc, AND no padding required
1857  // (e.g. in the case of 32x32 transcoding that needs padding to 256x128),
1858  // then reuse the YUV frame data layout passed in because it's already in
1859  // the required format
1860  if (p_enc_ctx->codec_format == p_dec_ctx->codec_format &&
1861  input_video_width >= NI_LOGAN_MIN_WIDTH &&
1862  input_video_height >= NI_LOGAN_MIN_HEIGHT &&
1863  ! p_dec_out_data->data.frame.sei_hdr_content_light_level_info_len &&
1865  ! p_dec_out_data->data.frame.sei_hdr_plus_len &&
1866  ! p_dec_out_data->data.frame.sei_cc_len &&
1867  ! p_dec_out_data->data.frame.sei_user_data_unreg_len &&
1868  ! p_dec_out_data->data.frame.roi_len)
1869  {
1870  ni_log(NI_LOG_TRACE, "%s: encoding to the same codec format as the "
1871  "source: %d, NO SEI, reusing the frame struct!\n",
1872  __FUNCTION__, p_enc_ctx->codec_format);
1873  p_to_send = p_dec_out_data;
1874  p_in_frame = &(p_to_send->data.frame);
1875 
1876  p_in_frame->force_key_frame = 0;
1877 
1878  p_in_frame->sei_total_len
1879  = p_in_frame->sei_cc_offset = p_in_frame->sei_cc_len
1884  = p_in_frame->sei_hdr_plus_offset
1885  = p_in_frame->sei_hdr_plus_len = 0;
1886 
1887  p_in_frame->roi_len = 0;
1888  p_in_frame->reconf_len = 0;
1889  p_in_frame->force_pic_qp = 0;
1891  p_in_frame->ni_logan_pict_type = 0;
1892  }
1893  else
1894  {
1895  // otherwise have to pad/crop the source and copy to a new frame struct
1896  // and prep for the SEI aux data
1897  p_to_send = p_enc_in_data;
1898  p_in_frame = &(p_to_send->data.frame);
1900  p_in_frame->end_of_stream = p_dec_out_data->data.frame.end_of_stream;
1901  p_in_frame->ni_logan_pict_type = 0;
1902 
1903  p_in_frame->roi_len = 0;
1904  p_in_frame->reconf_len = 0;
1905  p_in_frame->force_pic_qp = 0;
1906 
1907  // NETINT_INTERNAL - currently only for internal testing
1908  if (api_params->reconf_demo_mode)
1909  {
1910  int ret = ni_logan_enc_fill_reconfig_params(api_params, p_enc_ctx,
1911  p_in_frame, g_reconfigCount);
1912  if (ret < 0)
1913  {
1914  return ret;
1915  }
1916  else
1917  {
1918  g_reconfigCount = ret;
1919  }
1920  }
1921  int dst_stride[NI_LOGAN_MAX_NUM_DATA_POINTERS] = {0};
1922  int dst_height_aligned[NI_LOGAN_MAX_NUM_DATA_POINTERS] = {0};
1923  ni_logan_get_hw_yuv420p_dim(input_video_width, input_video_height,
1924  p_enc_ctx->bit_depth_factor,
1926  dst_stride, dst_height_aligned);
1927 
1928  int should_send_sei_with_frame = ni_logan_should_send_sei_with_frame(
1929  p_enc_ctx, p_in_frame->ni_logan_pict_type, api_params);
1930 
1931  // data buffer for various SEI: HDR mastering display color volume, HDR
1932  // content light level, close caption, User data unregistered, HDR10+ etc.
1933  uint8_t mdcv_data[NI_LOGAN_MAX_SEI_DATA];
1934  uint8_t cll_data[NI_LOGAN_MAX_SEI_DATA];
1935  uint8_t cc_data[NI_LOGAN_MAX_SEI_DATA];
1936  uint8_t udu_data[NI_LOGAN_MAX_SEI_DATA];
1937  uint8_t hdrp_data[NI_LOGAN_MAX_SEI_DATA];
1938 
1939  // prep for auxiliary data (various SEI, ROI) in p_in_frame, based on the
1940  // data returned in decoded frame
1941  ni_logan_enc_prep_aux_data(p_enc_ctx, p_in_frame, &(p_dec_out_data->data.frame),
1942  p_enc_ctx->codec_format, should_send_sei_with_frame,
1943  mdcv_data, cll_data, cc_data, udu_data, hdrp_data);
1944 
1945  p_in_frame->extra_data_len += p_in_frame->sei_total_len;
1946 
1947  // layout requirement: leave space for reconfig data if SEI or ROI present
1948  if ((p_in_frame->sei_total_len || p_in_frame->roi_len) &&
1949  ! p_in_frame->reconf_len)
1950  {
1951  p_in_frame->extra_data_len += sizeof(ni_logan_encoder_change_params_t);
1952  }
1953 
1954  ni_logan_encoder_frame_buffer_alloc(p_in_frame, input_video_width,
1955  input_video_height,
1956  dst_stride,
1958  p_in_frame->extra_data_len,
1959  p_enc_ctx->bit_depth_factor);
1960  if (! p_in_frame->p_data[0])
1961  {
1962  fprintf(stderr, "Error: cannot allocate YUV frame buffer!");
1963  return -1;
1964  }
1965 
1966  ni_log(NI_LOG_TRACE, "p_dst alloc linesize = %d/%d/%d src height=%d "
1967  "dst height aligned = %d/%d/%d force_key_frame=%d, extra_data_len=%d"
1968  " sei_size=%u (hdr_content_light_level %u hdr_mastering_display_"
1969  "color_vol %u hdr10+ %u hrd %u) reconf_size=%u roi_size=%u "
1970  "force_pic_qp=%u udu_sei_size=%u "
1971  "use_cur_src_as_long_term_pic %u use_long_term_ref %u \n",
1972  dst_stride[0], dst_stride[1], dst_stride[2], input_video_height,
1973  dst_height_aligned[0], dst_height_aligned[1], dst_height_aligned[2],
1974  p_in_frame->force_key_frame, p_in_frame->extra_data_len,
1975  p_in_frame->sei_total_len,
1978  p_in_frame->sei_hdr_plus_len, 0, /* hrd is 0 size for now */
1979  p_in_frame->reconf_len, p_in_frame->roi_len,
1980  p_in_frame->force_pic_qp, p_in_frame->sei_user_data_unreg_len,
1981  p_in_frame->use_cur_src_as_long_term_pic,
1982  p_in_frame->use_long_term_ref);
1983 
1984  uint8_t *p_src[NI_LOGAN_MAX_NUM_DATA_POINTERS];
1985  int src_stride[NI_LOGAN_MAX_NUM_DATA_POINTERS];
1986  int src_height[NI_LOGAN_MAX_NUM_DATA_POINTERS];
1987 
1988  src_stride[0] = p_dec_out_data->data.frame.data_len[0] /
1989  p_dec_out_data->data.frame.video_height;
1990  src_stride[1] =
1991  src_stride[2] = src_stride[0] / 2;
1992 
1993  p_src[0] = p_dec_out_data->data.frame.p_data[0];
1994  p_src[1] = p_dec_out_data->data.frame.p_data[1];
1995  p_src[2] = p_dec_out_data->data.frame.p_data[2];
1996  src_height[0] = p_dec_out_data->data.frame.video_height;
1997  src_height[1] =
1998  src_height[2] = src_height[0] / 2;
1999 
2000  // YUV part of the encoder input data layout
2001  ni_logan_copy_hw_yuv420p((uint8_t **)(p_in_frame->p_data), p_src,
2002  input_video_width, input_video_height,
2003  p_enc_ctx->bit_depth_factor,
2004  dst_stride, dst_height_aligned,
2005  src_stride, src_height);
2006 
2007  // auxiliary data part of the encoder input data layout
2008  ni_logan_enc_copy_aux_data(p_enc_ctx, p_in_frame, &(p_dec_out_data->data.frame),
2009  p_enc_ctx->codec_format, mdcv_data, cll_data, cc_data,
2010  udu_data, hdrp_data);
2011  }
2012 
2013  p_in_frame->video_width = input_video_width;
2014  p_in_frame->video_height = input_video_height;
2015 
2016  p_in_frame->start_of_stream = 0;
2017  if (! started)
2018  {
2019  started = 1;
2020  p_in_frame->start_of_stream = 1;
2021  }
2022  // p_in_frame->end_of_stream = 0;
2023 
2024 send_frame:
2025  oneSent = p_in_frame->data_len[0] + p_in_frame->data_len[1] +
2026  p_in_frame->data_len[2];
2027 
2028  if (oneSent > 0 || p_in_frame->end_of_stream)
2029  {
2030  oneSent = ni_logan_device_session_write(p_enc_ctx, p_to_send, NI_LOGAN_DEVICE_TYPE_ENCODER);
2031  p_in_frame->end_of_stream = 0;
2032  }
2033  else
2034  {
2035  goto end_encoder_send_data2;
2036  }
2037 
2038  if (oneSent < 0) {
2039  fprintf(stderr, "Error: %s\n", __FUNCTION__);
2040  need_to_resend_2 = 1;
2041  return -1;
2042  }
2043  else if (oneSent == 0)
2044  {
2045  if (p_device_state->enc_eos_sent == 0 && p_enc_ctx->ready_to_close)
2046  {
2047  need_to_resend_2 = 0;
2048  p_device_state->enc_eos_sent = 1;
2049  }
2050  else
2051  {
2052  need_to_resend_2 = 1;
2053  }
2054  }
2055  else
2056  {
2057  need_to_resend_2 = 0;
2058  if (p_enc_ctx->ready_to_close)
2059  {
2060  p_device_state->enc_eos_sent = 1;
2061  }
2062  ni_log(NI_LOG_TRACE, "%s: success\n", __FUNCTION__);
2063  }
2064 
2065 end_encoder_send_data2:
2066  return 0;
2067 }
2068 
2069 
2070 /*!*****************************************************************************
2071  * \brief Receive output data from encoder
2072  *
2073  * \param
2074  *
2075  * \return
2076  ******************************************************************************/
2078  ni_logan_session_data_io_t* p_out_data,
2079  int output_video_width, int output_video_height,
2080  FILE* p_file,
2081  unsigned long long *total_bytes_received,
2082  int print_time)
2083 {
2084  int packet_size = NI_LOGAN_MAX_TX_SZ;
2085  int rc = 0;
2086  int end_flag = 0;
2087  int rx_size = 0;
2088  ni_logan_packet_t * p_out_pkt = &(p_out_data->data.packet);
2090 
2091  ni_log(NI_LOG_TRACE, "===> %s <===\n", __FUNCTION__);
2092 
2093  if (NI_LOGAN_INVALID_SESSION_ID == p_enc_ctx->session_id ||
2094  NI_INVALID_DEVICE_HANDLE == p_enc_ctx->blk_io_handle)
2095  {
2096  ni_log(NI_LOG_TRACE, "encode session not opened yet, return\n");
2097  return 0;
2098  }
2099 
2100  ni_logan_packet_buffer_alloc(p_out_pkt, packet_size);
2101 
2102 receive_data: rc = ni_logan_device_session_read(p_enc_ctx, p_out_data,
2104 
2105  end_flag = p_out_pkt->end_of_stream;
2106  rx_size = rc;
2107 
2108  ni_log(NI_LOG_TRACE, "%s: received data size=%d\n", __FUNCTION__, rx_size);
2109 
2110  if (rx_size > meta_size)
2111  {
2112  if (p_file && (fwrite((uint8_t*)p_out_pkt->p_data + meta_size,
2113  p_out_pkt->data_len - meta_size, 1, p_file) != 1))
2114  {
2115  fprintf(stderr, "Error: writing data %d bytes error!\n",
2116  p_out_pkt->data_len - meta_size);
2117  fprintf(stderr, "Error: ferror rc = %d\n", ferror(p_file));
2118  }
2119 
2120  *total_bytes_received += rx_size - meta_size;
2121 
2122  if (0 == p_enc_ctx->pkt_num)
2123  {
2124  p_enc_ctx->pkt_num = 1;
2125  ni_log(NI_LOG_TRACE, "got encoded stream header, keep reading ..\n");
2126  goto receive_data;
2127  }
2129 
2130  ni_log(NI_LOG_TRACE, "Got: Packets= %u\n", number_of_packets);
2131  }
2132  else if (rx_size != 0)
2133  {
2134  fprintf(stderr, "Error: received %d bytes, <= metadata size %d!\n",
2135  rx_size, meta_size);
2136  }
2137  else if (rx_size == 0 && ! end_flag && ((ni_logan_encoder_params_t*)(
2138  p_enc_ctx->p_session_config))->low_delay_mode == 1)
2139  {
2140  ni_log(NI_LOG_TRACE, "low delay mode and NO pkt, keep reading ..\n");
2141  goto receive_data;
2142  }
2143 
2144  if (print_time)
2145  {
2146  int timeDiff = current_time.tv_sec - start_time.tv_sec;
2147  if (timeDiff == 0)
2148  {
2149  timeDiff = 1;
2150  }
2151  printf("[R] Got:%d Packets= %u fps=%d Total bytes %lld\n",
2152  rx_size, number_of_packets, number_of_packets/timeDiff,
2153  *total_bytes_received);
2154  }
2155 
2156  if (end_flag)
2157  {
2158  printf("Encoder Receiving done.\n");
2159  return 1;
2160  }
2161 
2162  ni_log(NI_LOG_TRACE, "%s: success\n", __FUNCTION__);
2163 
2164  return 0;
2165 }
2166 
2167 /*!*****************************************************************************
2168  * \brief Encoder session open
2169  *
2170  * \param [out] p_enc_ctx pointer to an encoder session context
2171  * [in] dst_codec_format AVC or HEVC
2172  *
2173  * \return 0 if successful, < 0 otherwise
2174  ******************************************************************************/
2176  int dst_codec_format, int xcoder_id,
2177  const char *xcoder_name,
2178  ni_logan_encoder_params_t *p_enc_params,
2179  int src_bit_depth, int width, int height,
2180  ni_color_primaries_t color_primaries,
2182  ni_color_space_t color_space,
2183  int video_full_range_flag,
2184  int sar_num, int sar_den)
2185 {
2186  int ret = 0;
2187 
2188  p_enc_ctx->p_session_config = p_enc_params;
2190  p_enc_ctx->codec_format = dst_codec_format;
2191 
2192  // assign the card GUID in the encoder context and let session open
2193  // take care of the rest
2194  p_enc_ctx->device_handle = NI_INVALID_DEVICE_HANDLE;
2195  p_enc_ctx->blk_io_handle = NI_INVALID_DEVICE_HANDLE;
2196  p_enc_ctx->hw_id = xcoder_id;
2197  p_enc_ctx->hw_name = xcoder_name;
2198 
2199  // default: little endian
2200  p_enc_ctx->src_bit_depth = src_bit_depth;
2202  p_enc_ctx->bit_depth_factor = 1;
2203  if (10 == p_enc_ctx->src_bit_depth)
2204  {
2205  p_enc_ctx->bit_depth_factor = 2;
2206  }
2207 
2208  width = NI_LOGAN_ODD2EVEN(width);
2209  height = NI_LOGAN_ODD2EVEN(height);
2210 
2211  int linesize_aligned = ((width + 7) / 8) * 8;
2212  if (p_enc_ctx->codec_format == NI_LOGAN_CODEC_FORMAT_H264)
2213  {
2214  linesize_aligned = ((width + 15) / 16) * 16;
2215  }
2216  if (linesize_aligned < NI_LOGAN_MIN_WIDTH)
2217  {
2218  p_enc_params->enc_input_params.conf_win_right += NI_LOGAN_MIN_WIDTH - width;
2219  linesize_aligned = NI_LOGAN_MIN_WIDTH;
2220  }
2221  else if (linesize_aligned > width)
2222  {
2223  p_enc_params->enc_input_params.conf_win_right += linesize_aligned - width;
2224  }
2225  p_enc_params->source_width = linesize_aligned;
2226 
2227  int height_aligned = ((height + 7) / 8) * 8;
2228  if (p_enc_ctx->codec_format == NI_LOGAN_CODEC_FORMAT_H264)
2229  {
2230  height_aligned = ((height + 15) / 16) * 16;
2231  }
2232  if (height_aligned < NI_LOGAN_MIN_HEIGHT)
2233  {
2234  p_enc_params->enc_input_params.conf_win_bottom += NI_LOGAN_MIN_HEIGHT - height;
2235  height_aligned = NI_LOGAN_MIN_HEIGHT;
2236  }
2237  else if (height_aligned > height)
2238  {
2239  p_enc_params->enc_input_params.conf_win_bottom += height_aligned - height;
2240  }
2241  p_enc_params->source_height = height_aligned;
2242 
2243  // VUI setting including color setting
2244  ni_logan_set_vui(p_enc_params, p_enc_ctx, color_primaries, color_trc, color_space,
2245  video_full_range_flag, sar_num, sar_den, dst_codec_format);
2246 
2248  if (ret < 0)
2249  {
2250  fprintf(stderr, "Error: %s failure!\n", __FUNCTION__);
2251  }
2252  else
2253  {
2254  if (xcoder_name != NULL)
2255  {
2256  printf("Encoder device %s session open successful.\n", xcoder_name);
2257  }
2258  else
2259  {
2260  printf("Encoder device %d session open successful.\n", xcoder_id);
2261  }
2262  }
2263 
2264  return ret;
2265 }
2266 
2267 void print_usage(void)
2268 {
2269  printf("Video decoder/encoder/transcoder application directly using Netint Libxcoder API v%s\n"
2270  "Usage: xcoder [options]\n"
2271  "\n"
2272  "options:\n"
2273  "-h | --help Show help.\n"
2274  "-l | --loglevel Set loglevel of libxcoder API.\n"
2275  " [none, fatal, error, info, debug, trace]\n"
2276  " (Default: info)\n"
2277  "-c | --card Set card index to use.\n"
2278  " See `ni_logan_rsrc_mon` for cards on system.\n"
2279  " (Default: 0)\n"
2280  "-n | --devname Specify the xcoder device name to work.\n"
2281  "-i | --input Input file path.\n"
2282  "-s | --size Resolution of input file in format WIDTHxHEIGHT.\n"
2283  " (eg. '1920x1080')\n"
2284  "-m | --mode Input to output codec processing mode in format:\n"
2285  " INTYPE2OUTTYPE. [a2y, h2y, y2a, y2h, a2a, a2h, h2a, h2h]\n"
2286  " Type notation: y=YUV420P a=AVC, h=HEVC\n"
2287  "-b | --bitdepth Input and output bit depth. [8, 10]\n"
2288  " (Default: 8)\n"
2289  "-x | --xcoder-params Encoding params. See \"Encoding Parameters\" chapter in\n"
2290  " IntegrationProgrammingGuideT408_T432_FW*.pdf for help.\n"
2291  " (Default: \"\")\n"
2292  "-o | --output Output file path.\n"
2293  "-p | --loop Number of times to repeat input file. (Default: 1)\n"
2294  "-a | --dec_async Decoding in asynchronous multi-threading.\n"
2295  "-e | --enc_async Encoding in asynchronous multi-threading.\n"
2296  "-t | --dec_flush_sec Flush decoder at the specified second\n"
2297  "-f | --dec_flush Flush decoder at the specific packet index. Prefix\n"
2298  " number with 'r' to repeatedly flush at packet period.\n"
2299  " (eg. r20)\n", NI_LOGAN_XCODER_REVISION);
2300 }
2301 
2302 
2303 // retrieve key and value from 'key=value' pair, return 0 if successful
2304 // otherwise non-0
2305 static int get_key_value(char *p_str, char *key, char *value)
2306 {
2307  if (! p_str || ! key || ! value)
2308  {
2309  return 1;
2310  }
2311 
2312  char *p = strchr(p_str, '=');
2313  if (! p)
2314  {
2315  return 1;
2316  }
2317  else
2318  {
2319  *p = '\0';
2320  key[0] = '\0';
2321  value[0] = '\0';
2322  strncat(key, p_str, strlen(p_str));
2323  strncat(value, p+1, strlen(p+1));
2324  return 0;
2325  }
2326 }
2327 
2328 /* Convert string of log_level to log_level integer */
2329 static int32_t log_str_to_level(char *log_str)
2330 {
2331  ni_log_level_t converted_log_level;
2332  size_t i;
2333  for (i = 0; i < strlen(log_str); i++)
2334  log_str[i] = tolower((unsigned char) log_str[i]);
2335 
2336  if (strcmp(log_str, "none") == 0)
2337  converted_log_level = NI_LOG_NONE;
2338  else if (strcmp(log_str, "fatal") == 0)
2339  converted_log_level = NI_LOG_FATAL;
2340  else if (strcmp(log_str, "error") == 0)
2341  converted_log_level = NI_LOG_ERROR;
2342  else if (strcmp(log_str, "info") == 0)
2343  converted_log_level = NI_LOG_INFO;
2344  else if (strcmp(log_str, "debug") == 0)
2345  converted_log_level = NI_LOG_DEBUG;
2346  else if (strcmp(log_str, "trace") == 0)
2347  converted_log_level = NI_LOG_TRACE;
2348  else
2349  converted_log_level = -16;
2350  return converted_log_level;
2351 }
2352 
2353 // retrieve config parameter valus from --xcoder-params,
2354 // return 0 if successful, -1 otherwise
2355 static int retrieve_xcoder_params(char xcoderParams[],
2356  ni_logan_encoder_params_t *params,
2358 {
2359  char key[64], value[64];
2360  char *p = xcoderParams;
2361  char *curr = xcoderParams, *colon_pos;
2362  int ret = 0;
2363 
2364  while (*curr)
2365  {
2366  colon_pos = strchr(curr, ':');
2367 
2368  if (colon_pos)
2369  {
2370  *colon_pos = '\0';
2371  }
2372 
2373  if (strlen(curr) > sizeof(key) + sizeof(value) - 1 ||
2374  get_key_value(curr, key, value))
2375  {
2376  fprintf(stderr, "Error: xcoder-params p_config key/value not "
2377  "retrieved: %s\n", curr);
2378  ret = -1;
2379  break;
2380  }
2381  ret = ni_logan_encoder_params_set_value(params, key, value, ctx);
2382  switch (ret)
2383  {
2385  fprintf(stderr, "Error: unknown option: %s.\n", key);
2386  break;
2388  fprintf(stderr, "Error: invalid value for %s: %s.\n", key, value);
2389  break;
2390  default:
2391  break;
2392  }
2393 
2394  if (NI_LOGAN_RETCODE_SUCCESS != ret)
2395  {
2396  fprintf(stderr, "Error: config parsing failed %d: %s\n", ret,
2397  ni_logan_get_rc_txt(ret));
2398  break;
2399  }
2400 
2401  if (colon_pos)
2402  {
2403  curr = colon_pos + 1;
2404  }
2405  else
2406  {
2407  curr += strlen(curr);
2408  }
2409  }
2410  return ret;
2411 }
2412 
2413 // Decoder send thread
2414 static void *decoder_send_routine(void *arg)
2415 {
2416  dev_send_param_t *p_param = arg;
2417 
2418  for (; ;)
2419  {
2420  int ret = decoder_send_data(p_param->p_ctx, p_param->p_data, p_param->input_video_width,
2421  p_param->input_video_height, p_param->input_size, p_param->p_total_bytes_sent,
2422  p_param->print_time, p_param->p_xcodeState, p_param->p_SPS);
2423  if (ret < 0)
2424  {
2425  ni_log(NI_LOG_ERROR, "Error: %s failed: %x\n", __FUNCTION__, p_param->p_ctx->session_id);
2426  }
2427  else if (p_param->p_xcodeState->dec_eos_sent)
2428  {
2430  break;
2431  }
2432  }
2433 
2434  ni_log(NI_LOG_DEBUG, "Exit %s\n", __FUNCTION__);
2435  return NULL;
2436 }
2437 
2438 // Decoder receive thread
2439 static void *decoder_receive_routine(void *arg)
2440 {
2441  dev_recv_param_t *p_param = arg;
2442  ni_logan_frame_t *p_frm = &p_param->p_data->data.frame;
2443 
2444  for (; ;)
2445  {
2446  int ret = decoder_receive_data(p_param->p_ctx, p_param->p_data,
2447  p_param->output_video_width, p_param->output_video_height,
2448  p_param->p_file, p_param->p_total_bytes_received,
2449  p_param->print_time, p_param->p_xcodeState);
2451  if (ret == 2)
2452  {
2453  // EAGAIN
2454  ni_logan_usleep(1000);
2455  }
2456  else if (ret < 0 || p_frm->end_of_stream)
2457  {
2458  if (ret == 1)
2459  {
2460  // Over.
2461  break;
2462  }
2463  else
2464  {
2465  //ni_log(NI_LOG_ERROR, "Error %s failed: %x\n", __FUNCTION__, p_param->p_ctx->session_id);
2466  }
2467  }
2468  }
2469 
2470  ni_log(NI_LOG_DEBUG, "Exit %s\n", __FUNCTION__);
2471  return NULL;
2472 }
2473 
2474 // Decoder flush thread
2475 static void *decoder_flush_routine(void *arg)
2476 {
2477  dev_send_param_t *p_param = arg;
2478 
2479  while (!flush_fin_flag)
2480  {
2481  ni_logan_usleep(dec_flush_sec * 1000 * 1000);
2482 
2483  int ret = ni_logan_device_dec_session_flush(p_param->p_ctx);
2484  if (ret < 0)
2485  {
2486  ni_log(NI_LOG_ERROR, "Error %s failed: %x\n", __FUNCTION__, p_param->p_ctx->session_id);
2488  break;
2489  }
2490  }
2491 
2493  ni_log(NI_LOG_DEBUG, "Exit %s\n", __FUNCTION__);
2494  return NULL;
2495 }
2496 
2497 // Encoder send thread
2498 static void *encoder_send_routine(void *arg)
2499 {
2500  dev_send_param_t *p_param = arg;
2501 
2502  for (; ;)
2503  {
2504  int ret = encoder_send_data(p_param->p_ctx, p_param->p_data,
2505  p_param->input_video_width, p_param->input_video_height,
2506  p_param->p_total_bytes_sent, p_param->p_xcodeState);
2507  if (ret < 0)
2508  {
2509  ni_log(NI_LOG_ERROR, "Error: %s failed: %x\n", __FUNCTION__, p_param->p_ctx->session_id);
2510  }
2511  else if (p_param->p_xcodeState->enc_eos_sent)
2512  {
2513  // Over
2514  break;
2515  }
2516  }
2517 
2518  ni_log(NI_LOG_DEBUG, "Exit %s\n", __FUNCTION__);
2519  return NULL;
2520 }
2521 
2522 // Encoder receive thread
2523 static void *encoder_receive_routine(void *arg)
2524 {
2525  dev_recv_param_t *p_param = arg;
2526  ni_logan_packet_t *p_pkt = &p_param->p_data->data.packet;
2527 
2528  for (; ;)
2529  {
2530  int ret = encoder_receive_data(p_param->p_ctx, p_param->p_data,
2531  p_param->output_video_width, p_param->output_video_height,
2532  p_param->p_file, p_param->p_total_bytes_received, p_param->print_time);
2533  if (ret)
2534  {
2535  if (ret > 0)
2536  {
2537  // Over.
2538  break;
2539  }
2540  else
2541  {
2542  ni_log(NI_LOG_ERROR, "Error %s failed: %x\n", __FUNCTION__, p_param->p_ctx->session_id);
2543  }
2544  }
2545  }
2546 
2547  ni_log(NI_LOG_DEBUG, "Exit %s\n", __FUNCTION__);
2548  return NULL;
2549 }
2550 
2551 /*!*****************************************************************************
2552  * \brief main
2553  *
2554  * \param
2555  *
2556  * \return
2557  ******************************************************************************/
2558 int main(int argc, char *argv[])
2559 {
2560  tx_data_t sdPara = {0};
2561  rx_data_t rcPara = {0};
2562  device_state_t xcodeState = {0};
2563  int err = 0, pfs = 0, sos_flag = 0, edFlag = 0, bytes_sent = 0;
2564  int xcoder_id = 0;
2565  char xcoder_name[32] = {'\0'};
2566  unsigned long total_bytes_sent;
2567  unsigned long long total_bytes_received;
2568  unsigned long long xcodeRecvTotal;
2569  FILE *p_file = NULL;
2570  char *n; // used for parsing width and height from --size
2571  char mode_description[128];
2572  int input_video_width;
2573  int input_video_height;
2574  int arg_width = 0;
2575  int arg_height = 0;
2576  int mode = -1;
2577  size_t i;
2578  int pkt_size;
2579  int dec_async = 0;
2580  int enc_async = 0;
2581  ni_logan_encoder_params_t enc_api_param;
2582  ni_logan_decoder_params_t dec_api_param;
2583  char encConfXcoderParams[2048] = { 0 };
2584  ni_device_handle_t dev_handle = NI_INVALID_DEVICE_HANDLE, dev_handle_1 = NI_INVALID_DEVICE_HANDLE;
2585  int src_codec_format = 0, dst_codec_format = 0;
2586  ni_log_level_t loglevel = NI_LOG_ERROR;
2587  int bit_depth = 8;
2588  ni_logan_h264_sps_t SPS = {0}; // input header SPS
2589 
2590  // Input arg handling
2591  int opt;
2592  int opt_index;
2593  const char *opt_string = "aehl:c:n:f:i:s:m:b:o:p:t:x:";
2594  static struct option long_options[] =
2595  {
2596  {"help", no_argument, NULL, 'h'},
2597  {"dec_async", no_argument, NULL, 'a'},
2598  {"enc_async", no_argument, NULL, 'e'},
2599  {"loglevel", required_argument, NULL, 'l'},
2600  {"card", required_argument, NULL, 'c'},
2601  {"xcoder_name", required_argument, NULL, 'n'},
2602  {"input", required_argument, NULL, 'i'},
2603  {"size", required_argument, NULL, 's'},
2604  {"mode", required_argument, NULL, 'm'},
2605  {"bitdepth", required_argument, NULL, 'b'},
2606  {"xcoder-params", required_argument, NULL, 'x'},
2607  {"output", required_argument, NULL, 'o'},
2608  {"dec_flush", required_argument, NULL, 'f'},
2609  {"dec_flush_sec", required_argument, NULL, 't'},
2610  {"loop", required_argument, NULL, 'p'},
2611  {NULL, 0, NULL, 0},
2612  };
2613 
2614  while ((opt = getopt_long(argc, argv, opt_string, long_options, &opt_index)) != -1)
2615  {
2616  switch (opt)
2617  {
2618  case 'h':
2619  print_usage();
2620  exit(0);
2621  case 'a':
2622  dec_async = 1;
2623  break;
2624  case 'e':
2625  enc_async = 1;
2626  break;
2627  case 'l':
2628  loglevel = log_str_to_level(optarg);
2629  if (loglevel < NI_LOG_NONE || loglevel > NI_LOG_TRACE)
2630  arg_error_exit("-l | --loglevel", optarg);
2631  ni_log_set_level(loglevel);
2632  break;
2633  case 'c':
2634  xcoder_id = strtol(optarg, &n, 10);
2635  if (n == optarg) // no numeric characters found in left side of optarg
2636  arg_error_exit("-c | --card", optarg);
2637  break;
2638  case 'n':
2639  strcpy(xcoder_name, optarg);
2640  break;
2641  case 'i':
2642  strcpy(sdPara.fileName, optarg);
2643  break;
2644  case 's':
2645  arg_width = (int) strtol(optarg, &n, 10);
2646  arg_height = atoi(n + 1);
2647  if ((*n != 'x') || (!arg_width || !arg_height))
2648  arg_error_exit("-s | --size", optarg);
2649  break;
2650  case 'm':
2651  if (!(strlen(optarg) == 3))
2652  arg_error_exit("-, | --mode", optarg);
2653  // convert to lower case for processing
2654  for (i = 0; i < strlen(optarg); i++)
2655  optarg[i] = tolower((unsigned char) optarg[i]);
2656 
2657  if (strcmp(optarg, "y2a") &&
2658  strcmp(optarg, "y2h") &&
2659  strcmp(optarg, "a2y") &&
2660  strcmp(optarg, "a2a") &&
2661  strcmp(optarg, "a2h") &&
2662  strcmp(optarg, "h2y") &&
2663  strcmp(optarg, "h2a") &&
2664  strcmp(optarg, "h2h"))
2665  arg_error_exit("-, | --mode", optarg);
2666 
2667  // determine dec/enc/xcod mode to use
2668  if (optarg[0] == 'y')
2669  {
2670  sprintf(mode_description, "Encoding");
2671  mode = XCODER_APP_ENCODE;
2672  }
2673  else if (optarg[2] == 'y')
2674  {
2675  sprintf(mode_description, "Decoding");
2676  mode = XCODER_APP_DECODE;
2677  }
2678  else if ((optarg[0] == 'y') && (optarg[2] == 'y'))
2679  {
2680  arg_error_exit("-, | --mode", optarg);
2681  }
2682  else
2683  {
2684  sprintf(mode_description, "Transcoding");
2685  mode = XCODER_APP_TRANSCODE;
2686  }
2687 
2688  // determine codecs to use
2689  if (optarg[0] == 'a')
2690  {
2691  src_codec_format = NI_LOGAN_CODEC_FORMAT_H264;
2692  strcat(mode_description, " from AVC");
2693  }
2694  if (optarg[0] == 'h')
2695  {
2696  src_codec_format = NI_LOGAN_CODEC_FORMAT_H265;
2697  strcat(mode_description, " from HEVC");
2698  }
2699  if (optarg[2] == 'a')
2700  {
2701  dst_codec_format = NI_LOGAN_CODEC_FORMAT_H264;
2702  strcat(mode_description, " to AVC");
2703  }
2704  if (optarg[2] == 'h')
2705  {
2706  dst_codec_format = NI_LOGAN_CODEC_FORMAT_H265;
2707  strcat(mode_description, " to HEVC");
2708  }
2709 
2710  break;
2711  case 'b':
2712  if (!(atoi(optarg) == 8 || atoi(optarg) == 10))
2713  arg_error_exit("-b | --bitdepth", optarg);
2714  bit_depth = atoi(optarg);
2715  break;
2716  case 'p':
2717  g_file_loop = atoi(optarg);
2718  break;
2719  case 'x':
2720  strcpy(encConfXcoderParams, optarg);
2721  break;
2722  case 'o':
2723  strcpy(rcPara.fileName, optarg);
2724  break;
2725  case 't':
2726  dec_flush_sec = atoi(optarg);
2727  if (dec_flush_sec < 0)
2728  arg_error_exit("-t | --dec_flush_sec", optarg);
2729  break;
2730  case 'f':
2731  if (optarg[0] == 'r')
2732  {
2733  dec_flush_cnt = -1;
2734  dec_flush_pkt = atoi(optarg + 1);
2735  }
2736  else
2737  {
2738  dec_flush_cnt = 1;
2739  dec_flush_pkt = atoi(optarg);
2740  }
2741  if (dec_flush_pkt < 0)
2742  arg_error_exit("-f | --dec_flush", optarg);
2743  break;
2744  default:
2745  print_usage();
2746  exit(1);
2747  }
2748  }
2749 
2750  // Check required args are present
2751  if (!sdPara.fileName[0])
2752  {
2753  printf("Error: missing argument for -i | --input\n");
2754  exit(-1);
2755  }
2756  if ((mode != XCODER_APP_TRANSCODE) && (mode != XCODER_APP_DECODE) && (mode != XCODER_APP_ENCODE))
2757  {
2758  printf("Error: missing argument for -m | --mode\n");
2759  exit(-1);
2760  }
2761  if (!rcPara.fileName[0])
2762  {
2763  printf("Error: missing argument for -o | --output\n");
2764  exit(-1);
2765  }
2766 
2767  sdPara.mode = mode;
2768  rcPara.mode = mode;
2769 
2770  // Print high-level description of processing to occur and codecs involved
2771  printf("%s...\n", mode_description);
2772 
2773  pkt_size = 131040; // hardcoded input data chunk size (for H.265)
2774 
2775 
2776 #ifdef _WIN32
2777  pfs = open(sdPara.fileName, O_RDONLY | O_BINARY);
2778 #elif defined(__linux__)
2779  pfs = open(sdPara.fileName, O_RDONLY);
2780 #endif
2781 
2782  if (pfs < 0)
2783  {
2784  fprintf(stderr, "Error: cannot open %s\n", sdPara.fileName);
2785  fprintf(stderr, "Error: input file read failure\n");
2786  err_flag = 1;
2787  goto end;
2788  }
2789  printf("SUCCESS: Opened input file: %s with file id = %d\n", sdPara.fileName, pfs);
2790 
2791  lseek(pfs, 0, SEEK_END);
2792  total_file_size = lseek(pfs, 0, SEEK_CUR);
2793  lseek(pfs, 0, SEEK_SET);
2794  unsigned long tmpFileSize = total_file_size;
2795  // try to allocate memory for input file buffer, quit if failure
2796  if (! (g_file_cache = malloc(total_file_size)))
2797  {
2798  fprintf(stderr, "Error: input file size %lu exceeding max malloc, quit\n",
2799  total_file_size);
2800  goto end;
2801  }
2802  g_curr_cache_pos = g_file_cache;
2803 
2804  printf("Reading %lu bytes in total ..\n", total_file_size);
2805  while (tmpFileSize)
2806  {
2807  uint32_t chunk_size = tmpFileSize > 4096 ? 4096 : tmpFileSize;
2808  int one_read_size = read(pfs, g_curr_cache_pos, tmpFileSize);
2809  if (one_read_size == -1)
2810  {
2811  fprintf(stderr, "Error: reading file, quit! left-to-read %lu\n", tmpFileSize);
2812  goto end;
2813  }
2814  else
2815  {
2816  tmpFileSize -= one_read_size;
2817  g_curr_cache_pos += one_read_size;
2818  }
2819  }
2820  printf("read %lu bytes from input file into memory\n", total_file_size);
2821 
2822  g_curr_cache_pos = g_file_cache;
2824 
2825  if (strcmp(rcPara.fileName, "null"))
2826  {
2827  p_file = fopen(rcPara.fileName, "wb");
2828  if (p_file == NULL)
2829  {
2830  fprintf(stderr, "Error: cannot open %s\n", rcPara.fileName);
2831  err_flag = 1;
2832  goto end;
2833  }
2834  }
2835  printf("SUCCESS: Opened output file: %s\n", rcPara.fileName);
2836 
2837  // for H.264, probe the source and use the probed source info as defaults
2838  if (NI_LOGAN_CODEC_FORMAT_H264 == src_codec_format &&
2839  (mode == XCODER_APP_TRANSCODE || mode == XCODER_APP_DECODE))
2840  {
2841  if (probe_h264_stream_info(&SPS))
2842  {
2843  fprintf(stderr, "ERROR: H.264 file probing complete, source file format "
2844  "not supported !\n");
2845  goto end;
2846  }
2847 
2848  ni_log(NI_LOG_INFO, "Using probed H.264 source info: %d bits "
2849  "resolution %dx%d\n", SPS.bit_depth_luma, SPS.width, SPS.height);
2850  bit_depth = SPS.bit_depth_luma;
2851  arg_width = SPS.width;
2852  arg_height = SPS.height;
2853  }
2854 
2855  sdPara.arg_width = arg_width;
2856  sdPara.arg_height = arg_height;
2857  rcPara.arg_width = arg_width;
2858  rcPara.arg_height = arg_height;
2859 
2860  // set up decoder p_config with some hard coded numbers
2861  if (ni_logan_decoder_init_default_params(&dec_api_param, 25, 1, 200000,
2862  arg_width, arg_height) < 0)
2863  {
2864  fprintf(stderr, "Error: decoder p_config set up error\n");
2865  return -1;
2866  }
2867 
2868  send_fin_flag = 0;
2869  receive_fin_flag = 0;
2870 
2871  ni_logan_session_context_t dec_ctx = {0};
2872  ni_logan_session_context_t enc_ctx = {0};
2873 
2874  dec_ctx.keep_alive_timeout = enc_ctx.keep_alive_timeout = 10;
2875 
2878 
2879  sdPara.p_dec_ctx = (void *) &dec_ctx;
2880  sdPara.p_enc_ctx = (void *) &enc_ctx;
2881  rcPara.p_dec_ctx = (void *) &dec_ctx;
2882  rcPara.p_enc_ctx = (void *) &enc_ctx;
2883 
2884  enc_ctx.nb_rois = 0;
2885  enc_ctx.roi_side_data_size = 0;
2886  enc_ctx.nb_rois = 0;
2887  enc_ctx.roi_side_data_size = 0;
2888  enc_ctx.av_rois = NULL;
2889  enc_ctx.codec_format = dst_codec_format;
2890 
2891  if (mode == XCODER_APP_TRANSCODE || mode == XCODER_APP_DECODE)
2892  {
2893  dec_ctx.p_session_config = NULL;
2895  dec_ctx.codec_format = src_codec_format;
2896 
2897  // no need to directly allocate resource context
2898  rcPara.p_dec_rsrc_ctx = sdPara.p_dec_rsrc_ctx = NULL;
2899 
2900  // assign the card GUID in the decoder context and let session open
2901  // take care of the rest
2902  dec_ctx.device_handle = dec_ctx.blk_io_handle = NI_INVALID_DEVICE_HANDLE;
2903  dec_ctx.hw_id = xcoder_id;
2904  dec_ctx.hw_name = &xcoder_name[0];
2905 
2906  dec_ctx.p_session_config = &dec_api_param;
2907  // default: little endian
2908  dec_ctx.src_bit_depth = bit_depth;
2910  dec_ctx.bit_depth_factor = 1;
2911  if (10 == dec_ctx.src_bit_depth)
2912  {
2913  dec_ctx.bit_depth_factor = 2;
2914  }
2915 
2917  if (err < 0)
2918  {
2919  fprintf(stderr, "Error: ni_logan_decoder_session_open() failure!\n");
2920  return -1;
2921  }
2922  else
2923  {
2924  if (xcoder_name[0] != '\0')
2925  {
2926  printf("Encoder device %s session open successful.\n", xcoder_name);
2927  }
2928  else
2929  {
2930  printf("Encoder device %d session open successful.\n", xcoder_id);
2931  }
2932  }
2933  }
2934 
2935  if (mode == XCODER_APP_TRANSCODE || mode == XCODER_APP_ENCODE)
2936  {
2937  // no need to directly allocate resource context for encoder
2938  rcPara.p_enc_rsrc_ctx = sdPara.p_enc_rsrc_ctx = NULL;
2939  }
2940 
2941  // encoder session open, if needed, will be at the first frame arrival as it
2942  // carries source stream info that may be useful in encoding config
2943 
2944  sos_flag = 1;
2945  edFlag = 0;
2946  bytes_sent = 0;
2947  total_bytes_received = 0;
2948  xcodeRecvTotal = 0;
2949  total_bytes_sent = 0;
2950 
2951  printf("user video resolution: %dx%d\n", arg_width, arg_height);
2952  if (arg_width == 0 || arg_height == 0)
2953  {
2954  input_video_width = 1280;
2955  input_video_height = 720;
2956  }
2957  else
2958  {
2959  input_video_width = arg_width;
2960  input_video_height = arg_height;
2961  }
2962  int output_video_width = input_video_width;
2963  int output_video_height = input_video_height;
2964 
2965 
2966  (void) ni_logan_gettimeofday(&start_time, NULL);
2967  (void) ni_logan_gettimeofday(&previous_time, NULL);
2968  (void) ni_logan_gettimeofday(&current_time, NULL);
2970 
2971 
2972 
2973 #if 0
2974 #ifdef __linux__
2975  struct timespec start, end;
2976  clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start);
2977 #endif
2978 #endif
2979 
2980 
2981  if (mode == XCODER_APP_DECODE)
2982  {
2983  ni_logan_session_data_io_t in_pkt = {0};
2984  ni_logan_session_data_io_t out_frame = {0};
2985 
2986  printf("Decoding Mode: %dx%d to %dx%d\n",
2987  input_video_width, input_video_height,
2988  output_video_width, output_video_height);
2989 
2990  if (dec_async)
2991  {
2992  // As for multi-threading decoding, three threads are created for sending
2993  // receiving and dec_flushing. When the dec_flush trigger the flush and
2994  // close functions the send/recv functions would return failure and also
2995  // call the close funtion according to the client scenario. Fortunately
2996  // the internal session context mutex will assure the thread safety.
2997  // After all the threads terminate, the ni_logan_device_session_context_clear
2998  // function shall be called to destroy the mutex.
2999  ni_pthread_t send_tid, recv_tid, flush_tid;
3000  dev_send_param_t send_param = {0};
3001  dev_recv_param_t recv_param = {0};
3002 
3003  send_param.p_ctx = &dec_ctx;
3004  send_param.p_data = &in_pkt;
3005  send_param.input_video_width = input_video_width;
3006  send_param.input_video_height = input_video_height;
3007  send_param.input_size = pkt_size;
3008  send_param.print_time = 0;
3009  send_param.p_total_bytes_sent = &total_bytes_sent;
3010  send_param.p_xcodeState = &xcodeState;
3011  send_param.p_SPS = &SPS;
3012 
3013  recv_param.p_ctx = &dec_ctx;
3014  recv_param.p_data = &out_frame;
3015  recv_param.output_video_width = output_video_width;
3016  recv_param.output_video_height = output_video_height;
3017  recv_param.print_time = 0;
3018  recv_param.p_file = p_file;
3019  recv_param.p_total_bytes_received = &total_bytes_received;
3020  recv_param.p_xcodeState = &xcodeState;
3021 
3022  if (ni_logan_pthread_create(&send_tid, NULL, decoder_send_routine, &send_param))
3023  {
3024  fprintf(stderr, "create send pkt thread failed in decoder mode\n");
3025  return -1;
3026  }
3027 
3028  if (ni_logan_pthread_create(&recv_tid, NULL, decoder_receive_routine, &recv_param))
3029  {
3030  fprintf(stderr, "create recv frame thread failed in decoder mode\n");
3031  return -1;
3032  }
3033 
3034  if (dec_flush_sec > 0 &&
3035  ni_logan_pthread_create(&flush_tid, NULL, decoder_flush_routine, &send_param))
3036  {
3037  fprintf(stderr, "create flush frame thread failed in decoder mode\n");
3038  return -1;
3039  }
3040 
3041  ni_logan_pthread_join(send_tid, NULL);
3042  ni_logan_pthread_join(recv_tid, NULL);
3043  if (dec_flush_sec > 0)
3044  {
3045  flush_fin_flag = 1;
3046  ni_logan_pthread_join(flush_tid, NULL);
3047  }
3048  }
3049  else
3050  {
3051  while (send_fin_flag == 0 || receive_fin_flag == 0)
3052  {
3053 
3054  (void) ni_logan_gettimeofday(&current_time, NULL);
3055  int print_time = ((current_time.tv_sec - previous_time.tv_sec) > 1);
3056 
3057  // Sending
3059  &dec_ctx, &in_pkt, input_video_width, input_video_height,
3060  pkt_size, &total_bytes_sent, print_time, &xcodeState, &SPS);
3061  sos_flag = 0;
3062  if (send_fin_flag < 0)
3063  {
3064  fprintf(stderr, "Error: decoder_send_data() failed, rc: %d\n",
3065  send_fin_flag);
3066  break;
3067  }
3068 
3069  // Receiving
3071  &dec_ctx, &out_frame, output_video_width, output_video_height,
3072  p_file, &total_bytes_received, print_time, &xcodeState);
3073 
3075  if (print_time)
3076  {
3078  }
3079 
3080  // Error or eos
3081  if (receive_fin_flag < 0 || out_frame.data.frame.end_of_stream)
3082  {
3083  break;
3084  }
3085  }
3086  }
3087 
3088  int time_diff = current_time.tv_sec - start_time.tv_sec;
3089  if (time_diff == 0)
3090  time_diff = 1;
3091 
3092  printf("[R] Got: Frames= %u fps=%d Total bytes %llu\n",
3093  number_of_frames, number_of_frames/time_diff, total_bytes_received);
3094 
3098  rcPara.p_dec_rsrc_ctx = sdPara.p_dec_rsrc_ctx = NULL;
3099 
3102  }
3103  else if (mode == XCODER_APP_ENCODE)
3104  {
3105  printf("Encoding Mode: %dx%d to %dx%d\n",
3106  input_video_width, input_video_height,
3107  output_video_width, output_video_height);
3108 
3109  // set up encoder p_config, using some hard coded numbers
3110  if (ni_logan_encoder_init_default_params(&enc_api_param, 30, 1, 200000,
3111  NI_LOGAN_ODD2EVEN(arg_width), NI_LOGAN_ODD2EVEN(arg_height)) < 0)
3112  {
3113  fprintf(stderr, "Error: encoder init default set up error\n");
3114  return -1;
3115  }
3116 
3117  // check and set ni_logan_encoder_params from --xcoder-params
3118  if (retrieve_xcoder_params(encConfXcoderParams, &enc_api_param, &enc_ctx))
3119  {
3120  fprintf(stderr, "Error: encoder p_config parsing error\n");
3121  return -1;
3122  }
3123 
3124  ni_logan_session_data_io_t in_frame = {0};
3125  ni_logan_session_data_io_t out_packet = {0};
3126  int video_full_range_flag = 0;
3127 
3128  if (enc_api_param.video_full_range_flag >= 0)
3129  {
3130  ni_log(NI_LOG_TRACE, "Using user-configured video_full_range_flag "
3131  "%d\n", enc_api_param.video_full_range_flag);
3132  video_full_range_flag = enc_api_param.video_full_range_flag;
3133  }
3134 
3135  // for encode from YUV, use all the parameters specified by user
3136  if (encoder_open_session(&enc_ctx, dst_codec_format, xcoder_id, xcoder_name,
3137  &enc_api_param, bit_depth, arg_width, arg_height,
3138  enc_api_param.color_primaries,
3139  enc_api_param.color_transfer_characteristic,
3140  enc_api_param.color_space,
3141  video_full_range_flag,
3142  enc_api_param.sar_num, enc_api_param.sar_denom))
3143  {
3144  goto end;
3145  }
3146 
3147  if (enc_async)
3148  {
3149  dev_send_param_t send_param = {0};
3150  dev_recv_param_t recv_param = {0};
3151  ni_pthread_t send_tid, recv_tid;
3152 
3153  send_param.p_ctx = &enc_ctx;
3154  send_param.p_data = &in_frame;
3155  send_param.input_video_width = input_video_width;
3156  send_param.input_video_height = input_video_height;
3157  send_param.print_time = 0;
3158  send_param.p_total_bytes_sent = &total_bytes_sent;
3159  send_param.p_xcodeState = &xcodeState;
3160 
3161  recv_param.p_ctx = &enc_ctx;
3162  recv_param.p_data = &out_packet;
3163  recv_param.output_video_width = output_video_width;
3164  recv_param.output_video_height = output_video_height;
3165  recv_param.print_time = 0;
3166  recv_param.p_file = p_file;
3167  recv_param.p_total_bytes_received = &total_bytes_received;
3168  recv_param.p_xcodeState = &xcodeState;
3169 
3170  if (ni_logan_pthread_create(&send_tid, NULL, encoder_send_routine, &send_param))
3171  {
3172  fprintf(stderr, "create send frame thread failed in encoder mode\n");
3173  return -1;
3174  }
3175 
3176  if (ni_logan_pthread_create(&recv_tid, NULL, encoder_receive_routine, &recv_param))
3177  {
3178  fprintf(stderr, "create recv pkt thread failed in encoder mode\n");
3179  return -1;
3180  }
3181 
3182  ni_logan_pthread_join(send_tid, NULL);
3183  ni_logan_pthread_join(recv_tid, NULL);
3184  }
3185  else
3186  {
3187  while (send_fin_flag == 0 || receive_fin_flag == 0)
3188  {
3189  (void) ni_logan_gettimeofday(&current_time, NULL);
3190  int print_time = ((current_time.tv_sec - previous_time.tv_sec) > 1);
3191 
3192  // Sending
3194  &enc_ctx, &in_frame, input_video_width, input_video_height,
3195  &total_bytes_sent, &xcodeState);
3196  sos_flag = 0;
3197  if (send_fin_flag == 2) //Error
3198  {
3199  break;
3200  }
3201 
3202  // Receiving
3204  &enc_ctx, &out_packet, output_video_width, output_video_height,
3205  p_file, &total_bytes_received, print_time);
3206 
3207  if (print_time)
3208  {
3210  }
3211 
3212  // Error or eos
3213  if (receive_fin_flag == 2 || out_packet.data.packet.end_of_stream)
3214  {
3215  break;
3216  }
3217  }
3218  }
3219 
3220  int timeDiff = current_time.tv_sec - start_time.tv_sec;
3221  if (timeDiff == 0)
3222  {
3223  timeDiff = 1;
3224  }
3225 
3226  printf("[R] Got: Packets= %u fps=%d Total bytes %lld\n",
3227  number_of_packets, number_of_packets/timeDiff, total_bytes_received);
3228 
3232  rcPara.p_enc_rsrc_ctx = sdPara.p_enc_rsrc_ctx = NULL;
3233 
3236  }
3237  else if (mode == XCODER_APP_TRANSCODE)
3238  {
3239  printf("Xcoding Mode: %dx%d to %dx%d\n", input_video_width,
3240  input_video_height, output_video_width, output_video_height);
3241 
3242  ni_logan_session_data_io_t in_pkt = {0};
3243  ni_logan_session_data_io_t out_frame = {0};
3244  ni_logan_session_data_io_t enc_in_frame = {0};
3245  ni_logan_session_data_io_t out_packet = {0};
3246 
3247  while (send_fin_flag == 0 || receive_fin_flag == 0)
3248  {
3249  (void) ni_logan_gettimeofday(&current_time, NULL);
3250  int print_time = ((current_time.tv_sec - previous_time.tv_sec) > 1);
3251 
3252  // bitstream Sending
3254  &dec_ctx, &in_pkt, input_video_width, input_video_height, pkt_size,
3255  &total_bytes_sent, print_time, &xcodeState, &SPS);
3256 
3257  sos_flag = 0;
3258  if (send_fin_flag == 2) //Error
3259  {
3260  break;
3261  }
3262 
3263  // YUV Receiving: not writing to file
3265  &dec_ctx, &out_frame, output_video_width, output_video_height,
3266  p_file, &total_bytes_received, print_time, &xcodeState);
3267 
3268  if (print_time)
3269  {
3271  }
3272 
3273  if (2 == receive_fin_flag)
3274  {
3275  ni_log(NI_LOG_TRACE, "no decoder output, jump to encoder receive!\n");
3277  goto encode_recv;
3278  }
3279  else if (NI_LOGAN_INVALID_SESSION_ID == enc_ctx.session_id ||
3280  NI_INVALID_DEVICE_HANDLE == enc_ctx.blk_io_handle)
3281  {
3282  // open the encode session when the first frame arrives and the session
3283  // is not opened yet, with the source stream and user-configured encode
3284  // info both considered when constructing VUI in the stream headers
3285  int color_pri = out_frame.data.frame.color_primaries;
3286  int color_trc = out_frame.data.frame.color_trc;
3287  int color_space = out_frame.data.frame.color_space;
3288  int video_full_range_flag = out_frame.data.frame.video_full_range_flag;
3289  int sar_num = out_frame.data.frame.sar_width;
3290  int sar_den = out_frame.data.frame.sar_height;
3291  int fps_num = 0, fps_den = 0;
3292 
3293  // calculate the source fps and set it as the default target fps, based
3294  // on the timing_info passed in from the decoded frame
3295  if (out_frame.data.frame.vui_num_units_in_tick &&
3296  out_frame.data.frame.vui_time_scale)
3297  {
3299  {
3300  if (0 == (out_frame.data.frame.vui_time_scale % 2))
3301  {
3302  fps_num = out_frame.data.frame.vui_time_scale / 2;
3303  fps_den = out_frame.data.frame.vui_num_units_in_tick;
3304  }
3305  else
3306  {
3307  fps_num = out_frame.data.frame.vui_time_scale;
3308  fps_den = 2 * out_frame.data.frame.vui_num_units_in_tick;
3309  }
3310  }
3311  else if (NI_LOGAN_CODEC_FORMAT_H265 == out_frame.data.frame.src_codec)
3312  {
3313  fps_num = out_frame.data.frame.vui_time_scale;
3314  fps_den = out_frame.data.frame.vui_num_units_in_tick;
3315  }
3316  }
3317 
3318  // set up encoder p_config, using some info from source
3319  if (ni_logan_encoder_init_default_params(&enc_api_param, fps_num, fps_den, 200000,
3320  arg_width, arg_height) < 0)
3321  {
3322  fprintf(stderr, "Error: encoder init default set up error\n");
3323  break;
3324  }
3325 
3326  // check and set ni_logan_encoder_params from --xcoder-params
3327  // Note: the parameter setting has to be in this order so that user
3328  // configured values can overwrite the source/default ones if
3329  // desired.
3330  if (retrieve_xcoder_params(encConfXcoderParams, &enc_api_param, &enc_ctx))
3331  {
3332  fprintf(stderr, "Error: encoder p_config parsing error\n");
3333  break;
3334  }
3335 
3336  if (color_pri != enc_api_param.color_primaries &&
3337  NI_COL_PRI_UNSPECIFIED != enc_api_param.color_primaries)
3338  {
3339  ni_log(NI_LOG_TRACE, "Using user-configured color primaries %d to "
3340  "overwrite source %d\n", enc_api_param.color_primaries, color_pri);
3341  color_pri = enc_api_param.color_primaries;
3342  }
3343  if (color_trc != enc_api_param.color_transfer_characteristic &&
3345  {
3346  ni_log(NI_LOG_TRACE, "Using user-configured color trc %d to overwrite"
3347  " source %d\n",
3348  enc_api_param.color_transfer_characteristic, color_trc);
3349  color_trc = enc_api_param.color_transfer_characteristic;
3350  }
3351  if (color_space != enc_api_param.color_space &&
3352  NI_COL_SPC_UNSPECIFIED != enc_api_param.color_space)
3353  {
3354  ni_log(NI_LOG_TRACE, "Using user-configured color space %d to "
3355  "overwrite source %d\n", enc_api_param.color_space, color_space);
3356  color_space = enc_api_param.color_space;
3357  }
3358  if (enc_api_param.video_full_range_flag >= 0)
3359  {
3360  ni_log(NI_LOG_TRACE, "Using user-configured video_full_range_flag "
3361  "%d\n", enc_api_param.video_full_range_flag);
3362  video_full_range_flag = enc_api_param.video_full_range_flag;
3363  }
3364  if (out_frame.data.frame.aspect_ratio_idc > 0 &&
3366  {
3367  sar_num = ni_h264_pixel_aspect_list[
3368  out_frame.data.frame.aspect_ratio_idc].num;
3369  sar_den = ni_h264_pixel_aspect_list[
3370  out_frame.data.frame.aspect_ratio_idc].den;
3371  }
3372 
3373  if (encoder_open_session(&enc_ctx, dst_codec_format, xcoder_id,
3374  xcoder_name, &enc_api_param, bit_depth, arg_width,
3375  arg_height, color_pri, color_trc, color_space,
3376  video_full_range_flag, sar_num, sar_den))
3377  {
3378  ni_log(NI_LOG_ERROR, "Error: encoder_open_session failed, stop!\n");
3379  break;
3380  }
3381  }
3382 
3383  // YUV Sending
3385  &enc_ctx, &dec_ctx, &out_frame, &enc_in_frame,
3386  input_video_width, input_video_height,
3387  &total_bytes_sent, &xcodeState);
3388  sos_flag = 0;
3389  if (send_fin_flag == 2) //Error
3390  {
3392  break;
3393  }
3394 
3396 
3397  // encoded bitstream Receiving
3398 encode_recv:
3400  &enc_ctx, &out_packet, output_video_width, output_video_height,
3401  p_file, &xcodeRecvTotal, print_time);
3402 
3403  if (print_time)
3404  {
3406  }
3407 
3408  // Error or encoder eos
3409  if (receive_fin_flag == 2 || out_packet.data.packet.end_of_stream)
3410  {
3411  break;
3412  }
3413  }
3414 
3415  int time_diff = current_time.tv_sec - start_time.tv_sec;
3416  if (time_diff == 0)
3417  time_diff = 1;
3418 
3419  printf("[R] Got: Frames= %u fps=%d Total bytes %llu\n",
3420  number_of_frames, number_of_frames/time_diff, total_bytes_received);
3421  printf("[R] Got: Packets= %u fps=%d Total bytes %llu\n",
3422  number_of_packets, number_of_packets/time_diff, xcodeRecvTotal);
3423 
3425 
3428  rcPara.p_dec_rsrc_ctx = sdPara.p_dec_rsrc_ctx = NULL;
3429 
3431  ni_logan_frame_buffer_free(&(out_frame.data.frame));
3432 
3434 
3437  rcPara.p_enc_rsrc_ctx = sdPara.p_enc_rsrc_ctx = NULL;
3438 
3439  ni_logan_frame_buffer_free(&(enc_in_frame.data.frame));
3440  ni_logan_packet_buffer_free(&(out_packet.data.packet));
3441  }
3442 
3443 end: close(pfs);
3444  if (p_file)
3445  {
3446  fclose(p_file);
3447  }
3448 
3449  free(g_file_cache);
3450  g_file_cache = NULL;
3451 
3452  printf("All Done.\n");
3453 
3454  return 0;
3455 }
void ni_logan_dec_retrieve_aux_data(ni_logan_frame_t *frame)
Retrieve auxiliary data (close caption, various SEI) associated with this frame that is returned by d...
int ni_logan_enc_fill_reconfig_params(ni_logan_encoder_params_t *p_param, ni_logan_session_context_t *p_ctx, ni_logan_frame_t *p_api_fme, int reconfigCount)
Fill reconfig params.
void ni_logan_enc_copy_aux_data(ni_logan_session_context_t *p_enc_ctx, ni_logan_frame_t *p_enc_frame, ni_logan_frame_t *p_dec_frame, ni_logan_codec_format_t codec_format, const uint8_t *mdcv_data, const uint8_t *cll_data, const uint8_t *cc_data, const uint8_t *udu_data, const uint8_t *hdrp_data)
Copy auxiliary data that should be sent together with this frame to encoder.
void ni_logan_set_vui(ni_logan_encoder_params_t *p_param, ni_logan_session_context_t *p_ctx, ni_color_primaries_t color_primaries, ni_color_transfer_characteristic_t color_trc, ni_color_space_t color_space, int video_full_range_flag, int sar_num, int sar_den, ni_logan_codec_format_t codec_format)
Set SPS VUI part of encoded stream header.
int ni_logan_should_send_sei_with_frame(ni_logan_session_context_t *p_enc_ctx, ni_logan_pic_type_t pic_type, ni_logan_encoder_params_t *p_param)
Whether SEI (HDR) should be sent together with this frame to encoder.
void ni_logan_enc_prep_aux_data(ni_logan_session_context_t *p_enc_ctx, ni_logan_frame_t *p_enc_frame, ni_logan_frame_t *p_dec_frame, ni_logan_codec_format_t codec_format, int should_send_sei_with_frame, uint8_t *mdcv_data, uint8_t *cll_data, uint8_t *cc_data, uint8_t *udu_data, uint8_t *hdrp_data)
Prepare auxiliary data that should be sent together with this frame to encoder based on the auxiliary...
@ NI_COL_TRC_RESERVED0
@ NI_COL_TRC_UNSPECIFIED
@ NI_COL_TRC_NB
enum _ni_color_primaries ni_color_primaries_t
@ NI_COL_SPC_NB
@ NI_COL_SPC_UNSPECIFIED
@ NI_COL_SPC_RGB
@ NI_COL_PRI_RESERVED0
@ NI_COL_PRI_NB
@ NI_COL_PRI_UNSPECIFIED
@ NI_LOGAN_HEVC_NAL_SPS
@ NI_LOGAN_HEVC_NAL_VPS
@ NI_LOGAN_HEVC_NAL_PPS
enum _ni_color_transfer_characteristic ni_color_transfer_characteristic_t
#define NI_NUM_PIXEL_ASPECT_RATIO
enum _ni_color_space ni_color_space_t
@ NI_LOGAN_H264_NAL_SLICE
@ NI_LOGAN_H264_NAL_SEI
@ NI_LOGAN_H264_NAL_PPS
@ NI_LOGAN_H264_NAL_SPS
@ NI_LOGAN_H264_NAL_IDR_SLICE
@ NI_H264_SEI_PIC_STRUCT_FRAME_TRIPLING
@ NI_H264_SEI_PIC_STRUCT_FRAME
@ NI_H264_SEI_TYPE_PIC_TIMING
int ni_bs_reader_bits_count(ni_bitstream_reader_t *br)
return the number of bits already parsed in stream
uint32_t ni_bs_reader_get_ue(ni_bitstream_reader_t *br)
read an unsigned Exp-Golomb code ue(v)
int32_t ni_bs_reader_get_se(ni_bitstream_reader_t *br)
read a signed Exp-Golomb code se(v)
void ni_bitstream_reader_init(ni_bitstream_reader_t *br, const uint8_t *data, int bit_size)
init a bitstream reader Note: bitstream_reader takes reading ownership of the data
uint32_t ni_bs_reader_get_bits(ni_bitstream_reader_t *br, int n)
read bits (up to 32) from the bitstream reader, after reader init
int ni_bs_reader_get_bits_left(ni_bitstream_reader_t *br)
return the number of bits left to parse in stream
void ni_bs_reader_skip_bits(ni_bitstream_reader_t *br, int n)
skip a number of bits ahead in the bitstream reader
Utility functions to operate on bits in a bitstream.
ni_logan_retcode_t
@ NI_LOGAN_RETCODE_PARAM_ERROR_MN_QP
@ NI_LOGAN_RETCODE_ERROR_INVALID_HANDLE
@ NI_LOGAN_RETCODE_NVME_SC_VPU_GENERAL_ERROR
@ NI_LOGAN_RETCODE_PARAM_ERROR_CONF_WIN_R
@ NI_LOGAN_RETCODE_PARAM_ERROR_HEIGHT_TOO_SMALL
@ NI_LOGAN_RETCODE_ERROR_INVALID_SESSION
@ NI_LOGAN_RETCODE_PARAM_ERROR_ZERO
@ NI_LOGAN_RETCODE_PARAM_ERROR_FRATE
@ NI_LOGAN_RETCODE_PARAM_INVALID_VALUE
@ NI_LOGAN_RETCODE_PARAM_ERROR_TOO_SMALL
@ NI_LOGAN_RETCODE_PARAM_ERROR_OOR
@ NI_LOGAN_RETCODE_PARAM_ERROR_CONF_WIN_TOP
@ NI_LOGAN_RETCODE_PARAM_ERROR_USR_RMD_ENC_PARAM
@ NI_LOGAN_RETCODE_PARAM_ERROR_CU_SIZE_MODE
@ NI_LOGAN_RETCODE_PARAM_ERROR_TRATE
@ NI_LOGAN_RETCODE_PARAM_ERROR_GOP_PRESET
@ NI_LOGAN_RETCODE_PARAM_ERROR_AREA_TOO_BIG
@ NI_LOGAN_RETCODE_PARAM_ERROR_RCENABLE
@ NI_LOGAN_RETCODE_PARAM_ERROR_WIDTH_TOO_SMALL
@ NI_LOGAN_RETCODE_NVME_SC_RESOURCE_IS_EMPTY
@ NI_LOGAN_RETCODE_ERROR_UNLOCK_DEVICE
@ NI_LOGAN_RETCODE_DEFAULT_SESSION_ERR_NO
@ NI_LOGAN_RETCODE_PARAM_GOP_INTRA_INCOMPATIBLE
@ NI_LOGAN_RETCODE_PARAM_ERROR_CONF_WIN_L
@ NI_LOGAN_RETCODE_NVME_SC_REQUEST_IN_PROGRESS
@ NI_LOGAN_RETCODE_PARAM_ERROR_TOO_BIG
@ NI_LOGAN_RETCODE_ERROR_RESOURCE_UNAVAILABLE
@ NI_LOGAN_RETCODE_PARAM_ERROR_MX_QP
@ NI_LOGAN_RETCODE_PARAM_ERROR_BRATE_LT_TRATE
@ NI_LOGAN_RETCODE_PARAM_ERROR_CUSIZE_MODE_8X8_EN
@ NI_LOGAN_RETCODE_PARAM_ERROR_DY_MERGE_16X16_EN
@ NI_LOGAN_RETCODE_PARAM_ERROR_CUSIZE_MODE_16X16_EN
@ NI_LOGAN_RETCODE_ERROR_NVME_CMD_FAILED
@ NI_LOGAN_RETCODE_INVALID_PARAM
@ NI_LOGAN_RETCODE_ERROR_MEM_ALOC
@ NI_LOGAN_RETCODE_PARAM_ERROR_DY_MERGE_8X8_EN
@ NI_LOGAN_RETCODE_PARAM_ERROR_PIC_HEIGHT
@ NI_LOGAN_RETCODE_PARAM_ERROR_INTRA_PERIOD
@ NI_LOGAN_RETCODE_ERROR_VPU_RECOVERY
@ NI_LOGAN_RETCODE_PARAM_INVALID_NAME
@ NI_LOGAN_RETCODE_ERROR_GET_DEVICE_POOL
@ NI_LOGAN_RETCODE_PARAM_ERROR_BRATE
@ NI_LOGAN_RETCODE_PARAM_ERROR_HEIGHT_TOO_BIG
@ NI_LOGAN_RETCODE_PARAM_ERROR_RCINITDELAY
@ NI_LOGAN_RETCODE_PARAM_ERROR_MAXNUMMERGE
@ NI_LOGAN_RETCODE_PARAM_ERROR_CONF_WIN_BOT
@ NI_LOGAN_RETCODE_PARAM_ERROR_HVS_QP_EN
@ NI_LOGAN_RETCODE_PARAM_ERROR_CUSTOM_GOP
@ NI_LOGAN_RETCODE_SUCCESS
@ NI_LOGAN_RETCODE_NVME_SC_WRITE_BUFFER_FULL
@ NI_LOGAN_RETCODE_FAILURE
@ NI_LOGAN_RETCODE_NVME_SC_VPU_RECOVERY
@ NI_LOGAN_RETCODE_PARAM_ERROR_PIC_WIDTH
@ NI_LOGAN_RETCODE_PARAM_ERROR_DY_MERGE_32X32_EN
@ NI_LOGAN_RETCODE_PARAM_ERROR_MX_DELTA_QP
@ NI_LOGAN_RETCODE_NVME_SC_RESOURCE_UNAVAILABLE
@ NI_LOGAN_RETCODE_PARAM_ERROR_CUSIZE_MODE_32X32_EN
@ NI_LOGAN_RETCODE_PARAM_ERROR_HVS_QP_SCL
@ NI_LOGAN_RETCODE_PARAM_ERROR_INTRA_QP
@ NI_LOGAN_RETCODE_PARAM_ERROR_DECODING_REFRESH_TYPE
@ NI_LOGAN_RETCODE_PARAM_ERROR_CU_LVL_RC_EN
@ NI_LOGAN_RETCODE_ERROR_LOCK_DOWN_DEVICE
@ NI_LOGAN_RETCODE_PARAM_ERROR_WIDTH_TOO_BIG
@ NI_LOGAN_RETCODE_ERROR_INVALID_ALLOCATION_METHOD
@ NI_LOGAN_RETCODE_ERROR_OPEN_DEVICE
@ NI_LOGAN_RETCODE_ERROR_EXCEED_MAX_NUM_SESSIONS
@ NI_LOGAN_RETCODE_PARAM_ERROR_RC_INIT_DELAY
@ NI_LOGAN_RETCODE_NVME_SC_VPU_RSRC_INSUFFICIENT
@ NI_LOGAN_RETCODE_PARAM_ERROR_MX_NUM_MERGE
@ NI_LOGAN_RETCODE_NVME_SC_INVALID_PARAMETER
@ NI_LOGAN_RETCODE_NVME_SC_REQUEST_NOT_COMPLETED
@ NI_LOGAN_RETCODE_NVME_SC_RESOURCE_NOT_FOUND
#define END
#define NI_LOGAN_APP_ENC_FRAME_META_DATA_SIZE
#define NI_LOGAN_FW_ENC_BITSTREAM_META_DATA_SIZE
#define NI_LOGAN_MAX_NUM_DATA_POINTERS
#define NI_LOGAN_XCODER_REVISION
Definition: ni_defs_logan.h:62
@ NI_LOGAN_DEVICE_TYPE_ENCODER
@ NI_LOGAN_DEVICE_TYPE_DECODER
#define LRETURN
#define NI_LOGAN_MAX_TX_SZ
ni_logan_retcode_t ni_logan_packet_buffer_alloc(ni_logan_packet_t *p_packet, int packet_size)
Allocate memory for the packet buffer based on provided packet size.
ni_logan_retcode_t ni_logan_device_dec_session_save_hdrs(ni_logan_session_context_t *p_ctx, uint8_t *hdr_data, uint8_t hdr_size)
Save a stream's headers in a decoder session that can be used later for continuous decoding from the ...
ni_logan_retcode_t ni_logan_device_session_flush(ni_logan_session_context_t *p_ctx, ni_logan_device_type_t device_type)
Sends a flush command to the device ni_logan_device_session_open() If device_type is NI_LOGAN_DEVICE_...
ni_logan_retcode_t ni_logan_device_session_close(ni_logan_session_context_t *p_ctx, int eos_recieved, ni_logan_device_type_t device_type)
Closes device session that was previously opened by calling ni_logan_device_session_open() If device_...
ni_logan_retcode_t ni_logan_packet_buffer_free(ni_logan_packet_t *p_packet)
Free packet buffer that was previously allocated with either ni_logan_packet_buffer_alloc.
ni_logan_retcode_t ni_logan_decoder_frame_buffer_alloc(ni_logan_buf_pool_t *p_pool, ni_logan_frame_t *p_frame, int alloc_mem, int video_width, int video_height, int alignment, int factor)
Allocate memory for decoder frame buffer based on provided parameters; the memory is retrieved from a...
LIB_API ni_logan_retcode_t ni_logan_device_dec_session_flush(ni_logan_session_context_t *p_ctx)
Flush a decoder session to get ready to continue decoding.
ni_logan_retcode_t ni_logan_decoder_frame_buffer_free(ni_logan_frame_t *p_frame)
Free decoder frame buffer that was previously allocated with ni_logan_decoder_frame_buffer_alloc,...
void ni_logan_device_session_context_init(ni_logan_session_context_t *p_ctx)
Initialize already allocated session context to a known state.
ni_logan_retcode_t ni_logan_frame_buffer_free(ni_logan_frame_t *p_frame)
Free frame buffer that was previously allocated with either ni_logan_frame_buffer_alloc or ni_logan_e...
ni_logan_retcode_t ni_logan_encoder_frame_buffer_alloc(ni_logan_frame_t *p_frame, int video_width, int video_height, int linesize[], int alignment, int extra_len, int factor)
Allocate memory for the frame buffer for encoding based on given parameters, taking into account pic ...
int ni_logan_packet_copy(void *p_destination, const void *const p_source, int cur_size, void *p_leftover, int *p_prev_size)
Copy video packet accounting for allighment.
int ni_logan_device_session_read(ni_logan_session_context_t *p_ctx, ni_logan_session_data_io_t *p_data, ni_logan_device_type_t device_type)
Reads data the device If device_type is NI_LOGAN_DEVICE_TYPE_DECODER reads data packet from decoder I...
ni_logan_retcode_t ni_logan_encoder_params_set_value(ni_logan_encoder_params_t *p_params, const char *name, const char *value, ni_logan_session_context_t *ctx)
Set value referenced by name in encoder parameters structure.
#define atoi(p_str)
void ni_logan_device_session_context_clear(ni_logan_session_context_t *p_ctx)
Clear already allocated session context to all zeros.
ni_logan_retcode_t ni_logan_encoder_init_default_params(ni_logan_encoder_params_t *p_param, int fps_num, int fps_denom, long bit_rate, int width, int height)
Initialize default encoder parameters.
ni_logan_retcode_t ni_logan_device_session_open(ni_logan_session_context_t *p_ctx, ni_logan_device_type_t device_type)
Opens a new device session depending on the device_type parameter If device_type is NI_LOGAN_DEVICE_T...
int ni_logan_device_session_write(ni_logan_session_context_t *p_ctx, ni_logan_session_data_io_t *p_data, ni_logan_device_type_t device_type)
Sends data the device If device_type is NI_LOGAN_DEVICE_TYPE_DECODER sends data packet to decoder If ...
ni_logan_retcode_t ni_logan_decoder_init_default_params(ni_logan_decoder_params_t *p_param, int fps_num, int fps_denom, long bit_rate, int width, int height)
Initialize default decoder parameters.
Main NETINT device API header file provides the ability to communicate with NI T-408 type hardware tr...
struct _ni_logan_encoder_change_params_t ni_logan_encoder_change_params_t
This is a data structure for encoding parameters that have changed.
#define NI_LOGAN_MIN_WIDTH
#define NI_LOGAN_MAX_SEI_DATA
#define NI_LOGAN_MIN_HEIGHT
#define NI_LOGAN_ENC_MAX_SEI_BUF_SIZE
#define NI_LOGAN_FRAME_LITTLE_ENDIAN
enum _ni_logan_codec_format ni_logan_codec_format_t
This is an enumeration for supported codec formats.
@ NI_LOGAN_CODEC_FORMAT_H265
@ NI_LOGAN_CODEC_FORMAT_H264
#define NI_LOGAN_INVALID_SESSION_ID
int parse_vui(ni_bitstream_reader_t *br, ni_logan_h264_sps_t *sps)
#define MAX_YUV_FRAME_SIZE
int parse_scaling_list(ni_bitstream_reader_t *br, uint8_t *factors, int size, const uint8_t *jvt_list, const uint8_t *fallback_list)
time_t start_timestamp
int main(int argc, char *argv[])
main
volatile int receive_fin_flag
ni_logan_retcode_t decoder_send_data(ni_logan_session_context_t *p_dec_ctx, ni_logan_session_data_io_t *p_in_data, int input_video_width, int input_video_height, int packet_size, unsigned long *total_bytes_sent, int print_time, device_state_t *p_device_state, ni_logan_h264_sps_t *sps)
Send decoder input data.
int probe_h264_stream_info(ni_logan_h264_sps_t *sps)
int parse_h264_slice_header(uint8_t *buf, int size_bytes, ni_logan_h264_sps_t *sps, int32_t *frame_num, unsigned int *first_mb_in_slice)
int parse_scaling_matrices(ni_bitstream_reader_t *br, const ni_logan_h264_sps_t *sps, const ni_logan_h264_pps_t *pps, int is_sps, uint8_t(*scaling_matrix4)[16], uint8_t(*scaling_matrix8)[64])
volatile uint32_t data_left_size
int find_h264_next_nalu(uint8_t *p_dst, int *nal_type)
#define MIN_LOG2_MAX_FRAME_NUM
int parse_hrd(ni_bitstream_reader_t *br, ni_logan_h264_sps_t *sps)
int encoder_receive_data(ni_logan_session_context_t *p_enc_ctx, ni_logan_session_data_io_t *p_out_data, int output_video_width, int output_video_height, FILE *p_file, unsigned long long *total_bytes_received, int print_time)
Receive output data from encoder.
int encoder_send_data(ni_logan_session_context_t *p_enc_ctx, ni_logan_session_data_io_t *p_in_data, int input_video_width, int input_video_height, unsigned long *bytes_sent, device_state_t *p_device_state)
Send encoder input data, read from input file.
int ni_logan_device_dec_session_write(ni_logan_session_context_t *p_ctx, ni_logan_session_data_io_t *p_data)
Sends data to decoder device. The data is assumed to be a full encoded frame that will be scanned,...
int parse_sps(uint8_t *buf, int size_bytes, ni_logan_h264_sps_t *sps)
time_t current_timestamp
int encoder_send_data2(ni_logan_session_context_t *p_enc_ctx, ni_logan_session_context_t *p_dec_ctx, ni_logan_session_data_io_t *p_dec_out_data, ni_logan_session_data_io_t *p_enc_in_data, int input_video_width, int input_video_height, unsigned long *bytes_sent, device_state_t *p_device_state)
int parse_sei(uint8_t *buf, int size_bytes, ni_logan_h264_sps_t *sps, int *sei_type, int *is_interlaced)
time_t privious_timestamp
void reset_data_buf_pos(void)
void rewind_data_buf_pos_by(int nb_bytes)
volatile uint32_t number_of_frames
const uint8_t ni_logan_zigzag_scan[16+1]
#define QP_MAX_NUM
volatile int err_flag
const uint8_t ni_logan_zigzag_direct[64]
struct _ni_logan_h264_pps_t ni_logan_h264_pps_t
void print_usage(void)
int read_next_chunk(uint8_t *p_dst, uint32_t to_read)
volatile int send_fin_flag
struct timeval start_time previous_time current_time
struct _ni_logan_err_rc_txt_entry ni_logan_err_rc_txt_entry_t
#define EXTENDED_SAR
volatile int flush_fin_flag
int decoder_receive_data(ni_logan_session_context_t *p_dec_ctx, ni_logan_session_data_io_t *p_out_data, int output_video_width, int output_video_height, FILE *p_file, unsigned long long *total_bytes_received, int print_time, device_state_t *p_device_state)
Receive decoded output data from decoder.
void arg_error_exit(char *arg_name, char *param)
volatile long total_file_size
#define MAX_LOG2_MAX_FRAME_NUM
volatile uint32_t number_of_packets
int encoder_open_session(ni_logan_session_context_t *p_enc_ctx, int dst_codec_format, int xcoder_id, const char *xcoder_name, ni_logan_encoder_params_t *p_enc_params, int src_bit_depth, int width, int height, ni_color_primaries_t color_primaries, ni_color_transfer_characteristic_t color_trc, ni_color_space_t color_space, int video_full_range_flag, int sar_num, int sar_den)
Encoder session open.
Example code on how to programmatically work with NI T-408 using libxcoder API.
#define XCODER_APP_ENCODE
#define XCODER_APP_TRANSCODE
#define XCODER_APP_DECODE
char * optarg
int getopt_long(int argc, char *argv[], const char *optstring, const struct option *longopts, int *longindex)
#define no_argument
#define required_argument
void ni_log_set_level(ni_log_level_t level)
Set ni_log_level.
Definition: ni_log_logan.c:138
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_level_t
Definition: ni_log_logan.h:60
@ NI_LOG_NONE
Definition: ni_log_logan.h:62
@ NI_LOG_DEBUG
Definition: ni_log_logan.h:66
@ NI_LOG_TRACE
Definition: ni_log_logan.h:67
@ NI_LOG_FATAL
Definition: ni_log_logan.h:63
@ NI_LOG_ERROR
Definition: ni_log_logan.h:64
@ NI_LOG_INFO
Definition: ni_log_logan.h:65
uint8_t * g_curr_cache_pos
struct timeval start_time
struct timeval previous_time
void ni_logan_rsrc_free_device_context(ni_logan_device_context_t *p_device_context)
Free previously allocated device context.
Exported definitions related to resource management of NI T-408 devices.
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....
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....
void ni_logan_usleep(int64_t usec)
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.
int32_t ni_logan_gettimeofday(struct timeval *p_tp, void *p_tzp)
Definition: ni_util_logan.c:56
Exported utility routines definition.
#define NI_LOGAN_ODD2EVEN(X)
Definition: ni_util_logan.h:80
ni_logan_encoder_input_params_t enc_input_params
ni_logan_retcode_t rc
const char * txt
unsigned int sei_hdr_mastering_display_color_vol_offset
unsigned int sei_hdr_content_light_level_info_offset
unsigned int sei_hdr_plus_len
uint32_t data_len[NI_LOGAN_MAX_NUM_DATA_POINTERS]
unsigned int sei_hdr_plus_offset
unsigned int extra_data_len
unsigned int sei_total_len
unsigned int sei_cc_offset
unsigned int sei_user_data_unreg_len
ni_logan_pic_type_t ni_logan_pict_type
uint8_t use_cur_src_as_long_term_pic
ni_logan_codec_format_t src_codec
unsigned int sei_hdr_content_light_level_info_len
void * p_data[NI_LOGAN_MAX_NUM_DATA_POINTERS]
unsigned int sei_hdr_mastering_display_color_vol_len
int pic_order_present
pic_order_present_flag
int deblocking_filter_parameters_present
deblocking_filter_parameters_present_flag
int init_qs
pic_init_qs_minus26 + 26
int slice_group_count
num_slice_groups_minus1 + 1
int cabac
entropy_coding_mode_flag
int weighted_pred
weighted_pred_flag
uint8_t chroma_qp_table[2][QP_MAX_NUM+1]
pre-scaled (with chroma_qp_index_offset) version of qp_table
int constrained_intra_pred
constrained_intra_pred_flag
int init_qp
pic_init_qp_minus26 + 26
uint32_t(*[6] dequant4_coeff)[16]
uint8_t scaling_matrix8[6][64]
uint32_t dequant8_buffer[6][QP_MAX_NUM+1][64]
int transform_8x8_mode
transform_8x8_mode_flag
unsigned int ref_count[2]
num_ref_idx_l0/1_active_minus1 + 1
uint8_t scaling_matrix4[6][16]
int redundant_pic_cnt_present
redundant_pic_cnt_present_flag
uint32_t(*[6] dequant8_coeff)[64]
uint32_t dequant4_buffer[6][QP_MAX_NUM+1][16]
ni_color_transfer_characteristic_t color_trc
ni_color_primaries_t color_primaries
int log2_max_frame_num
log2_max_frame_num_minus4 + 4
unsigned int crop_left
frame_cropping_rect_left_offset
int cpb_removal_delay_length
cpb_removal_delay_length_minus1 + 1
int poc_type
pic_order_cnt_type
int constraint_set_flags
constraint_set[0-3]_flag
int bit_depth_luma
bit_depth_luma_minus8 + 8
int transform_bypass
qpprime_y_zero_transform_bypass_flag
uint8_t scaling_matrix8[6][64]
int initial_cpb_removal_delay_length
initial_cpb_removal_delay_length_minus1 + 1
unsigned int max_dec_frame_buffering
unsigned int crop_bottom
frame_cropping_rect_bottom_offset
ni_color_space_t colorspace
uint8_t scaling_matrix4[6][16]
int poc_cycle_length
num_ref_frames_in_pic_order_cnt_cycle
int residual_color_transform_flag
residual_colour_transform_flag
int mb_aff
mb_adaptive_frame_field_flag
int dpb_output_delay_length
dpb_output_delay_length_minus1 + 1
unsigned int crop_right
frame_cropping_rect_right_offset
unsigned int crop_top
frame_cropping_rect_top_offset
int cpb_cnt
See H.264 E.1.2.
int crop
frame_cropping_flag
int ref_frame_count
num_ref_frames
int bit_depth_chroma
bit_depth_chroma_minus8 + 8
int log2_max_poc_lsb
log2_max_pic_order_cnt_lsb_minus4
int mb_width
(pic_height_in_map_units_minus1 + 1) * (2 - frame_mbs_only_flag)
ni_device_handle_t device_handle
ni_device_handle_t blk_io_handle
ni_logan_buf_pool_t * dec_fme_buf_pool
ni_region_of_interest_t * av_rois
union _ni_logan_session_data_io::@4 data
char fileName[FILE_NAME_LEN]
ni_logan_session_context_t * p_enc_ctx
ni_logan_device_context_t * p_enc_rsrc_ctx
ni_logan_session_context_t * p_dec_ctx
ni_logan_device_context_t * p_dec_rsrc_ctx
char fileName[FILE_NAME_LEN]
ni_logan_session_context_t * p_enc_ctx
ni_logan_device_context_t * p_enc_rsrc_ctx
ni_logan_session_context_t * p_dec_ctx
ni_logan_device_context_t * p_dec_rsrc_ctx
device_state_t * p_xcodeState
unsigned long long * p_total_bytes_received
ni_logan_session_data_io_t * p_data
ni_logan_session_context_t * p_ctx
device_state_t * p_xcodeState
ni_logan_session_data_io_t * p_data
unsigned long * p_total_bytes_sent
ni_logan_session_context_t * p_ctx
ni_logan_h264_sps_t * p_SPS