libxcoder  5.5.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 or name.\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, j|jpeg, 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  char jpeg_filename[MAX_OUTPUT_FILES][FILE_NAME_LEN*2] = {0};
93  FILE* input_fp[MAX_INPUT_FILES] = {0};
94  FILE* output_fp[MAX_OUTPUT_FILES] = {0};
95  uint64_t prev_num_pkt[MAX_OUTPUT_FILES] = {0};
96  int i_index = 0, s_index = 0, o_index = 0, e_index = 0, g_index = 0;
97  int input_total = 0, output_total = 0;
98  int enc_codec_format = -1;
99  ni_log_level_t log_level;
100  int xcoderGUID = 0;
101  char *n;
103  ni_sw_pix_fmt_t sw_pix_fmt = NI_SW_PIX_FMT_NONE;
104  int video_width[MAX_INPUT_FILES] = {0};
105  int video_height[MAX_INPUT_FILES] = {0};
106  char enc_conf_params[MAX_OUTPUT_FILES][2048] = {0};
107  char enc_gop_params[MAX_OUTPUT_FILES][2048] = {0};
108  ni_xcoder_params_t *p_enc_api_param = NULL;
109  int hwupload = 0;
110  int first_frame_uploaded = 0;
111  void *yuv_buf = NULL;
112  int send_rc = NI_TEST_RETCODE_SUCCESS, receive_rc = NI_TEST_RETCODE_SUCCESS;
113  ni_session_context_t enc_ctx[MAX_OUTPUT_FILES] = {0};
114  ni_session_context_t upl_ctx = {0};
115  ni_session_context_t sca_ctx = {0};
116  ni_session_data_io_t in_frame = {0};
117  ni_session_data_io_t out_packet[MAX_OUTPUT_FILES] = {0};
118  ni_session_data_io_t sw_pix_frame[2] = {0};
119  ni_session_data_io_t scale_frame = {0};
120  ni_session_data_io_t swin_frame = {0};
121  ni_session_data_io_t *p_in_frame;
122  uint64_t current_time, previous_time;
123  int end_of_all_streams = 0, read_size = 0, eos = 0;
124  niFrameSurface1_t *p_hwframe = NULL;
125 
126  int opt;
127  int opt_index;
128  const char *opt_string = "hvi:o:m:l:c:r:k:p:s:e:g:u";
129  static struct option long_options[] = {
130  {"help", no_argument, NULL, 'h'},
131  {"version", no_argument, NULL, 'v'},
132  {"input", required_argument, NULL, 'i'},
133  {"output", required_argument, NULL, 'o'},
134  {"enc-codec", required_argument, NULL, 'm'},
135  {"loglevel", required_argument, NULL, 'l'},
136  {"card", required_argument, NULL, 'c'},
137  {"repeat", required_argument, NULL, 'r'},
138  {"readframerate", required_argument, NULL, 'k'},
139  {"pix_fmt", required_argument, NULL, 'p'},
140  {"size", required_argument, NULL, 's'},
141  {"encoder-params", required_argument, NULL, 'e'},
142  {"encoder-gop", required_argument, NULL, 'g'},
143  {"hwupload", no_argument, NULL, 'u'},
144  {NULL, 0, NULL, 0},
145  };
146 
147  while ((opt = getopt_long(argc, argv, opt_string, long_options, &opt_index)) != -1)
148  {
149  switch (opt)
150  {
151  case 'h':
152  print_usage();
153  ret = 0;
154  goto end;
155  case 'v':
156  print_version();
157  ret = 0;
158  goto end;
159  case 'i':
160  if (i_index == MAX_INPUT_FILES)
161  {
162  ni_log(NI_LOG_ERROR, "Error: number of input files cannot exceed %d\n", MAX_INPUT_FILES);
163  ret = -1;
164  goto end;
165  }
166  ni_strcpy(in_filename[i_index], FILE_NAME_LEN, optarg);
167  i_index++;
168  break;
169  case 'o':
170  if (o_index == MAX_OUTPUT_FILES)
171  {
172  ni_log(NI_LOG_ERROR, "Error: number of output files cannot exceed %d\n", MAX_OUTPUT_FILES);
173  ret = -1;
174  goto end;
175  }
176 
177  for (i = 0; i < o_index; i++)
178  {
179  if (0 == strcmp(out_filename[i], optarg))
180  {
181  ni_log(NI_LOG_ERROR, "Error: output file names must be unique: %s\n", optarg);
182  ret = -1;
183  goto end;
184  }
185  }
186 
187  ni_strcpy(out_filename[o_index], FILE_NAME_LEN, optarg);
188  o_index++;
189  break;
190  case 'm':
191  // Accept both upper and lower case
192  for (i = 0; i < strlen(optarg); i++)
193  {
194  optarg[i] = (char)tolower((unsigned char)optarg[i]);
195  }
196  if (strcmp(optarg, "a") == 0 || strcmp(optarg, "avc") == 0)
197  {
198  enc_codec_format = NI_CODEC_FORMAT_H264;
199  }
200  else if (strcmp(optarg, "h") == 0 || strcmp(optarg, "hevc") == 0)
201  {
202  enc_codec_format = NI_CODEC_FORMAT_H265;
203  }
204  else if (strcmp(optarg, "j") == 0 || strcmp(optarg, "jpeg") == 0)
205  {
206  enc_codec_format = NI_CODEC_FORMAT_JPEG;
207  }
208  else if (strcmp(optarg, "x") == 0 || strcmp(optarg, "av1") == 0)
209  {
210  enc_codec_format = NI_CODEC_FORMAT_AV1;
211  }
212  else if (strcmp(optarg, "o") == 0 || strcmp(optarg, "obu") == 0)
213  {
214  enc_codec_format = NI_CODEC_FORMAT_AV1;
215  ctx.av1_output_obu = 1;
216  }
217  else
218  {
219  ni_log(NI_LOG_ERROR, "Error: Invalid value \"%s\" for -m | --dec-codec option\n"
220  "Must be one of [a|avc, h|hevc, x|av1, o|obu]\n", optarg);
221  ret = -1;
222  goto end;
223  }
224  break;
225  case 'l':
226  log_level = arg_to_ni_log_level(optarg);
227  if (log_level != NI_LOG_INVALID)
228  {
229  ni_log_set_level(log_level);
230  }
231  else
232  {
233  ni_log(NI_LOG_ERROR, "Error: Invalid value \"%s\" for -l | --loglevel option\n"
234  "Must be one of [none, fatal, error, info, debug, trace]\n", optarg);
235  ret = -1;
236  goto end;
237  }
238  break;
239  case 'c':
240  xcoderGUID = (int)strtol(optarg, &n, 10);
241  if (n == optarg || *n != '\0' || xcoderGUID < 0)
242  {
243  ni_log(NI_LOG_ERROR, "Error: Invalid value \"%s\" for -c | --card option\n"
244  "Must be a non-negative integer\n", optarg);
245  ret = -1;
246  goto end;
247  }
248  break;
249  case 'r':
250  ctx.loops_left = strtol(optarg, &n, 10);
251  if (n == optarg || *n != '\0' || !(ctx.loops_left >= 1))
252  {
253  ni_log(NI_LOG_ERROR, "Error: Invalid value \"%s\" for -r | --repeat option\n"
254  "Must be a positive integer\n", optarg);
255  ret = -1;
256  goto end;
257  }
258  break;
259  case 'k':
260  ctx.read_framerate = (int)strtol(optarg, &n, 10);
261  if (n == optarg || *n != '\0' || ctx.read_framerate < 0)
262  {
263  ni_log(NI_LOG_ERROR, "Error: Invalid value \"%s\" for -k | --readframerate option\n"
264  "Must be a non-negative integer\n", optarg);
265  ret = -1;
266  goto end;
267  }
268  break;
269  case 'p':
270  pix_fmt = ni_pixel_format_search(optarg);
271  if (pix_fmt == NI_PIX_FMT_NONE)
272  {
273  if (!strcmp(optarg, "yuv444p"))
274  {
275  sw_pix_fmt = NI_SW_PIX_FMT_YUV444P;
276  }
277  else
278  {
279  ni_log(NI_LOG_ERROR, "Error: Invalid value \"%s\" for -p | --pix_fmt option\n"
280  "Must be one of [yuv420p, yuv420p10le, nv12, p010le, rgba, gbra, argb, abgr, bgr0, yuv444p]\n",
281  optarg);
282  ret = -1;
283  goto end;
284  }
285  }
286  break;
287  case 's':
288  if (s_index == MAX_INPUT_FILES)
289  {
290  ni_log(NI_LOG_ERROR, "Error: number of input resolutions cannot exceed %d\n", MAX_INPUT_FILES);
291  ret = -1;
292  goto end;
293  }
294  video_width[s_index] = (int)strtol(optarg, &n, 10);
295  video_height[s_index] = atoi(n + 1);
296  if ((*n != 'x') || (video_width[s_index] <= 0 || video_height[s_index] <= 0))
297  {
298  ni_log(NI_LOG_ERROR, "Error: Invalid value \"%s\" for -s | --size option\n"
299  "Must be in format [WIDTHxHEIGHT] (e.g. 1920x1080)\n", optarg);
300  ret = -1;
301  goto end;
302  }
303  s_index++;
304  break;
305  case 'e':
306  if (e_index == MAX_OUTPUT_FILES)
307  {
308  ni_log(NI_LOG_ERROR, "Error: number of encoder config cannot exceed %d\n", MAX_OUTPUT_FILES);
309  ret = -1;
310  goto end;
311  }
312  ni_strcpy(enc_conf_params[e_index], sizeof(enc_conf_params[e_index]), optarg);
313  e_index++;
314  break;
315  case 'g':
316  if (g_index == MAX_OUTPUT_FILES)
317  {
318  ni_log(NI_LOG_ERROR, "Error: number of encoder gop settings cannot exceed %d\n", MAX_OUTPUT_FILES);
319  ret = -1;
320  goto end;
321  }
322  ni_strcpy(enc_gop_params[g_index], sizeof(enc_gop_params[g_index]), optarg);
323  g_index++;
324  break;
325  case 'u':
326  hwupload = 1;
327  break;
328  default:
329  print_usage();
330  ret = -1;
331  goto end;
332  }
333  }
334 
335  if (i_index == 0) {
336  ni_log(NI_LOG_ERROR, "Error: Missing input file argument (-i | --input)\n");
337  ret = -1;
338  goto end;
339  }
340 
341  if (o_index == 0) {
342  ni_log(NI_LOG_ERROR, "Error: Missing output filepath (or filename) argument (-o | --output)\n");
343  ret = -1;
344  goto end;
345  }
346 
347  if (s_index != i_index) {
348  ni_log(NI_LOG_ERROR, "Error: Number of input resolution specified does not match number of input files\n");
349  ret = -1;
350  goto end;
351  }
352 
353  if (enc_codec_format == -1) {
354  ni_log(NI_LOG_ERROR, "Error: Missing encoder codec argument (-m | --enc-codec)\n");
355  ret = -1;
356  goto end;
357  }
358 
359  input_total = i_index;
360  i_index = 0;
361  if (ctx.loops_left > 1 && input_total > 1)
362  {
363  ni_log(NI_LOG_ERROR, "Error: multiple input files not supported when loops %u greater than 1\n", ctx.loops_left);
364  ret = -1;
365  goto end;
366  }
367 
368  output_total = o_index;
369  if (sw_pix_fmt == NI_SW_PIX_FMT_YUV444P && output_total != 2)
370  {
371  ni_log(NI_LOG_ERROR, "Error: Must indicate 2 output files for yuv444p encoding\n");
372  ret = -1;
373  goto end;
374  }
375 
376  // Check for features not supported with hwupload
377  if (hwupload && ctx.read_framerate)
378  {
379  ni_log(NI_LOG_ERROR, "Error: -k | --readframerate option is not supported in hwupload mode\n");
380  ret = -1;
381  goto end;
382  }
383  if (hwupload && input_total > 1)
384  {
385  ni_log(NI_LOG_ERROR, "Error: multiple input (sequence change) is not supported in hwupload mode\n");
386  ret = -1;
387  goto end;
388  }
389  if (hwupload && sw_pix_fmt == NI_SW_PIX_FMT_YUV444P)
390  {
391  ni_log(NI_LOG_ERROR, "Error: yuv444p input is not supported in hwupload mode\n");
392  ret = -1;
393  goto end;
394  }
395 
396  // Only in hwupload mode, the pixel formats not directly supported by encoder
397  // will be converted to yuv420p using 2D engine
398  if (!hwupload && !is_ni_enc_pix_fmt(pix_fmt) && sw_pix_fmt == NI_SW_PIX_FMT_NONE)
399  {
400  ni_log(NI_LOG_ERROR, "Error: pixel format %s is only supported in hwupload mode\n",
401  ni_pixel_format_name(pix_fmt));
402  ret = -1;
403  goto end;
404  }
405 
406  if (ni_posix_memalign(&yuv_buf, sysconf(_SC_PAGESIZE), MAX_YUV_FRAME_SIZE))
407  {
408  ni_log(NI_LOG_ERROR, "Error: failed to allocate YUV data buffer\n");
409  ret = -1;
410  goto end;
411  }
412 
413  for (i = 0; i < input_total; i++)
414  {
415  if (!in_filename[i][0])
416  {
417  ni_log(NI_LOG_ERROR, "Error: invalid input file %d\n", i);
418  ret = -1;
419  goto end;
420  }
421 
422  input_fp[i] = NULL;
423  ni_fopen(&(input_fp[i]), in_filename[i], "rb");
424 
425  if (!input_fp[i])
426  {
427  ni_log(NI_LOG_ERROR, "Error: Failed to open input %s\n", in_filename[i]);
428  ret = -1;
429  goto end;
430  }
431  ni_log(NI_LOG_INFO, "Opened input file: %s\n", in_filename[i]);
432  }
433 
434  ctx.total_file_size = get_total_file_size(input_fp[0]);
435  ctx.curr_file_offset = 0;
436 
437  for (i = 0; i < output_total; i++)
438  {
439  if (strcmp(out_filename[i], "null") != 0 &&
440  strcmp(out_filename[i], "/dev/null") != 0)
441  {
442  output_fp[i] = NULL;
443  if (enc_codec_format == NI_CODEC_FORMAT_JPEG)
444  {
445  snprintf(jpeg_filename[i], sizeof(jpeg_filename[i]), "%s/%" PRIu64 ".png",
446  out_filename[i], ctx.num_packets_received[i]);
447  ni_fopen(&(output_fp[i]), jpeg_filename[i], "wb");
448  } else
449  {
450  ni_fopen(&(output_fp[i]), out_filename[i], "wb");
451  }
452  if (!output_fp[i])
453  {
454  ni_log(NI_LOG_ERROR, "Error: Failed to open %s\n", enc_codec_format == NI_CODEC_FORMAT_JPEG ? jpeg_filename[i] : out_filename[i]);
455  ret = -1;
456  goto end;
457  }
458  if (enc_codec_format != NI_CODEC_FORMAT_JPEG)
459  {
460  ni_log(NI_LOG_INFO, "Opened output file: %s\n", out_filename[i]);
461  }
462  } else
463  {
464  output_fp[i] = NULL;
465  ni_log(NI_LOG_INFO, "Note: Requested NULL output for index %d, no output file will be generated\n", i);
466  }
467  }
468 
469  p_enc_api_param = calloc(output_total, sizeof(ni_xcoder_params_t));
470  if (!p_enc_api_param)
471  {
472  ni_log(NI_LOG_ERROR, "Error: Failed to allocate memory for p_enc_api_param\n");
473  ret = -1;
474  goto end;
475  }
476 
477  for (i = 0; i < output_total; i++)
478  {
479  if (ni_device_session_context_init(&enc_ctx[i]) < 0)
480  {
481  ni_log(NI_LOG_ERROR, "Error: init encoder %d context error\n", i);
482  ret = -1;
483  goto end;
484  }
485  }
486 
487  for (i = 0; i < output_total; i++)
488  {
489  enc_ctx[i].codec_format = enc_codec_format;
490  }
491 
492  ctx.start_time = ni_gettime_ns();
494 
495  if (hwupload)
496  {
497  if (ni_device_session_context_init(&upl_ctx) < 0)
498  {
499  ni_log(NI_LOG_ERROR, "Error: init uploader context error\n");
500  ret = -1;
501  goto end;
502  }
503 
504  if (ni_device_session_context_init(&sca_ctx) < 0)
505  {
506  ni_log(NI_LOG_ERROR, "Error: init scale context error\n");
507  ret = -1;
508  goto end;
509  }
510 
511  ni_log(NI_LOG_INFO, "Starting hwupload + encoding mode: video resolution %dx%d\n",
512  video_width[0], video_height[0]);
513  // buffers by downstream entity like encoders
514  ret = uploader_open_session(&upl_ctx, xcoderGUID, video_width[0] < NI_MIN_WIDTH ? NI_MIN_WIDTH : video_width[0],
515  video_height[0] < NI_MIN_HEIGHT ? NI_MIN_HEIGHT : video_height[0], pix_fmt, 0, 3);
516  if (ret != 0)
517  {
518  goto end;
519  }
520 
521  p_hwframe = hwupload_frame(&ctx, &upl_ctx, &sca_ctx, &swin_frame, &in_frame, &scale_frame, pix_fmt,
522  video_width[0], video_height[0], input_fp[0], yuv_buf, &eos);
523  if (p_hwframe == NULL)
524  {
525  ret = -1;
526  goto end;
527  }
528 
529  ret = encoder_open(&ctx, &enc_ctx[0], p_enc_api_param, output_total, enc_conf_params, enc_gop_params,
530  NULL, video_width[0], video_height[0], 30, 1, 200000, enc_codec_format,
531  is_ni_enc_pix_fmt(pix_fmt) ? pix_fmt : NI_PIX_FMT_YUV420P,
532  0, xcoderGUID, p_hwframe, 0, false);
533  if (ret != 0)
534  {
535  goto end;
536  }
537 
538  //unlike video codecs (1st packet is header), there is no header for Jpeg
539  if (enc_codec_format != NI_CODEC_FORMAT_JPEG)
540  {
541  do
542  {
543  receive_rc = encoder_receive(&ctx, enc_ctx, &in_frame, out_packet,
544  video_width[0], video_height[0], output_total, output_fp);
545  }
546  while (receive_rc == NI_TEST_RETCODE_EAGAIN);
547 
548  if (receive_rc == NI_TEST_RETCODE_SUCCESS)
549  {
550  ni_log(NI_LOG_INFO, "Got encoded sequence header packet\n");
551  }
552  else
553  {
554  ni_log(NI_LOG_ERROR, "Failed to get encoded sequence header packet, retcode %d\n", receive_rc);
555  ret = receive_rc;
556  goto end;
557  }
558  }
559  while (!end_of_all_streams &&
560  (send_rc == NI_TEST_RETCODE_SUCCESS || receive_rc== NI_TEST_RETCODE_SUCCESS ||
561  (send_rc == NI_TEST_RETCODE_EAGAIN && receive_rc == NI_TEST_RETCODE_EAGAIN)))
562  {
563  if (first_frame_uploaded && !eos)
564  {
565  p_hwframe = hwupload_frame(&ctx, &upl_ctx, &sca_ctx, &swin_frame, &in_frame, &scale_frame, pix_fmt,
566  video_width[0], video_height[0], input_fp[0], yuv_buf, &eos);
568  {
569  ni_log(NI_LOG_DEBUG, "No space to write to, try to read a packet\n");
570  p_in_frame = &in_frame;
571  goto receive_pkt;
572  } else if (p_hwframe == NULL)
573  {
575  break;
576  }
577  }
578 
579  // Sending
580  p_in_frame = is_ni_enc_pix_fmt(pix_fmt) ? &in_frame : &scale_frame;
581  for (i = 0; i < output_total; i++)
582  {
583  ctx.curr_enc_index = i;
584  send_rc = encoder_send_data3(&ctx, &enc_ctx[i], p_in_frame, video_width[0], video_height[0], eos);
585  first_frame_uploaded = 1; //since first frame read before while-loop
586  if (send_rc < 0) //Error
587  {
588  ni_log(NI_LOG_ERROR, "enc %d send error, quit !\n", i);
589  ni_hw_frame_ref(p_hwframe);
590  end_of_all_streams = 1;
591  break;
592  }
593  //track in array with unique index, free when enc read finds
594  //this must be implemented in application space for complete
595  //tracking of hwframes
596  if (!ctx.enc_resend[i])
597  {
598  //successful read means there is recycle to check
599  ni_hw_frame_ref(p_hwframe);
600  } else
601  {
602  ni_log(NI_LOG_DEBUG, "enc %d need to re-send !\n", i);
603  ni_usleep(500);
604  i--;
605  continue;
606  }
607  }
608  if (end_of_all_streams)
609  break;
610 
611 receive_pkt:
612  for (i = 0; i < output_total; i++)
613  {
614  prev_num_pkt[i] = ctx.num_packets_received[i];
615  }
616 
617  receive_rc = encoder_receive(&ctx, enc_ctx, p_in_frame, out_packet,
618  video_width[0], video_height[0], output_total, output_fp);
619  for (i = 0; receive_rc >= 0 && i < output_total; i++)
620  {
621  if (!ctx.enc_eos_received[i])
622  {
623  if (enc_ctx[i].codec_format == NI_CODEC_FORMAT_JPEG &&
624  prev_num_pkt[i] < ctx.num_packets_received[i] &&
625  output_fp[i] != NULL)
626  {
627  fclose(output_fp[i]);
628  output_fp[i] = NULL;
629  ni_log(NI_LOG_DEBUG, "Save jpeg file : %s\n", jpeg_filename[i]);
630  snprintf(jpeg_filename[i], sizeof(jpeg_filename[i]), "%s/%" PRIu64 ".png",
631  out_filename[i], ctx.num_packets_received[i]);
632  ni_fopen(&(output_fp[i]), jpeg_filename[i], "wb");
633  if (!output_fp[i])
634  {
635  ni_log(NI_LOG_ERROR, "Error: Failed to open %s\n", jpeg_filename[i]);
636  ret = -1;
637  break;
638  }
639  }
640 
641  ni_log(NI_LOG_DEBUG, "enc %d continues to read!\n", i);
642  end_of_all_streams = 0;
643  break;
644  } else
645  {
646  ni_log(NI_LOG_DEBUG, "enc %d eos !\n", i);
647  end_of_all_streams = 1;
648  }
649  }
650 
652  if (current_time - previous_time >= (uint64_t)1000000000) {
653  for (i = 0; i < output_total; i++)
654  {
655  ni_log(NI_LOG_INFO, "Encoder %d stats: received %u packets, fps %.2f, total bytes %u\n",
656  i, ctx.num_packets_received[i],
657  (float)enc_ctx[i].frame_num / (float)(current_time - ctx.start_time) * (float)1000000000,
659  }
661  }
662  }
663 
665  if (!is_ni_enc_pix_fmt(pix_fmt))
666  { //Uploading rgba requires scaler conversion so close the session too
668  }
669  }
670  else
671  {
672  in_frame.data.frame.pixel_format = pix_fmt;
673  ret = encoder_open(&ctx, enc_ctx, p_enc_api_param, output_total,
674  enc_conf_params, enc_gop_params, NULL, video_width[0],
675  video_height[0], 30, 1, 200000,
676  enc_codec_format, pix_fmt, 0, xcoderGUID, NULL,
677  0, (sw_pix_fmt != NI_SW_PIX_FMT_NONE) ? false : true);
678  // zero copy is not supported for YUV444P
679  if (ret != 0)
680  {
681  goto end;
682  }
683 
684  //unlike video codecs (1st packet is header), there is no header for Jpeg
685  if (enc_codec_format != NI_CODEC_FORMAT_JPEG)
686  {
687  do
688  {
689  receive_rc = encoder_receive(&ctx, enc_ctx, &in_frame, out_packet,
690  video_width[0], video_height[0], output_total, output_fp);
691  }
692  while (receive_rc == NI_TEST_RETCODE_EAGAIN);
693 
694  if (receive_rc == NI_TEST_RETCODE_SUCCESS)
695  {
696  ni_log(NI_LOG_INFO, "Got encoded sequence header packet\n");
697  }
698  else
699  {
700  ni_log(NI_LOG_ERROR, "Failed to get encoded sequence header packet, retcode %d\n", receive_rc);
701  ret = receive_rc;
702  goto end;
703  }
704  }
705 
706  ni_log(NI_LOG_INFO, "Starting to encode: video resolution %dx%d\n", video_width[0], video_height[0]);
707 
708  while (!end_of_all_streams &&
709  (send_rc == NI_TEST_RETCODE_SUCCESS || receive_rc == NI_TEST_RETCODE_SUCCESS ||
710  (send_rc == NI_TEST_RETCODE_EAGAIN && receive_rc == NI_TEST_RETCODE_EAGAIN)))
711  {
712  read_size = read_yuv_from_file(&ctx, input_fp[i_index], yuv_buf,
713  video_width[i_index], video_height[i_index],
714  pix_fmt, sw_pix_fmt, &eos,
715  enc_ctx[0].session_run_state);
716  if (read_size < 0)
717  {
718  break;
719  }
720 
721  // YUV444P reading
722  if (sw_pix_fmt != NI_SW_PIX_FMT_NONE)
723  {
724  ret = convert_yuv_444p_to_420p(&sw_pix_frame[0], eos ? NULL : yuv_buf,
725  video_width[i_index], video_height[i_index],
726  sw_pix_fmt, 0, enc_codec_format);
727  if (ret < 0)
728  {
729  break;
730  }
731  }
732 
733  for (i = 0; i < output_total; i++)
734  {
735  if (sw_pix_fmt != NI_SW_PIX_FMT_NONE)
736  {
737  ctx.curr_enc_index = i;
738  send_rc = encoder_send_data3(&ctx, &enc_ctx[i], &sw_pix_frame[i],
739  video_width[i_index], video_height[i_index], eos);
740  } else
741  {
742  ctx.curr_enc_index = i;
743  send_rc = encoder_send_data(&ctx, &enc_ctx[i],
744  &in_frame, eos ? NULL : yuv_buf,
745  video_width[i_index], video_height[i_index],
746  i_index == input_total - 1);
747  }
748 
749  if (send_rc == NI_TEST_RETCODE_EAGAIN)
750  {
751  // retry send to same encoder session
752  i--;
753  continue;
754  } else if (send_rc == NI_TEST_RETCODE_NEXT_INPUT) // next input (will trigger sequence change)
755  {
756  i_index++;
757  ctx.total_file_size = get_total_file_size(input_fp[i_index]);
758  ctx.curr_file_offset = 0;
759  send_rc = NI_TEST_RETCODE_SUCCESS;
760  }
761  }
762 
763  for (i = 0; i < output_total; i++)
764  {
765  prev_num_pkt[i] = ctx.num_packets_received[i];
766  }
767 
768  receive_rc = encoder_receive(&ctx, enc_ctx, &in_frame, out_packet,
769  video_width[0], video_height[0], output_total, output_fp);
770  for (i = 0; receive_rc >= 0 && i < output_total; i++)
771  {
772  if (!ctx.enc_eos_received[i])
773  {
774  if (enc_ctx[i].codec_format == NI_CODEC_FORMAT_JPEG &&
775  prev_num_pkt[i] < ctx.num_packets_received[i] &&
776  output_fp[i] != NULL)
777  {
778  fclose(output_fp[i]);
779  output_fp[i] = NULL;
780  ni_log(NI_LOG_DEBUG, "Save jpeg file : %s\n", jpeg_filename[i]);
781  snprintf(jpeg_filename[i], sizeof(jpeg_filename[i]), "%s/%" PRIu64 ".png",
782  out_filename[i], ctx.num_packets_received[i]);
783  ni_fopen(&(output_fp[i]), jpeg_filename[i], "wb");
784  if (!output_fp[i])
785  {
786  ni_log(NI_LOG_ERROR, "Error: Failed to open %s\n", jpeg_filename[i]);
787  ret = -1;
788  break;
789  }
790  }
791 
792  ni_log(NI_LOG_DEBUG, "enc %d continues to read!\n", i);
793  end_of_all_streams = 0;
794  break;
795  } else
796  {
797  ni_log(NI_LOG_DEBUG, "enc %d eos !\n", i);
798  end_of_all_streams = 1;
799  }
800  }
801 
803  if (current_time - previous_time >= (uint64_t)1000000000) {
804  for (i = 0; i < output_total; i++)
805  {
806  ni_log(NI_LOG_INFO, "Encoder %d stats: received %u packets, fps %.2f, total bytes %u\n",
807  i, ctx.num_packets_received[i],
808  (float)enc_ctx[i].frame_num / (float)(current_time - ctx.start_time) * (float)1000000000,
811  }
812  }
813  }
814  }
815 
816  //delete jpeg file that are 0 bytes in size
817  for (i = 0; i < output_total; i++)
818  {
819  if (enc_ctx[i].codec_format == NI_CODEC_FORMAT_JPEG &&
820  output_fp[i] != NULL)
821  {
822  fseek(output_fp[i], 0, SEEK_END);
823  if (ftell(output_fp[i]) == 0)
824  {
825  fclose(output_fp[i]);
826  output_fp[i] = NULL;
827  remove(jpeg_filename[i]);
828  }
829  }
830  }
831 
832  encoder_stat_report_and_close(&ctx, enc_ctx, output_total);
833 
834 end:
835  ni_frame_buffer_free(&in_frame.data.frame);
836  ni_frame_buffer_free(&swin_frame.data.frame);
837  for (i = 0; i < output_total; i++)
838  {
839  ni_packet_buffer_free(&out_packet[i].data.packet);
840  }
841  for (i = 0; i < sizeof(sw_pix_frame)/sizeof(ni_session_data_io_t); i++)
842  {
843  ni_frame_buffer_free(&sw_pix_frame[i].data.frame);
844  }
845 
848  for (i = 0; i < output_total; i++)
849  {
850  ni_device_session_context_clear(&enc_ctx[i]);
851  if (output_fp[i] != NULL)
852  {
853  fclose(output_fp[i]);
854  }
855  }
856 
857  for (i = 0; i < input_total; i++)
858  {
859  if (input_fp[i])
860  {
861  fclose(input_fp[i]);
862  }
863  }
864 
865  ni_aligned_free(yuv_buf);
866  free(p_enc_api_param);
867 
868  for(i = 0; i < MAX_OUTPUT_FILES; ++i)
869  {
870  free(ctx.enc_pts_queue[i]);
871  ctx.enc_pts_queue[i] = NULL;
872  }
873 
874  return ret;
875 }
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_CODEC_FORMAT_JPEG
@ NI_CODEC_FORMAT_JPEG
Definition: ni_device_api.h:928
ni_log_level_t
ni_log_level_t
Definition: ni_log.h:57
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:264
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:3725
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:2563
ni_strcpy
ni_retcode_t ni_strcpy(char *dest, size_t dmax, const char *src)
Definition: ni_util.c:453
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:266
_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:3039
NI_DEVICE_TYPE_UPLOAD
@ NI_DEVICE_TYPE_UPLOAD
Definition: ni_defs.h:367
_ni_session_context::status
int status
Definition: ni_device_api.h:1555
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:2622
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:4007
no_argument
#define no_argument
Definition: ni_getopt.h:85
NI_PIX_FMT_NONE
@ NI_PIX_FMT_NONE
Definition: ni_device_api.h:281
_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:63
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:62
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:2418
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:929
_ni_session_data_io
Definition: ni_device_api.h:3034
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:59
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:362
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:1562
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:262
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:362
_ni_session_context
Definition: ni_device_api.h:1435
_niFrameSurface1
Definition: ni_device_api.h:2897
_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:2021
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:2814
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:1517
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:202
_ni_session_data_io::frame
ni_frame_t frame
Definition: ni_device_api.h:3038
atoi
#define atoi(p_str)
Definition: ni_device_api.c:7531
_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:129
_ni_frame::pixel_format
int pixel_format
Definition: ni_device_api.h:2769
_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:548
ni_aligned_free
#define ni_aligned_free(p_memptr)
Definition: ni_util.h:400
NI_CODEC_FORMAT_H264
@ NI_CODEC_FORMAT_H264
Definition: ni_device_api.h:925
NI_MIN_WIDTH
#define NI_MIN_WIDTH
Definition: ni_device_api.h:127
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:162
_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:64
_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:1542
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_fopen
ni_retcode_t ni_fopen(FILE **fp, const char *filename, const char *mode)
Definition: ni_util.c:983
NI_CODEC_FORMAT_H265
@ NI_CODEC_FORMAT_H265
Definition: ni_device_api.h:926