libxcoder  5.2.0
ni_xcoder_encode.c
Go to the documentation of this file.
1 /*******************************************************************************
2  *
3  * Copyright (C) 2022 NETINT Technologies
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to deal
7  * in the Software without restriction, including without limitation the rights
8  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9  * copies of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
17  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
18  * SOFTWARE.
19  *
20  ******************************************************************************/
21 
22 /*!*****************************************************************************
23  * \file ni_xcoder_encode.c
24  *
25  * \brief Video encoding demo application directly using Netint Libxcoder API
26  ******************************************************************************/
27 
28 #include "ni_generic_utils.h"
29 #include "ni_encode_utils.h"
30 #include "ni_log.h"
31 #include "ni_util.h"
32 
33 #ifdef _WIN32
34 #include "ni_getopt.h"
35 #elif __linux__ || __APPLE__
36 #include <getopt.h>
37 #include <unistd.h>
38 #endif
39 
40 static void print_usage(void)
41 {
43  "Video encoding demo application directly using Netint Libxcoder version %s\n"
44  "Usage: ni_xcoder_encode [options]\n"
45  "\n"
46  "options:\n"
47  "-h | --help Show this message.\n"
48  "-v | --version Print version info.\n"
49  "-i | --input (Required) Input file path.\n"
50  " Can be specified multiple (max %d) times\n"
51  " to concatenate inputs with different resolution together (sequence change)\n"
52  "-o | --output (Required) Output file path.\n"
53  " Can be specified multiple (max %d) times\n"
54  " to run multiple encoding instances simultaneously.\n"
55  "-m | --enc-codec (Required) Encoder codec format.\n"
56  " [a|avc, h|hevc, x|av1, o|obu]\n"
57  " (x is in ivf container format, o is output raw AV1 OBU only)\n"
58  "-l | --loglevel Set loglevel of this application and libxcoder API.\n"
59  " [none, fatal, error, info, debug, trace]\n"
60  " (Default: info)\n"
61  "-c | --card Set card index to use.\n"
62  " See `ni_rsrc_mon` for info of cards on system.\n"
63  " (Default: 0)\n"
64  "-r | --repeat To loop input X times. Must be a positive integer\n"
65  " (Default: 1)\n"
66  "-k | --readframerate Read input at specified frame rate.\n"
67  "-p | --pix_fmt Indicate the pixel format of the input.\n"
68  " [yuv420p, yuv420p10le, nv12, p010le, rgba, gbra, argb, abgr, bgr0, yuv444p]\n"
69  " (Default: yuv420p)\n"
70  "-s | --size (Required) Resolution of input file in format WIDTHxHEIGHT.\n"
71  " (eg. '1920x1080')\n"
72  "-e | --encoder-params Encoding params. See \"Encoding Parameters\" chapter in\n"
73  " QuadraIntegration&ProgrammingGuide*.pdf for help.\n"
74  " Can be specified multiple (max %d) times,\n"
75  " must match the number of -o specified.\n"
76  " (Default: \"\")\n"
77  "-g | --encoder-gop Custom GOP for encoding. See \"Custom Gop Structure\" chapter in\n"
78  " QuadraIntegration&ProgrammingGuide*.pdf for help.\n"
79  " gopPresetIdx must be set to 0 to be in effect.\n"
80  " (Default: \"\")\n"
81  "-u | --hwupload (No argument) When enabled, upload raw frame to device first before encoding\n"
82  " Multiple input files and yuv444p format input are not supported in this mode\n"
84 }
85 
86 int main(int argc, char *argv[])
87 {
88  int i, ret = 0;
89  ni_demo_context_t ctx = {0};
90  char in_filename[MAX_INPUT_FILES][FILE_NAME_LEN] = {0};
91  char out_filename[MAX_OUTPUT_FILES][FILE_NAME_LEN] = {0};
92  FILE* input_fp[MAX_INPUT_FILES] = {0};
93  FILE* output_fp[MAX_OUTPUT_FILES] = {0};
94  int i_index = 0, s_index = 0, o_index = 0, e_index = 0, g_index = 0;
95  int input_total = 0, output_total = 0;
96  int enc_codec_format = -1;
97  ni_log_level_t log_level;
98  int xcoderGUID = 0;
99  char *n;
101  ni_sw_pix_fmt_t sw_pix_fmt = NI_SW_PIX_FMT_NONE;
102  int video_width[MAX_INPUT_FILES] = {0};
103  int video_height[MAX_INPUT_FILES] = {0};
104  char enc_conf_params[MAX_OUTPUT_FILES][2048] = {0};
105  char enc_gop_params[MAX_OUTPUT_FILES][2048] = {0};
106  ni_xcoder_params_t *p_enc_api_param = NULL;
107  int hwupload = 0;
108  int first_frame_uploaded = 0;
109  void *yuv_buf = NULL;
110  int send_rc = NI_TEST_RETCODE_SUCCESS, receive_rc = NI_TEST_RETCODE_SUCCESS;
111  ni_session_context_t enc_ctx[MAX_OUTPUT_FILES] = {0};
112  ni_session_context_t upl_ctx = {0};
113  ni_session_context_t sca_ctx = {0};
114  ni_session_data_io_t in_frame = {0};
115  ni_session_data_io_t out_packet[MAX_OUTPUT_FILES] = {0};
116  ni_session_data_io_t sw_pix_frame[2] = {0};
117  ni_session_data_io_t scale_frame = {0};
118  ni_session_data_io_t swin_frame = {0};
119  ni_session_data_io_t *p_in_frame;
120  uint64_t current_time, previous_time;
121  int end_of_all_streams = 0, read_size = 0, eos = 0;
122  niFrameSurface1_t *p_hwframe = NULL;
123 
124  int opt;
125  int opt_index;
126  const char *opt_string = "hvi:o:m:l:c:r:k:p:s:e:g:u";
127  static struct option long_options[] = {
128  {"help", no_argument, NULL, 'h'},
129  {"version", no_argument, NULL, 'v'},
130  {"input", required_argument, NULL, 'i'},
131  {"output", required_argument, NULL, 'o'},
132  {"enc-codec", required_argument, NULL, 'm'},
133  {"loglevel", required_argument, NULL, 'l'},
134  {"card", required_argument, NULL, 'c'},
135  {"repeat", required_argument, NULL, 'r'},
136  {"readframerate", required_argument, NULL, 'k'},
137  {"pix_fmt", required_argument, NULL, 'p'},
138  {"size", required_argument, NULL, 's'},
139  {"encoder-params", required_argument, NULL, 'e'},
140  {"encoder-gop", required_argument, NULL, 'g'},
141  {"hwupload", no_argument, NULL, 'u'},
142  {NULL, 0, NULL, 0},
143  };
144 
145  while ((opt = getopt_long(argc, argv, opt_string, long_options, &opt_index)) != -1)
146  {
147  switch (opt)
148  {
149  case 'h':
150  print_usage();
151  ret = 0;
152  goto end;
153  case 'v':
154  print_version();
155  ret = 0;
156  goto end;
157  case 'i':
158  if (i_index == MAX_INPUT_FILES)
159  {
160  ni_log(NI_LOG_ERROR, "Error: number of input files cannot exceed %d\n", MAX_INPUT_FILES);
161  ret = -1;
162  goto end;
163  }
164  strcpy(in_filename[i_index], optarg);
165  i_index++;
166  break;
167  case 'o':
168  if (o_index == MAX_OUTPUT_FILES)
169  {
170  ni_log(NI_LOG_ERROR, "Error: number of output files cannot exceed %d\n", MAX_OUTPUT_FILES);
171  ret = -1;
172  goto end;
173  }
174 
175  for (i = 0; i < o_index; i++)
176  {
177  if (0 == strcmp(out_filename[i], optarg))
178  {
179  ni_log(NI_LOG_ERROR, "Error: output file names must be unique: %s\n", optarg);
180  ret = -1;
181  goto end;
182  }
183  }
184 
185  strcpy(out_filename[o_index], optarg);
186  o_index++;
187  break;
188  case 'm':
189  // Accept both upper and lower case
190  for (i = 0; i < strlen(optarg); i++)
191  {
192  optarg[i] = (char)tolower((unsigned char)optarg[i]);
193  }
194  if (strcmp(optarg, "a") == 0 || strcmp(optarg, "avc") == 0)
195  {
196  enc_codec_format = NI_CODEC_FORMAT_H264;
197  }
198  else if (strcmp(optarg, "h") == 0 || strcmp(optarg, "hevc") == 0)
199  {
200  enc_codec_format = NI_CODEC_FORMAT_H265;
201  }
202  else if (strcmp(optarg, "x") == 0 || strcmp(optarg, "av1") == 0)
203  {
204  enc_codec_format = NI_CODEC_FORMAT_AV1;
205  }
206  else if (strcmp(optarg, "o") == 0 || strcmp(optarg, "obu") == 0)
207  {
208  enc_codec_format = NI_CODEC_FORMAT_AV1;
209  ctx.av1_output_obu = 1;
210  }
211  else
212  {
213  ni_log(NI_LOG_ERROR, "Error: Invalid value \"%s\" for -m | --dec-codec option\n"
214  "Must be one of [a|avc, h|hevc, x|av1, o|obu]\n", optarg);
215  ret = -1;
216  goto end;
217  }
218  break;
219  case 'l':
220  log_level = arg_to_ni_log_level(optarg);
221  if (log_level != NI_LOG_INVALID)
222  {
223  ni_log_set_level(log_level);
224  }
225  else
226  {
227  ni_log(NI_LOG_ERROR, "Error: Invalid value \"%s\" for -l | --loglevel option\n"
228  "Must be one of [none, fatal, error, info, debug, trace]\n", optarg);
229  ret = -1;
230  goto end;
231  }
232  break;
233  case 'c':
234  xcoderGUID = (int)strtol(optarg, &n, 10);
235  if (n == optarg || *n != '\0' || xcoderGUID < 0)
236  {
237  ni_log(NI_LOG_ERROR, "Error: Invalid value \"%s\" for -c | --card option\n"
238  "Must be a non-negative integer\n", optarg);
239  ret = -1;
240  goto end;
241  }
242  break;
243  case 'r':
244  ctx.loops_left = strtol(optarg, &n, 10);
245  if (n == optarg || *n != '\0' || ctx.loops_left <= 0)
246  {
247  ni_log(NI_LOG_ERROR, "Error: Invalid value \"%s\" for -r | --repeat option\n"
248  "Must be a positive integer\n", optarg);
249  ret = -1;
250  goto end;
251  }
252  break;
253  case 'k':
254  ctx.read_framerate = (int)strtol(optarg, &n, 10);
255  if (n == optarg || *n != '\0' || ctx.read_framerate < 0)
256  {
257  ni_log(NI_LOG_ERROR, "Error: Invalid value \"%s\" for -k | --readframerate option\n"
258  "Must be a non-negative integer\n", optarg);
259  ret = -1;
260  goto end;
261  }
262  break;
263  case 'p':
264  pix_fmt = ni_pixel_format_search(optarg);
265  if (pix_fmt == NI_PIX_FMT_NONE)
266  {
267  if (!strcmp(optarg, "yuv444p"))
268  {
269  sw_pix_fmt = NI_SW_PIX_FMT_YUV444P;
270  }
271  else
272  {
273  ni_log(NI_LOG_ERROR, "Error: Invalid value \"%s\" for -p | --pix_fmt option\n"
274  "Must be one of [yuv420p, yuv420p10le, nv12, p010le, rgba, gbra, argb, abgr, bgr0, yuv444p]\n",
275  optarg);
276  ret = -1;
277  goto end;
278  }
279  }
280  break;
281  case 's':
282  if (s_index == MAX_INPUT_FILES)
283  {
284  ni_log(NI_LOG_ERROR, "Error: number of input resolutions cannot exceed %d\n", MAX_INPUT_FILES);
285  ret = -1;
286  goto end;
287  }
288  video_width[s_index] = (int)strtol(optarg, &n, 10);
289  video_height[s_index] = atoi(n + 1);
290  if ((*n != 'x') || (video_width[s_index] <= 0 || video_height[s_index] <= 0))
291  {
292  ni_log(NI_LOG_ERROR, "Error: Invalid value \"%s\" for -s | --size option\n"
293  "Must be in format [WIDTHxHEIGHT] (e.g. 1920x1080)\n", optarg);
294  ret = -1;
295  goto end;
296  }
297  s_index++;
298  break;
299  case 'e':
300  if (e_index == MAX_OUTPUT_FILES)
301  {
302  ni_log(NI_LOG_ERROR, "Error: number of encoder config cannot exceed %d\n", MAX_OUTPUT_FILES);
303  ret = -1;
304  goto end;
305  }
306  strcpy(enc_conf_params[e_index], optarg);
307  e_index++;
308  break;
309  case 'g':
310  if (g_index == MAX_OUTPUT_FILES)
311  {
312  ni_log(NI_LOG_ERROR, "Error: number of encoder gop settings cannot exceed %d\n", MAX_OUTPUT_FILES);
313  ret = -1;
314  goto end;
315  }
316  strcpy(enc_gop_params[g_index], optarg);
317  g_index++;
318  break;
319  case 'u':
320  hwupload = 1;
321  break;
322  default:
323  print_usage();
324  ret = -1;
325  goto end;
326  }
327  }
328 
329  if (i_index == 0) {
330  ni_log(NI_LOG_ERROR, "Error: Missing input file argument (-i | --input)\n");
331  ret = -1;
332  goto end;
333  }
334 
335  if (o_index == 0) {
336  ni_log(NI_LOG_ERROR, "Error: Missing output file argument (-o | --output)\n");
337  ret = -1;
338  goto end;
339  }
340 
341  if (s_index != i_index) {
342  ni_log(NI_LOG_ERROR, "Error: Number of input resolution specified does not match number of input files\n");
343  ret = -1;
344  goto end;
345  }
346 
347  if (enc_codec_format == -1) {
348  ni_log(NI_LOG_ERROR, "Error: Missing encoder codec argument (-m | --enc-codec)\n");
349  ret = -1;
350  goto end;
351  }
352 
353  input_total = i_index;
354  i_index = 0;
355  if (ctx.loops_left > 1 && input_total > 1)
356  {
357  ni_log(NI_LOG_ERROR, "Error: multiple input files not supported when loops %u greater than 1\n", ctx.loops_left);
358  ret = -1;
359  goto end;
360  }
361 
362  output_total = o_index;
363  if (sw_pix_fmt == NI_SW_PIX_FMT_YUV444P && output_total != 2)
364  {
365  ni_log(NI_LOG_ERROR, "Error: Must indicate 2 output files for yuv444p encoding\n");
366  ret = -1;
367  goto end;
368  }
369 
370  // Check for features not supported with hwupload
371  if (hwupload && ctx.read_framerate)
372  {
373  ni_log(NI_LOG_ERROR, "Error: -k | --readframerate option is not supported in hwupload mode\n");
374  ret = -1;
375  goto end;
376  }
377  if (hwupload && input_total > 1)
378  {
379  ni_log(NI_LOG_ERROR, "Error: multiple input (sequence change) is not supported in hwupload mode\n");
380  ret = -1;
381  goto end;
382  }
383  if (hwupload && sw_pix_fmt == NI_SW_PIX_FMT_YUV444P)
384  {
385  ni_log(NI_LOG_ERROR, "Error: yuv444p input is not supported in hwupload mode\n");
386  ret = -1;
387  goto end;
388  }
389 
390  if (ni_posix_memalign(&yuv_buf, sysconf(_SC_PAGESIZE), MAX_YUV_FRAME_SIZE))
391  {
392  ni_log(NI_LOG_ERROR, "Error: failed to allocate YUV data buffer\n");
393  ret = -1;
394  goto end;
395  }
396 
397  for (i = 0; i < input_total; i++)
398  {
399  if (!in_filename[i][0])
400  {
401  ni_log(NI_LOG_ERROR, "Error: invalid input file %d\n", i);
402  ret = -1;
403  goto end;
404  }
405 
406  input_fp[i] = fopen(in_filename[i], "rb");
407 
408  if (!input_fp[i])
409  {
410  ni_log(NI_LOG_ERROR, "Error: Failed to open input %s\n", in_filename[i]);
411  ret = -1;
412  goto end;
413  }
414  ni_log(NI_LOG_INFO, "Opened input file: %s\n", in_filename[i]);
415  }
416 
417  ctx.total_file_size = get_total_file_size(input_fp[0]);
418  ctx.curr_file_offset = 0;
419 
420  for (i = 0; i < output_total; i++)
421  {
422  if (strcmp(out_filename[i], "null") != 0 &&
423  strcmp(out_filename[i], "/dev/null") != 0)
424  {
425  output_fp[i] = fopen(out_filename[i], "wb");
426  if (!output_fp[i])
427  {
428  ni_log(NI_LOG_ERROR, "Error: Failed to open %s\n", out_filename[i]);
429  ret = -1;
430  goto end;
431  }
432  ni_log(NI_LOG_INFO, "Opened output file: %s\n", out_filename[i]);
433  } else
434  {
435  output_fp[i] = NULL;
436  ni_log(NI_LOG_INFO, "Note: Requested NULL output for index %d, no output file will be generated\n", i);
437  }
438  }
439 
440  p_enc_api_param = calloc(output_total, sizeof(ni_xcoder_params_t));
441  if (!p_enc_api_param)
442  {
443  ni_log(NI_LOG_ERROR, "Error: Failed to allocate memory for p_enc_api_param\n");
444  ret = -1;
445  goto end;
446  }
447 
448  for (i = 0; i < output_total; i++)
449  {
450  if (ni_device_session_context_init(&enc_ctx[i]) < 0)
451  {
452  ni_log(NI_LOG_ERROR, "Error: init encoder %d context error\n", i);
453  ret = -1;
454  goto end;
455  }
456  }
457 
458  for (i = 0; i < output_total; i++)
459  {
460  enc_ctx[i].codec_format = enc_codec_format;
461  }
462 
463  ctx.start_time = ni_gettime_ns();
465 
466  if (hwupload)
467  {
468  if (ni_device_session_context_init(&upl_ctx) < 0)
469  {
470  ni_log(NI_LOG_ERROR, "Error: init uploader context error\n");
471  ret = -1;
472  goto end;
473  }
474 
475  if (ni_device_session_context_init(&sca_ctx) < 0)
476  {
477  ni_log(NI_LOG_ERROR, "Error: init scale context error\n");
478  ret = -1;
479  goto end;
480  }
481 
482  ni_log(NI_LOG_INFO, "Starting hwupload + encoding mode: video resolution %dx%d\n",
483  video_width[0], video_height[0]);
484  // buffers by downstream entity like encoders
485  ret = uploader_open_session(&upl_ctx, xcoderGUID, video_width[0] < NI_MIN_WIDTH ? NI_MIN_WIDTH : video_width[0],
486  video_height[0] < NI_MIN_HEIGHT ? NI_MIN_HEIGHT : video_height[0], pix_fmt, 0, 3);
487  if (ret != 0)
488  {
489  goto end;
490  }
491 
492  p_hwframe = hwupload_frame(&ctx, &upl_ctx, &sca_ctx, &swin_frame, &in_frame, &scale_frame, pix_fmt,
493  video_width[0], video_height[0], input_fp[0], yuv_buf, &eos);
494  if (p_hwframe == NULL)
495  {
496  ret = -1;
497  goto end;
498  }
499 
500  ret = encoder_open(&enc_ctx[0], p_enc_api_param, output_total, enc_conf_params, enc_gop_params,
501  NULL, video_width[0], video_height[0], 30, 1, 200000, enc_codec_format,
502  is_ni_enc_pix_fmt(pix_fmt) ? pix_fmt : NI_PIX_FMT_YUV420P,
503  0, xcoderGUID, p_hwframe, 0, false);
504  if (ret != 0)
505  {
506  goto end;
507  }
508 
509  while (!end_of_all_streams &&
510  (send_rc == NI_TEST_RETCODE_SUCCESS || receive_rc== NI_TEST_RETCODE_SUCCESS ||
511  (send_rc == NI_TEST_RETCODE_EAGAIN && receive_rc == NI_TEST_RETCODE_EAGAIN)))
512  {
513  if (first_frame_uploaded && !eos)
514  {
515  p_hwframe = hwupload_frame(&ctx, &upl_ctx, &sca_ctx, &swin_frame, &in_frame, &scale_frame, pix_fmt,
516  video_width[0], video_height[0], input_fp[0], yuv_buf, &eos);
518  {
519  ni_log(NI_LOG_DEBUG, "No space to write to, try to read a packet\n");
520  p_in_frame = &in_frame;
521  goto receive_pkt;
522  } else if (p_hwframe == NULL)
523  {
525  break;
526  }
527  }
528 
529  // Sending
530  p_in_frame = is_ni_enc_pix_fmt(pix_fmt) ? &in_frame : &scale_frame;
531  for (i = 0; i < output_total; i++)
532  {
533  ctx.curr_enc_index = i;
534  send_rc = encoder_send_data3(&ctx, &enc_ctx[i], p_in_frame, video_width[0], video_height[0], eos);
535  first_frame_uploaded = 1; //since first frame read before while-loop
536  if (send_rc < 0) //Error
537  {
538  ni_log(NI_LOG_ERROR, "enc %d send error, quit !\n", i);
539  ni_hw_frame_ref(p_hwframe);
540  end_of_all_streams = 1;
541  break;
542  }
543  //track in array with unique index, free when enc read finds
544  //this must be implemented in application space for complete
545  //tracking of hwframes
546  if (!ctx.enc_resend[i])
547  {
548  //successful read means there is recycle to check
549  ni_hw_frame_ref(p_hwframe);
550  } else
551  {
552  ni_log(NI_LOG_DEBUG, "enc %d need to re-send !\n", i);
553  ni_usleep(500);
554  i--;
555  continue;
556  }
557  }
558  if (end_of_all_streams)
559  break;
560 
561 receive_pkt:
562  receive_rc = encoder_receive(&ctx, enc_ctx, p_in_frame, out_packet,
563  video_width[0], video_height[0], output_total, output_fp);
564  for (i = 0; receive_rc >= 0 && i < output_total; i++)
565  {
566  if (!ctx.enc_eos_received[i])
567  {
568  ni_log(NI_LOG_DEBUG, "enc %d continues to read!\n", i);
569  end_of_all_streams = 0;
570  break;
571  } else
572  {
573  ni_log(NI_LOG_DEBUG, "enc %d eos !\n", i);
574  end_of_all_streams = 1;
575  }
576  }
577 
579  if (current_time - previous_time >= (uint64_t)1000000000) {
580  for (i = 0; i < output_total; i++)
581  {
582  ni_log(NI_LOG_INFO, "Encoder %d stats: received %u packets, fps %.2f, total bytes %u\n",
583  i, ctx.num_packets_received[i],
584  (float)enc_ctx[i].frame_num / (float)(current_time - ctx.start_time) * (float)1000000000,
586  }
588  }
589  }
590 
592  if (!is_ni_enc_pix_fmt(pix_fmt))
593  { //Uploading rgba requires scaler conversion so close the session too
595  }
596  }
597  else
598  {
599  in_frame.data.frame.pixel_format = pix_fmt;
600  ret = encoder_open(enc_ctx, p_enc_api_param, output_total,
601  enc_conf_params, enc_gop_params, NULL, video_width[0],
602  video_height[0], 30, 1, 200000,
603  enc_codec_format, pix_fmt, 0, xcoderGUID, NULL,
604  0, (sw_pix_fmt != NI_SW_PIX_FMT_NONE) ? false : true);
605  // zero copy is not supported for YUV444P
606  if (ret != 0)
607  {
608  goto end;
609  }
610 
611  ni_log(NI_LOG_INFO, "Starting to encode: video resolution %dx%d\n", video_width[0], video_height[0]);
612 
613  while (!end_of_all_streams &&
614  (send_rc == NI_TEST_RETCODE_SUCCESS || receive_rc == NI_TEST_RETCODE_SUCCESS ||
615  (send_rc == NI_TEST_RETCODE_EAGAIN && receive_rc == NI_TEST_RETCODE_EAGAIN)))
616  {
617  read_size = read_yuv_from_file(&ctx, input_fp[i_index], yuv_buf,
618  video_width[i_index], video_height[i_index],
619  pix_fmt, sw_pix_fmt, &eos,
620  enc_ctx[0].session_run_state);
621  if (read_size < 0)
622  {
623  break;
624  }
625 
626  // YUV444P reading
627  if (sw_pix_fmt != NI_SW_PIX_FMT_NONE)
628  {
629  ret = convert_yuv_444p_to_420p(&sw_pix_frame[0], eos ? NULL : yuv_buf,
630  video_width[i_index], video_height[i_index],
631  sw_pix_fmt, 0, enc_codec_format);
632  if (ret < 0)
633  {
634  break;
635  }
636  }
637 
638  for (i = 0; i < output_total; i++)
639  {
640  if (sw_pix_fmt != NI_SW_PIX_FMT_NONE)
641  {
642  ctx.curr_enc_index = i;
643  send_rc = encoder_send_data3(&ctx, &enc_ctx[i], &sw_pix_frame[i],
644  video_width[i_index], video_height[i_index], eos);
645  } else
646  {
647  ctx.curr_enc_index = i;
648  send_rc = encoder_send_data(&ctx, &enc_ctx[i],
649  &in_frame, eos ? NULL : yuv_buf,
650  video_width[i_index], video_height[i_index],
651  i_index == input_total - 1);
652  }
653 
654  if (send_rc == NI_TEST_RETCODE_EAGAIN)
655  {
656  // retry send to same encoder session
657  i--;
658  continue;
659  } else if (send_rc == NI_TEST_RETCODE_NEXT_INPUT) // next input (will trigger sequence change)
660  {
661  i_index++;
662  ctx.total_file_size = get_total_file_size(input_fp[i_index]);
663  ctx.curr_file_offset = 0;
664  send_rc = NI_TEST_RETCODE_SUCCESS;
665  }
666  }
667 
668  receive_rc = encoder_receive(&ctx, enc_ctx, &in_frame, out_packet,
669  video_width[0], video_height[0], output_total, output_fp);
670  for (i = 0; receive_rc >= 0 && i < output_total; i++)
671  {
672  if (!ctx.enc_eos_received[i])
673  {
674  ni_log(NI_LOG_DEBUG, "enc %d continues to read!\n", i);
675  end_of_all_streams = 0;
676  break;
677  } else
678  {
679  ni_log(NI_LOG_DEBUG, "enc %d eos !\n", i);
680  end_of_all_streams = 1;
681  }
682  }
683 
685  if (current_time - previous_time >= (uint64_t)1000000000) {
686  for (i = 0; i < output_total; i++)
687  {
688  ni_log(NI_LOG_INFO, "Encoder %d stats: received %u packets, fps %.2f, total bytes %u\n",
689  i, ctx.num_packets_received[i],
690  (float)enc_ctx[i].frame_num / (float)(current_time - ctx.start_time) * (float)1000000000,
693  }
694  }
695  }
696  }
697 
698  encoder_stat_report_and_close(&ctx, enc_ctx, output_total);
699 
700 end:
701  ni_frame_buffer_free(&in_frame.data.frame);
702  ni_frame_buffer_free(&swin_frame.data.frame);
703  for (i = 0; i < output_total; i++)
704  {
705  ni_packet_buffer_free(&out_packet[i].data.packet);
706  }
707  for (i = 0; i < sizeof(sw_pix_frame)/sizeof(ni_session_data_io_t); i++)
708  {
709  ni_frame_buffer_free(&sw_pix_frame[i].data.frame);
710  }
711 
714  for (i = 0; i < output_total; i++)
715  {
716  ni_device_session_context_clear(&enc_ctx[i]);
717  if (output_fp[i] != NULL)
718  {
719  fclose(output_fp[i]);
720  }
721  }
722 
723  for (i = 0; i < input_total; i++)
724  {
725  if (input_fp[i])
726  {
727  fclose(input_fp[i]);
728  }
729  }
730 
731  ni_aligned_free(yuv_buf);
732  free(p_enc_api_param);
733 
734  return ret;
735 }
uploader_open_session
int uploader_open_session(ni_session_context_t *p_upl_ctx, int iXcoderGUID, int width, int height, ni_pix_fmt_t pix_fmt, int is_p2p, int pool_size)
Uploader session open.
Definition: ni_generic_utils.c:894
ni_log_level_t
ni_log_level_t
Definition: ni_log.h:55
encoder_send_data
int encoder_send_data(ni_demo_context_t *p_ctx, ni_session_context_t *p_enc_ctx, ni_session_data_io_t *p_in_data, void *yuv_buf, int input_video_width, int input_video_height, int is_last_input)
Send encoder input data, read from input file.
Definition: ni_encode_utils.c:735
_ni_demo_context::loops_left
uint64_t loops_left
Definition: ni_generic_utils.h:117
ni_pix_fmt_t
ni_pix_fmt_t
Definition: ni_device_api.h:260
get_total_file_size
uint64_t get_total_file_size(FILE *fp)
Definition: ni_generic_utils.c:250
ni_frame_buffer_free
ni_retcode_t ni_frame_buffer_free(ni_frame_t *p_frame)
Free frame buffer that was previously allocated with either ni_frame_buffer_alloc or ni_encoder_frame...
Definition: ni_device_api.c:3561
ni_hw_frame_ref
void ni_hw_frame_ref(const niFrameSurface1_t *p_surface)
Definition: ni_generic_utils.c:658
encoder_stat_report_and_close
void encoder_stat_report_and_close(ni_demo_context_t *p_ctx, ni_session_context_t *p_enc_ctx_list, int output_total)
Definition: ni_encode_utils.c:2252
ni_generic_utils.h
print_version
void print_version(void)
Definition: ni_generic_utils.c:70
_ni_demo_context::total_file_size
uint64_t total_file_size
Definition: ni_generic_utils.h:116
NI_PIX_FMT_YUV420P
@ NI_PIX_FMT_YUV420P
Definition: ni_device_api.h:262
_ni_session_data_io::packet
ni_packet_t packet
Definition: ni_device_api.h:2871
NI_DEVICE_TYPE_UPLOAD
@ NI_DEVICE_TYPE_UPLOAD
Definition: ni_defs.h:353
_ni_session_context::status
int status
Definition: ni_device_api.h:1524
ni_encode_utils.h
current_time
struct timeval current_time
Definition: ni_p2p_read_test.c:80
ni_log_set_level
void ni_log_set_level(ni_log_level_t level)
Set ni_log_level.
Definition: ni_log.c:202
ni_gettime_ns
uint64_t ni_gettime_ns(void)
Definition: ni_util.c:1998
MAX_OUTPUT_FILES
#define MAX_OUTPUT_FILES
Definition: ni_generic_utils.h:48
required_argument
#define required_argument
Definition: ni_getopt.h:86
NI_XCODER_REVISION
#define NI_XCODER_REVISION
Definition: ni_defs.h:95
is_ni_enc_pix_fmt
int is_ni_enc_pix_fmt(ni_pix_fmt_t pix_fmt)
Definition: ni_generic_utils.c:81
ni_packet_buffer_free
ni_retcode_t ni_packet_buffer_free(ni_packet_t *p_packet)
Free packet buffer that was previously allocated with ni_packet_buffer_alloc.
Definition: ni_device_api.c:3843
no_argument
#define no_argument
Definition: ni_getopt.h:85
NI_PIX_FMT_NONE
@ NI_PIX_FMT_NONE
Definition: ni_device_api.h:277
_ni_demo_context::curr_file_offset
uint64_t curr_file_offset
Definition: ni_generic_utils.h:115
MAX_INPUT_FILES
#define MAX_INPUT_FILES
Definition: ni_generic_utils.h:47
NI_TEST_RETCODE_NEXT_INPUT
#define NI_TEST_RETCODE_NEXT_INPUT
Definition: ni_generic_utils.h:54
previous_time
struct timeval previous_time
Definition: ni_p2p_read_test.c:79
FILE_NAME_LEN
#define FILE_NAME_LEN
Definition: ni_generic_utils.h:46
NI_SW_PIX_FMT_NONE
@ NI_SW_PIX_FMT_NONE
Definition: ni_generic_utils.h:78
ni_log.h
Logging definitions.
_ni_demo_context
Definition: ni_generic_utils.h:109
NI_LOG_INFO
@ NI_LOG_INFO
Definition: ni_log.h:61
arg_to_ni_log_level
ni_log_level_t arg_to_ni_log_level(const char *arg_str)
Convert terminal arg string to ni_log_level_t.
Definition: ni_log.c:262
NI_LOG_ERROR
@ NI_LOG_ERROR
Definition: ni_log.h:60
_ni_demo_context::enc_resend
int enc_resend[MAX_OUTPUT_FILES]
Definition: ni_generic_utils.h:145
NI_TEST_RETCODE_EAGAIN
#define NI_TEST_RETCODE_EAGAIN
Definition: ni_generic_utils.h:53
MAX_YUV_FRAME_SIZE
#define MAX_YUV_FRAME_SIZE
Definition: ni_generic_utils.h:60
encoder_receive
int encoder_receive(ni_demo_context_t *p_ctx, ni_session_context_t *enc_ctx_list, ni_session_data_io_t *in_frame, ni_session_data_io_t *pkt, int width, int height, int output_total, FILE **pfs_list)
Definition: ni_encode_utils.c:2181
NI_TEST_RETCODE_FAILURE
#define NI_TEST_RETCODE_FAILURE
Definition: ni_generic_utils.h:50
NI_CODEC_FORMAT_AV1
@ NI_CODEC_FORMAT_AV1
Definition: ni_device_api.h:915
_ni_session_data_io
Definition: ni_device_api.h:2866
ni_log
void ni_log(ni_log_level_t level, const char *fmt,...)
print log message using ni_log_callback
Definition: ni_log.c:183
NI_LOG_INVALID
@ NI_LOG_INVALID
Definition: ni_log.h:57
NI_TEST_RETCODE_SUCCESS
#define NI_TEST_RETCODE_SUCCESS
Definition: ni_generic_utils.h:51
getopt_long
int getopt_long(int argc, char *argv[], const char *optstring, const struct option *longopts, int *longindex)
Definition: ni_getopt.c:99
ni_usleep
void ni_usleep(int64_t usec)
Definition: ni_util.c:358
ni_pixel_format_search
ni_pix_fmt_t ni_pixel_format_search(const char *name)
Definition: ni_generic_utils.c:87
hwupload_frame
niFrameSurface1_t * hwupload_frame(ni_demo_context_t *p_ctx, ni_session_context_t *p_upl_ctx, ni_session_context_t *p_sca_ctx, ni_session_data_io_t *p_sw_data, ni_session_data_io_t *p_hw_data, ni_session_data_io_t *p_scale_data, ni_pix_fmt_t pix_fmt, int width, int height, FILE *pfs, void *yuv_buf, int *eos)
Definition: ni_generic_utils.c:937
_ni_session_context::frame_num
uint64_t frame_num
Definition: ni_device_api.h:1531
ni_device_session_context_clear
void ni_device_session_context_clear(ni_session_context_t *p_ctx)
Clear already allocated session context.
Definition: ni_device_api.c:249
convert_yuv_444p_to_420p
int convert_yuv_444p_to_420p(ni_session_data_io_t *p_frame, void *yuv_buf, int width, int height, ni_sw_pix_fmt_t sw_pix_fmt, int mode, ni_codec_format_t codec_format)
Definition: ni_generic_utils.c:448
optarg
char * optarg
Definition: ni_getopt.c:33
NI_DEVICE_TYPE_SCALER
@ NI_DEVICE_TYPE_SCALER
Definition: ni_defs.h:348
encoder_open
int encoder_open(ni_session_context_t *enc_ctx_list, ni_xcoder_params_t *p_api_param_list, int output_total, char p_enc_conf_params[][2048], char p_enc_conf_gop[][2048], ni_frame_t *p_ni_frame, int width, int height, int fps_num, int fps_den, int bitrate, int codec_format, ni_pix_fmt_t pix_fmt, int aspect_ratio_idc, int xcoder_guid, niFrameSurface1_t *p_surface, int multi_thread, bool check_zerocopy)
Definition: ni_encode_utils.c:1999
_ni_session_context
Definition: ni_device_api.h:1408
_niFrameSurface1
Definition: ni_device_api.h:2793
_ni_session_data_io::data
union _ni_session_data_io::@19 data
main
int main(int argc, char *argv[])
Definition: ni_xcoder_encode.c:86
_ni_demo_context::start_time
uint64_t start_time
Definition: ni_generic_utils.h:132
_ni_xcoder_params
Definition: ni_device_api.h:2713
option
Definition: ni_getopt.h:73
NI_SW_PIX_FMT_YUV444P
@ NI_SW_PIX_FMT_YUV444P
Definition: ni_generic_utils.h:79
ni_sw_pix_fmt_t
ni_sw_pix_fmt_t
Definition: ni_generic_utils.h:76
_ni_session_context::codec_format
uint32_t codec_format
Definition: ni_device_api.h:1486
read_yuv_from_file
int read_yuv_from_file(ni_demo_context_t *p_ctx, FILE *pfs, void *yuv_buf, int width, int height, ni_pix_fmt_t pix_fmt, ni_sw_pix_fmt_t sw_pix_fmt, int *eos, ni_session_run_state_t run_state)
Definition: ni_generic_utils.c:413
ni_posix_memalign
int ni_posix_memalign(void **memptr, size_t alignment, size_t size)
Allocate aligned memory.
Definition: ni_util.c:198
_ni_session_data_io::frame
ni_frame_t frame
Definition: ni_device_api.h:2870
atoi
#define atoi(p_str)
Definition: ni_device_api.c:7178
_ni_demo_context::num_packets_received
uint64_t num_packets_received[MAX_OUTPUT_FILES]
Definition: ni_generic_utils.h:130
_ni_demo_context::read_framerate
int read_framerate
Definition: ni_generic_utils.h:120
_ni_demo_context::enc_eos_received
int enc_eos_received[MAX_OUTPUT_FILES]
Definition: ni_generic_utils.h:148
NI_MIN_HEIGHT
#define NI_MIN_HEIGHT
Definition: ni_device_api.h:126
_ni_frame::pixel_format
int pixel_format
Definition: ni_device_api.h:2672
_ni_demo_context::av1_output_obu
uint8_t av1_output_obu
Definition: ni_generic_utils.h:138
ni_util.h
Utility definitions.
NI_RETCODE_NVME_SC_WRITE_BUFFER_FULL
@ NI_RETCODE_NVME_SC_WRITE_BUFFER_FULL
Definition: ni_defs.h:534
ni_aligned_free
#define ni_aligned_free(p_memptr)
Definition: ni_util.h:399
NI_CODEC_FORMAT_H264
@ NI_CODEC_FORMAT_H264
Definition: ni_device_api.h:911
NI_MIN_WIDTH
#define NI_MIN_WIDTH
Definition: ni_device_api.h:124
ni_device_session_context_init
ni_retcode_t ni_device_session_context_init(ni_session_context_t *p_ctx)
Initialize already allocated session context to a known state.
Definition: ni_device_api.c:156
_ni_demo_context::enc_total_bytes_received
uint64_t enc_total_bytes_received[MAX_OUTPUT_FILES]
Definition: ni_generic_utils.h:127
NI_LOG_DEBUG
@ NI_LOG_DEBUG
Definition: ni_log.h:62
_ni_demo_context::curr_enc_index
uint8_t curr_enc_index
Definition: ni_generic_utils.h:123
ni_getopt.h
Implementation of getopt() and getopt_long() for Windows environment.
ni_device_session_close
ni_retcode_t ni_device_session_close(ni_session_context_t *p_ctx, int eos_recieved, ni_device_type_t device_type)
Close device session that was previously opened by calling ni_device_session_open() If device_type is...
Definition: ni_device_api.c:1379
encoder_send_data3
int encoder_send_data3(ni_demo_context_t *p_ctx, ni_session_context_t *p_enc_ctx, ni_session_data_io_t *p_in_data, int input_video_width, int input_video_height, int eos)
Send encoder input data, read from uploader instance hwframe.
Definition: ni_encode_utils.c:1179
NI_CODEC_FORMAT_H265
@ NI_CODEC_FORMAT_H265
Definition: ni_device_api.h:912