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