libxcoder  5.3.1
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, bgra, 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 >= 1))
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  // Only in hwupload mode, the pixel formats not directly supported by encoder
391  // will be converted to yuv420p using 2D engine
392  if (!hwupload && !is_ni_enc_pix_fmt(pix_fmt) && sw_pix_fmt == NI_SW_PIX_FMT_NONE)
393  {
394  ni_log(NI_LOG_ERROR, "Error: pixel format %s is only supported in hwupload mode\n",
395  ni_pixel_format_name(pix_fmt));
396  ret = -1;
397  goto end;
398  }
399 
400  if (ni_posix_memalign(&yuv_buf, sysconf(_SC_PAGESIZE), MAX_YUV_FRAME_SIZE))
401  {
402  ni_log(NI_LOG_ERROR, "Error: failed to allocate YUV data buffer\n");
403  ret = -1;
404  goto end;
405  }
406 
407  for (i = 0; i < input_total; i++)
408  {
409  if (!in_filename[i][0])
410  {
411  ni_log(NI_LOG_ERROR, "Error: invalid input file %d\n", i);
412  ret = -1;
413  goto end;
414  }
415 
416  input_fp[i] = fopen(in_filename[i], "rb");
417 
418  if (!input_fp[i])
419  {
420  ni_log(NI_LOG_ERROR, "Error: Failed to open input %s\n", in_filename[i]);
421  ret = -1;
422  goto end;
423  }
424  ni_log(NI_LOG_INFO, "Opened input file: %s\n", in_filename[i]);
425  }
426 
427  ctx.total_file_size = get_total_file_size(input_fp[0]);
428  ctx.curr_file_offset = 0;
429 
430  for (i = 0; i < output_total; i++)
431  {
432  if (strcmp(out_filename[i], "null") != 0 &&
433  strcmp(out_filename[i], "/dev/null") != 0)
434  {
435  output_fp[i] = fopen(out_filename[i], "wb");
436  if (!output_fp[i])
437  {
438  ni_log(NI_LOG_ERROR, "Error: Failed to open %s\n", out_filename[i]);
439  ret = -1;
440  goto end;
441  }
442  ni_log(NI_LOG_INFO, "Opened output file: %s\n", out_filename[i]);
443  } else
444  {
445  output_fp[i] = NULL;
446  ni_log(NI_LOG_INFO, "Note: Requested NULL output for index %d, no output file will be generated\n", i);
447  }
448  }
449 
450  p_enc_api_param = calloc(output_total, sizeof(ni_xcoder_params_t));
451  if (!p_enc_api_param)
452  {
453  ni_log(NI_LOG_ERROR, "Error: Failed to allocate memory for p_enc_api_param\n");
454  ret = -1;
455  goto end;
456  }
457 
458  for (i = 0; i < output_total; i++)
459  {
460  if (ni_device_session_context_init(&enc_ctx[i]) < 0)
461  {
462  ni_log(NI_LOG_ERROR, "Error: init encoder %d context error\n", i);
463  ret = -1;
464  goto end;
465  }
466  }
467 
468  for (i = 0; i < output_total; i++)
469  {
470  enc_ctx[i].codec_format = enc_codec_format;
471  }
472 
473  ctx.start_time = ni_gettime_ns();
475 
476  if (hwupload)
477  {
478  if (ni_device_session_context_init(&upl_ctx) < 0)
479  {
480  ni_log(NI_LOG_ERROR, "Error: init uploader context error\n");
481  ret = -1;
482  goto end;
483  }
484 
485  if (ni_device_session_context_init(&sca_ctx) < 0)
486  {
487  ni_log(NI_LOG_ERROR, "Error: init scale context error\n");
488  ret = -1;
489  goto end;
490  }
491 
492  ni_log(NI_LOG_INFO, "Starting hwupload + encoding mode: video resolution %dx%d\n",
493  video_width[0], video_height[0]);
494  // buffers by downstream entity like encoders
495  ret = uploader_open_session(&upl_ctx, xcoderGUID, video_width[0] < NI_MIN_WIDTH ? NI_MIN_WIDTH : video_width[0],
496  video_height[0] < NI_MIN_HEIGHT ? NI_MIN_HEIGHT : video_height[0], pix_fmt, 0, 3);
497  if (ret != 0)
498  {
499  goto end;
500  }
501 
502  p_hwframe = hwupload_frame(&ctx, &upl_ctx, &sca_ctx, &swin_frame, &in_frame, &scale_frame, pix_fmt,
503  video_width[0], video_height[0], input_fp[0], yuv_buf, &eos);
504  if (p_hwframe == NULL)
505  {
506  ret = -1;
507  goto end;
508  }
509 
510  ret = encoder_open(&ctx, &enc_ctx[0], p_enc_api_param, output_total, enc_conf_params, enc_gop_params,
511  NULL, video_width[0], video_height[0], 30, 1, 200000, enc_codec_format,
512  is_ni_enc_pix_fmt(pix_fmt) ? pix_fmt : NI_PIX_FMT_YUV420P,
513  0, xcoderGUID, p_hwframe, 0, false);
514  if (ret != 0)
515  {
516  goto end;
517  }
518 
519  do
520  {
521  receive_rc = encoder_receive(&ctx, enc_ctx, &in_frame, out_packet,
522  video_width[0], video_height[0], output_total, output_fp);
523  }
524  while (receive_rc == NI_TEST_RETCODE_EAGAIN);
525 
526  if (receive_rc == NI_TEST_RETCODE_SUCCESS)
527  {
528  ni_log(NI_LOG_INFO, "Got encoded sequence header packet\n");
529  }
530  else
531  {
532  ni_log(NI_LOG_ERROR, "Failed to get encoded sequence header packet, retcode %d\n", receive_rc);
533  ret = receive_rc;
534  goto end;
535  }
536 
537  while (!end_of_all_streams &&
538  (send_rc == NI_TEST_RETCODE_SUCCESS || receive_rc== NI_TEST_RETCODE_SUCCESS ||
539  (send_rc == NI_TEST_RETCODE_EAGAIN && receive_rc == NI_TEST_RETCODE_EAGAIN)))
540  {
541  if (first_frame_uploaded && !eos)
542  {
543  p_hwframe = hwupload_frame(&ctx, &upl_ctx, &sca_ctx, &swin_frame, &in_frame, &scale_frame, pix_fmt,
544  video_width[0], video_height[0], input_fp[0], yuv_buf, &eos);
546  {
547  ni_log(NI_LOG_DEBUG, "No space to write to, try to read a packet\n");
548  p_in_frame = &in_frame;
549  goto receive_pkt;
550  } else if (p_hwframe == NULL)
551  {
553  break;
554  }
555  }
556 
557  // Sending
558  p_in_frame = is_ni_enc_pix_fmt(pix_fmt) ? &in_frame : &scale_frame;
559  for (i = 0; i < output_total; i++)
560  {
561  ctx.curr_enc_index = i;
562  send_rc = encoder_send_data3(&ctx, &enc_ctx[i], p_in_frame, video_width[0], video_height[0], eos);
563  first_frame_uploaded = 1; //since first frame read before while-loop
564  if (send_rc < 0) //Error
565  {
566  ni_log(NI_LOG_ERROR, "enc %d send error, quit !\n", i);
567  ni_hw_frame_ref(p_hwframe);
568  end_of_all_streams = 1;
569  break;
570  }
571  //track in array with unique index, free when enc read finds
572  //this must be implemented in application space for complete
573  //tracking of hwframes
574  if (!ctx.enc_resend[i])
575  {
576  //successful read means there is recycle to check
577  ni_hw_frame_ref(p_hwframe);
578  } else
579  {
580  ni_log(NI_LOG_DEBUG, "enc %d need to re-send !\n", i);
581  ni_usleep(500);
582  i--;
583  continue;
584  }
585  }
586  if (end_of_all_streams)
587  break;
588 
589 receive_pkt:
590  receive_rc = encoder_receive(&ctx, enc_ctx, p_in_frame, out_packet,
591  video_width[0], video_height[0], output_total, output_fp);
592  for (i = 0; receive_rc >= 0 && i < output_total; i++)
593  {
594  if (!ctx.enc_eos_received[i])
595  {
596  ni_log(NI_LOG_DEBUG, "enc %d continues to read!\n", i);
597  end_of_all_streams = 0;
598  break;
599  } else
600  {
601  ni_log(NI_LOG_DEBUG, "enc %d eos !\n", i);
602  end_of_all_streams = 1;
603  }
604  }
605 
607  if (current_time - previous_time >= (uint64_t)1000000000) {
608  for (i = 0; i < output_total; i++)
609  {
610  ni_log(NI_LOG_INFO, "Encoder %d stats: received %u packets, fps %.2f, total bytes %u\n",
611  i, ctx.num_packets_received[i],
612  (float)enc_ctx[i].frame_num / (float)(current_time - ctx.start_time) * (float)1000000000,
614  }
616  }
617  }
618 
620  if (!is_ni_enc_pix_fmt(pix_fmt))
621  { //Uploading rgba requires scaler conversion so close the session too
623  }
624  }
625  else
626  {
627  in_frame.data.frame.pixel_format = pix_fmt;
628  ret = encoder_open(&ctx, enc_ctx, p_enc_api_param, output_total,
629  enc_conf_params, enc_gop_params, NULL, video_width[0],
630  video_height[0], 30, 1, 200000,
631  enc_codec_format, pix_fmt, 0, xcoderGUID, NULL,
632  0, (sw_pix_fmt != NI_SW_PIX_FMT_NONE) ? false : true);
633  // zero copy is not supported for YUV444P
634  if (ret != 0)
635  {
636  goto end;
637  }
638 
639  do
640  {
641  receive_rc = encoder_receive(&ctx, enc_ctx, &in_frame, out_packet,
642  video_width[0], video_height[0], output_total, output_fp);
643  }
644  while (receive_rc == NI_TEST_RETCODE_EAGAIN);
645 
646  if (receive_rc == NI_TEST_RETCODE_SUCCESS)
647  {
648  ni_log(NI_LOG_INFO, "Got encoded sequence header packet\n");
649  }
650  else
651  {
652  ni_log(NI_LOG_ERROR, "Failed to get encoded sequence header packet, retcode %d\n", receive_rc);
653  ret = receive_rc;
654  goto end;
655  }
656 
657  ni_log(NI_LOG_INFO, "Starting to encode: video resolution %dx%d\n", video_width[0], video_height[0]);
658 
659  while (!end_of_all_streams &&
660  (send_rc == NI_TEST_RETCODE_SUCCESS || receive_rc == NI_TEST_RETCODE_SUCCESS ||
661  (send_rc == NI_TEST_RETCODE_EAGAIN && receive_rc == NI_TEST_RETCODE_EAGAIN)))
662  {
663  read_size = read_yuv_from_file(&ctx, input_fp[i_index], yuv_buf,
664  video_width[i_index], video_height[i_index],
665  pix_fmt, sw_pix_fmt, &eos,
666  enc_ctx[0].session_run_state);
667  if (read_size < 0)
668  {
669  break;
670  }
671 
672  // YUV444P reading
673  if (sw_pix_fmt != NI_SW_PIX_FMT_NONE)
674  {
675  ret = convert_yuv_444p_to_420p(&sw_pix_frame[0], eos ? NULL : yuv_buf,
676  video_width[i_index], video_height[i_index],
677  sw_pix_fmt, 0, enc_codec_format);
678  if (ret < 0)
679  {
680  break;
681  }
682  }
683 
684  for (i = 0; i < output_total; i++)
685  {
686  if (sw_pix_fmt != NI_SW_PIX_FMT_NONE)
687  {
688  ctx.curr_enc_index = i;
689  send_rc = encoder_send_data3(&ctx, &enc_ctx[i], &sw_pix_frame[i],
690  video_width[i_index], video_height[i_index], eos);
691  } else
692  {
693  ctx.curr_enc_index = i;
694  send_rc = encoder_send_data(&ctx, &enc_ctx[i],
695  &in_frame, eos ? NULL : yuv_buf,
696  video_width[i_index], video_height[i_index],
697  i_index == input_total - 1);
698  }
699 
700  if (send_rc == NI_TEST_RETCODE_EAGAIN)
701  {
702  // retry send to same encoder session
703  i--;
704  continue;
705  } else if (send_rc == NI_TEST_RETCODE_NEXT_INPUT) // next input (will trigger sequence change)
706  {
707  i_index++;
708  ctx.total_file_size = get_total_file_size(input_fp[i_index]);
709  ctx.curr_file_offset = 0;
710  send_rc = NI_TEST_RETCODE_SUCCESS;
711  }
712  }
713 
714  receive_rc = encoder_receive(&ctx, enc_ctx, &in_frame, out_packet,
715  video_width[0], video_height[0], output_total, output_fp);
716  for (i = 0; receive_rc >= 0 && i < output_total; i++)
717  {
718  if (!ctx.enc_eos_received[i])
719  {
720  ni_log(NI_LOG_DEBUG, "enc %d continues to read!\n", i);
721  end_of_all_streams = 0;
722  break;
723  } else
724  {
725  ni_log(NI_LOG_DEBUG, "enc %d eos !\n", i);
726  end_of_all_streams = 1;
727  }
728  }
729 
731  if (current_time - previous_time >= (uint64_t)1000000000) {
732  for (i = 0; i < output_total; i++)
733  {
734  ni_log(NI_LOG_INFO, "Encoder %d stats: received %u packets, fps %.2f, total bytes %u\n",
735  i, ctx.num_packets_received[i],
736  (float)enc_ctx[i].frame_num / (float)(current_time - ctx.start_time) * (float)1000000000,
739  }
740  }
741  }
742  }
743 
744  encoder_stat_report_and_close(&ctx, enc_ctx, output_total);
745 
746 end:
747  ni_frame_buffer_free(&in_frame.data.frame);
748  ni_frame_buffer_free(&swin_frame.data.frame);
749  for (i = 0; i < output_total; i++)
750  {
751  ni_packet_buffer_free(&out_packet[i].data.packet);
752  }
753  for (i = 0; i < sizeof(sw_pix_frame)/sizeof(ni_session_data_io_t); i++)
754  {
755  ni_frame_buffer_free(&sw_pix_frame[i].data.frame);
756  }
757 
760  for (i = 0; i < output_total; i++)
761  {
762  ni_device_session_context_clear(&enc_ctx[i]);
763  if (output_fp[i] != NULL)
764  {
765  fclose(output_fp[i]);
766  }
767  }
768 
769  for (i = 0; i < input_total; i++)
770  {
771  if (input_fp[i])
772  {
773  fclose(input_fp[i]);
774  }
775  }
776 
777  ni_aligned_free(yuv_buf);
778  free(p_enc_api_param);
779 
780  for(i = 0; i < MAX_OUTPUT_FILES; ++i)
781  {
782  free(ctx.enc_pts_queue[i]);
783  ctx.enc_pts_queue[i] = NULL;
784  }
785 
786  return ret;
787 }
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:893
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:128
ni_pix_fmt_t
ni_pix_fmt_t
Definition: ni_device_api.h:261
get_total_file_size
uint64_t get_total_file_size(FILE *fp)
Definition: ni_generic_utils.c:249
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:3562
ni_hw_frame_ref
void ni_hw_frame_ref(const niFrameSurface1_t *p_surface)
Definition: ni_generic_utils.c:657
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:2287
ni_generic_utils.h
print_version
void print_version(void)
Definition: ni_generic_utils.c:66
_ni_demo_context::total_file_size
uint64_t total_file_size
Definition: ni_generic_utils.h:127
NI_PIX_FMT_YUV420P
@ NI_PIX_FMT_YUV420P
Definition: ni_device_api.h:263
_ni_demo_context::enc_pts_queue
ni_pts_queue * enc_pts_queue[MAX_OUTPUT_FILES]
Definition: ni_generic_utils.h:162
_ni_session_data_io::packet
ni_packet_t packet
Definition: ni_device_api.h:2901
NI_DEVICE_TYPE_UPLOAD
@ NI_DEVICE_TYPE_UPLOAD
Definition: ni_defs.h:365
_ni_session_context::status
int status
Definition: ni_device_api.h:1526
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:98
is_ni_enc_pix_fmt
int is_ni_enc_pix_fmt(ni_pix_fmt_t pix_fmt)
Definition: ni_generic_utils.c:77
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:3844
no_argument
#define no_argument
Definition: ni_getopt.h:85
NI_PIX_FMT_NONE
@ NI_PIX_FMT_NONE
Definition: ni_device_api.h:278
_ni_demo_context::curr_file_offset
uint64_t curr_file_offset
Definition: ni_generic_utils.h:126
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:81
ni_log.h
Logging definitions.
_ni_demo_context
Definition: ni_generic_utils.h:120
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_pixel_format_name
const char * ni_pixel_format_name(ni_pix_fmt_t pix_fmt)
Definition: ni_generic_utils.c:100
_ni_demo_context::enc_resend
int enc_resend[MAX_OUTPUT_FILES]
Definition: ni_generic_utils.h:156
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:2215
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:917
_ni_session_data_io
Definition: ni_device_api.h:2896
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:85
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:936
_ni_session_context::frame_num
uint64_t frame_num
Definition: ni_device_api.h:1533
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:447
optarg
char * optarg
Definition: ni_getopt.c:33
NI_DEVICE_TYPE_SCALER
@ NI_DEVICE_TYPE_SCALER
Definition: ni_defs.h:360
_ni_session_context
Definition: ni_device_api.h:1410
_niFrameSurface1
Definition: ni_device_api.h:2823
_ni_session_data_io::data
union _ni_session_data_io::@19 data
encoder_open
int encoder_open(ni_demo_context_t *p_ctx, 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:2017
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:143
_ni_xcoder_params
Definition: ni_device_api.h:2743
option
Definition: ni_getopt.h:73
NI_SW_PIX_FMT_YUV444P
@ NI_SW_PIX_FMT_YUV444P
Definition: ni_generic_utils.h:82
ni_sw_pix_fmt_t
ni_sw_pix_fmt_t
Definition: ni_generic_utils.h:79
_ni_session_context::codec_format
uint32_t codec_format
Definition: ni_device_api.h:1488
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:412
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:2900
atoi
#define atoi(p_str)
Definition: ni_device_api.c:7263
_ni_demo_context::num_packets_received
uint64_t num_packets_received[MAX_OUTPUT_FILES]
Definition: ni_generic_utils.h:141
_ni_demo_context::read_framerate
int read_framerate
Definition: ni_generic_utils.h:131
_ni_demo_context::enc_eos_received
int enc_eos_received[MAX_OUTPUT_FILES]
Definition: ni_generic_utils.h:159
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:2698
_ni_demo_context::av1_output_obu
uint8_t av1_output_obu
Definition: ni_generic_utils.h:149
ni_util.h
Utility definitions.
NI_RETCODE_NVME_SC_WRITE_BUFFER_FULL
@ NI_RETCODE_NVME_SC_WRITE_BUFFER_FULL
Definition: ni_defs.h:546
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:913
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:138
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:134
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:1188
NI_CODEC_FORMAT_H265
@ NI_CODEC_FORMAT_H265
Definition: ni_device_api.h:914