libxcoder 5.9.0
Loading...
Searching...
No Matches
ni_xcoder_multithread_transcode.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_multithread_transcode.c
24 *
25 * \brief Multi-threaded video transcoding and filtering demo application
26 * directly using Netint Libxcoder API
27 ******************************************************************************/
28
29#include "ni_generic_utils.h"
30#include "ni_decode_utils.h"
31#include "ni_encode_utils.h"
32#include "ni_filter_utils.h"
33#include "ni_log.h"
34#include "ni_util.h"
35
36#ifdef _WIN32
37#include "ni_getopt.h"
38#elif __linux__ || __APPLE__
39#include <getopt.h>
40#include <unistd.h>
41#endif
42
43static void print_usage(void)
44{
46 "Multi-threaded video transcoding demo application directly using Netint Libxcoder version %s\n"
47 "Usage: ni_xcoder_multithread_transcode [options]\n"
48 "\n"
49 "options:\n"
50 "-h | --help Show this message.\n"
51 "-v | --version Print version info.\n"
52 "-i | --input (Required) Input file path.\n"
53 "-o | --output (Required) Output file path.\n"
54 " Can be specified multiple (max %d) times\n"
55 " to run multiple encoding instances simultaneously.\n"
56 "-m | --dec-codec (Required) Decoder codec format. Must match the codec of input file.\n"
57 " [a|avc, h|hevc, v|vp9]\n"
58 "-n | --enc-codec (Required) Encoder codec format.\n"
59 " [a|avc, h|hevc, x|av1] (x is in ivf container format)\n"
60 "-l | --loglevel Set loglevel of this application and libxcoder API.\n"
61 " [none, fatal, error, info, debug, trace]\n"
62 " (Default: info)\n"
63 "-c | --card Set card index to use.\n"
64 " See `ni_rsrc_mon` for info of cards on system.\n"
65 " (Default: 0)\n"
66 "-r | --repeat To loop input X times. Must be a positive integer\n"
67 " (Default: 1)\n"
68 "-d | --decoder-params Decoding params. See \"Decoding Parameters\" chapter in\n"
69 " QuadraIntegration&ProgrammingGuide*.pdf for help.\n"
70 " (Default: \"\")\n"
71 "-e | --encoder-params Encoding params. See \"Encoding Parameters\" chapter in\n"
72 " QuadraIntegration&ProgrammingGuide*.pdf for help.\n"
73 " Can be specified multiple (max %d) times,\n"
74 " must match the number of -o specified.\n"
75 " (Default: \"\")\n"
76 "-g | --encoder-gop Custom GOP for encoding. See \"Custom Gop Structure\" chapter in\n"
77 " QuadraIntegration&ProgrammingGuide*.pdf for help.\n"
78 " gopPresetIdx must be set to 0 to be in effect.\n"
79 " (Default: \"\")\n"
80 "-u | --user-data-sei-passthru (No argument) Enable user data unregistered SEI passthrough when specified\n"
81 "-f | --vf Video filter params. The only supported filters in this demo are:\n"
82 " ni_quadra_scale - supported params [width, height, format]\n"
83 " e.g. ni_quadra_scale=width=1280:height=720:format=yuv420p\n"
84 " ni_quadra_drawbox - supported params [x, y, width, height]\n"
85 " e.g. ni_quadra_drawbox=x=300:y=150:width=600:height=400\n"
86 " (Default: \"\")\n"
88}
89
90int main(int argc, char *argv[])
91{
92 int i, ret = 0;
93 ni_demo_context_t ctx = {0};
94 char in_filename[FILE_NAME_LEN] = {0};
95 char out_filename[MAX_OUTPUT_FILES][FILE_NAME_LEN] = {0};
96 FILE *output_fp[MAX_OUTPUT_FILES] = {0};
97 int o_index = 0, e_index = 0, g_index = 0;
98 int output_total = 0;
99 int input_width = 0, input_height = 0, output_width = 0, output_height = 0, bit_depth = 8;
100 int dec_codec_format = -1, enc_codec_format = -1;
101 ni_log_level_t log_level;
102 int xcoderGUID = 0;
103 char *n;
104 char dec_conf_params[2048] = {0};
105 char filter_conf_params[2048] = {0};
106 char enc_conf_params[MAX_OUTPUT_FILES][2048] = {0};
107 char enc_gop_params[MAX_OUTPUT_FILES][2048] = {0};
108 int user_data_sei_passthru = 0;
109 ni_h264_sps_t avc_sps = {0};
110 ni_h265_sps_t hevc_sps = {0};
111 ni_vp9_header_info_t vp9_info = {0};
112 ni_xcoder_params_t *p_dec_api_param = NULL;
113 ni_xcoder_params_t *p_enc_api_param = NULL;
114 ni_session_context_t dec_ctx = {0};
116 ni_session_context_t sca_ctx = {0};
117 ni_session_context_t crop_ctx = {0};
118 ni_session_context_t pad_ctx = {0};
119 ni_session_context_t ovly_ctx = {0};
120 ni_session_context_t fmt_ctx = {0};
121 void *p_stream_info = NULL;
122 int fps_num = 30, fps_den = 1, bitrate = 200000;
123 ni_frame_t *p_ni_frame = NULL;
124 niFrameSurface1_t *p_hwframe = NULL;
125 ni_scale_params_t scale_params = {0};
126 ni_drawbox_params_t drawbox_params = {0};
127 ni_ai_pre_params_t ai_pre_params = {0}; // ai_pre not supported in this demo
128 ni_test_frame_list_t frame_list = {0};
129 ni_pthread_t dec_send_tid, dec_recv_tid, enc_send_tid, enc_recv_tid;
134 ni_pix_fmt_t enc_pix_fmt = NI_PIX_FMT_YUV420P;
135
136 int opt;
137 int opt_index;
138 const char *opt_string = "hvi:o:m:n:l:c:r:d:e:g:uf:";
139 static struct option long_options[] = {
140 {"help", no_argument, NULL, 'h'},
141 {"version", no_argument, NULL, 'v'},
142 {"input", required_argument, NULL, 'i'},
143 {"output", required_argument, NULL, 'o'},
144 {"dec-codec", required_argument, NULL, 'n'},
145 {"enc-codec", required_argument, NULL, 'm'},
146 {"loglevel", required_argument, NULL, 'l'},
147 {"card", required_argument, NULL, 'c'},
148 {"repeat", required_argument, NULL, 'r'},
149 {"decoder-params", required_argument, NULL, 'd'},
150 {"encoder-params", required_argument, NULL, 'e'},
151 {"encoder-gop", required_argument, NULL, 'g'},
152 {"user-data-sei-passthru", no_argument, NULL, 'u'},
153 {"vf", required_argument, NULL, 'f'},
154 {NULL, 0, NULL, 0},
155 };
156
157 while ((opt = getopt_long(argc, argv, opt_string, long_options, &opt_index)) != -1)
158 {
159 switch (opt)
160 {
161 case 'h':
162 print_usage();
163 ret = 0;
164 goto end;
165 case 'v':
167 ret = 0;
168 goto end;
169 case 'i':
170 ni_strcpy(in_filename, FILE_NAME_LEN, optarg);
171 break;
172 case 'o':
173 if (o_index == MAX_OUTPUT_FILES)
174 {
175 ni_log(NI_LOG_ERROR, "Error: number of output files cannot exceed %d\n", MAX_OUTPUT_FILES);
176 ret = -1;
177 goto end;
178 }
179
180 for (i = 0; i < o_index; i++)
181 {
182 if (0 == strcmp(out_filename[i], optarg))
183 {
184 ni_log(NI_LOG_ERROR, "Error: output file names must be unique: %s\n", optarg);
185 ret = -1;
186 goto end;
187 }
188 }
189
190 ni_strcpy(out_filename[o_index], FILE_NAME_LEN, optarg);
191 o_index++;
192 break;
193 case 'm':
194 // Accept both upper and lower case
195 for (i = 0; i < strlen(optarg); i++)
196 {
197 optarg[i] = (char)tolower((unsigned char)optarg[i]);
198 }
199 if (strcmp(optarg, "a") == 0 || strcmp(optarg, "avc") == 0)
200 {
201 dec_codec_format = NI_CODEC_FORMAT_H264;
202 }
203 else if (strcmp(optarg, "h") == 0 || strcmp(optarg, "hevc") == 0)
204 {
205 dec_codec_format = NI_CODEC_FORMAT_H265;
206 }
207 else if (strcmp(optarg, "v") == 0 || strcmp(optarg, "vp9") == 0)
208 {
209 dec_codec_format = NI_CODEC_FORMAT_VP9;
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, v|vp9]\n", optarg);
215 ret = -1;
216 goto end;
217 }
218 break;
219 case 'n':
220 // Accept both upper and lower case
221 for (i = 0; i < strlen(optarg); i++)
222 {
223 optarg[i] = (char)tolower((unsigned char)optarg[i]);
224 }
225 if (strcmp(optarg, "a") == 0 || strcmp(optarg, "avc") == 0)
226 {
227 enc_codec_format = NI_CODEC_FORMAT_H264;
228 }
229 else if (strcmp(optarg, "h") == 0 || strcmp(optarg, "hevc") == 0)
230 {
231 enc_codec_format = NI_CODEC_FORMAT_H265;
232 }
233 else if (strcmp(optarg, "x") == 0 || strcmp(optarg, "av1") == 0)
234 {
235 enc_codec_format = NI_CODEC_FORMAT_AV1;
236 }
237 else
238 {
239 ni_log(NI_LOG_ERROR, "Error: Invalid value \"%s\" for -n | --enc-codec option\n"
240 "Must be one of [a|avc, h|hevc, x|av1]\n", optarg);
241 ret = -1;
242 goto end;
243 }
244 break;
245 case 'l':
246 log_level = arg_to_ni_log_level(optarg);
247 if (log_level != NI_LOG_INVALID)
248 {
249 ni_log_set_level(log_level);
250 }
251 else
252 {
253 ni_log(NI_LOG_ERROR, "Error: Invalid value \"%s\" for -l | --loglevel option\n"
254 "Must be one of [none, fatal, error, info, debug, trace]\n", optarg);
255 ret = -1;
256 goto end;
257 }
258 break;
259 case 'c':
260 xcoderGUID = (int)strtol(optarg, &n, 10);
261 if (n == optarg || *n != '\0' || xcoderGUID < 0)
262 {
263 ni_log(NI_LOG_ERROR, "Error: Invalid value \"%s\" for -c | --card option\n"
264 "Must be a non-negative integer\n", optarg);
265 ret = -1;
266 goto end;
267 }
268 break;
269 case 'r':
270 ctx.loops_left = strtol(optarg, &n, 10);
271 if (n == optarg || *n != '\0' || !(ctx.loops_left >= 1))
272 {
273 ni_log(NI_LOG_ERROR, "Error: Invalid value \"%s\" for -r | --repeat option\n"
274 "Must be a positive integer\n", optarg);
275 ret = -1;
276 goto end;
277 }
278 break;
279 case 'd':
280 ni_strcpy(dec_conf_params, sizeof(dec_conf_params), optarg);
281 break;
282 case 'e':
283 if (e_index == MAX_OUTPUT_FILES)
284 {
285 ni_log(NI_LOG_ERROR, "Error: number of encoder config cannot exceed %d\n", MAX_OUTPUT_FILES);
286 ret = -1;
287 goto end;
288 }
289 ni_strcpy(enc_conf_params[e_index], sizeof(enc_conf_params[e_index]), optarg);
290 e_index++;
291 break;
292 case 'g':
293 if (g_index == MAX_OUTPUT_FILES)
294 {
295 ni_log(NI_LOG_ERROR, "Error: number of encoder gop settings cannot exceed %d\n", MAX_OUTPUT_FILES);
296 ret = -1;
297 goto end;
298 }
299 ni_strcpy(enc_gop_params[g_index], sizeof(enc_gop_params[g_index]), optarg);
300 g_index++;
301 break;
302 case 'u':
303 user_data_sei_passthru = 1;
304 break;
305 case 'f':
306 ni_strcpy(filter_conf_params, sizeof(filter_conf_params), optarg);
307 break;
308 default:
309 print_usage();
310 ret = -1;
311 goto end;
312 }
313 }
314
315 if (!in_filename[0]) {
316 ni_log(NI_LOG_ERROR, "Error: Missing input file argument (-i | --input)\n");
317 ret = -1;
318 goto end;
319 }
320
321 if (o_index == 0) {
322 ni_log(NI_LOG_ERROR, "Error: Missing output file argument (-o | --output)\n");
323 ret = -1;
324 goto end;
325 }
326
327 if (dec_codec_format == -1) {
328 ni_log(NI_LOG_ERROR, "Error: Missing decoder codec argument (-m | --dec-codec)\n");
329 ret = -1;
330 goto end;
331 }
332
333 if (enc_codec_format == -1) {
334 ni_log(NI_LOG_ERROR, "Error: Missing encoder codec argument (-n | --enc-codec)\n");
335 ret = -1;
336 goto end;
337 }
338
339 ret = read_and_cache_file(&ctx, in_filename);
340 if (ret)
341 {
342 ni_log(NI_LOG_ERROR, "Error: Read input file failure\n");
343 goto end;
344 }
345
346 output_total = o_index;
347 for (i = 0; i < output_total; i++)
348 {
349 if (strcmp(out_filename[i], "null") != 0 &&
350 strcmp(out_filename[i], "/dev/null") != 0)
351 {
352 output_fp[i] = NULL;
353 ni_fopen(&(output_fp[i]), out_filename[i], "wb");
354 if (!output_fp[i])
355 {
356 ni_log(NI_LOG_ERROR, "Error: Failed to open %s\n", out_filename[i]);
357 ret = -1;
358 goto end;
359 }
360 ni_log(NI_LOG_INFO, "Opened output file: %s\n", out_filename[i]);
361 } else
362 {
363 output_fp[i] = NULL;
364 ni_log(NI_LOG_INFO, "Note: Requested NULL output for index %d, no output file will be generated\n", i);
365 }
366 }
367
368 p_dec_api_param = malloc(sizeof(ni_xcoder_params_t));
369 if (!p_dec_api_param)
370 {
371 ni_log(NI_LOG_ERROR, "Error: failed to allocate p_dec_api_param\n");
372 ret = -1;
373 goto end;
374 }
375
376 p_enc_api_param = calloc(output_total, sizeof(ni_xcoder_params_t));
377 if (!p_enc_api_param)
378 {
379 ni_log(NI_LOG_ERROR, "Error: Failed to allocate memory for p_enc_api_param\n");
380 ret = -1;
381 goto end;
382 }
383
384 if (dec_codec_format == NI_CODEC_FORMAT_H264)
385 {
386 ret = probe_h264_stream_info(&ctx, &avc_sps);
387 if (ret)
388 {
390 "ERROR: Failed to probe input file as H.264, file format not supported!\n");
391 goto end;
392 }
393
394 bit_depth = avc_sps.bit_depth_luma;
395 input_width = avc_sps.width;
396 input_height = avc_sps.height;
397 ni_log(NI_LOG_DEBUG, "Using probed H.264 source info: %d bits, resolution %dx%d\n",
398 bit_depth, input_width, input_height);
399 } else if (dec_codec_format == NI_CODEC_FORMAT_H265)
400 {
401 ret = probe_h265_stream_info(&ctx, &hevc_sps);
402 if (ret)
403 {
405 "ERROR: Failed to probe input file as H.265, file format not supported!\n");
406 goto end;
407 }
408 bit_depth = hevc_sps.bit_depth_chroma;
409 input_width = (int)(hevc_sps.width -
410 (hevc_sps.pic_conf_win.left_offset +
411 hevc_sps.pic_conf_win.right_offset));
412 input_height = (int)(hevc_sps.height -
413 (hevc_sps.pic_conf_win.top_offset +
414 hevc_sps.pic_conf_win.bottom_offset));
415 ni_log(NI_LOG_INFO, "Using probed H.265 source info: %d bits, resolution %dx%d\n",
416 bit_depth, input_width, input_height);
417 } else if (dec_codec_format == NI_CODEC_FORMAT_VP9)
418 {
419 ret = probe_vp9_stream_info(&ctx, &vp9_info);
420 if (ret)
421 {
423 "ERROR: Failed to probe input file as VP9, file format not supported!\n");
424 goto end;
425 }
426 bit_depth = vp9_info.profile ? 10 : 8;
427 input_width = vp9_info.width;
428 input_height = vp9_info.height;
430 "Using probed VP9 source info: %d bits, resolution %dx%d, timebase %u/%u\n",
431 bit_depth, input_width, input_height,
432 vp9_info.timebase.den, vp9_info.timebase.num);
433 }
434
435 // set up decoder config params with some hard-coded values
436 ret = ni_decoder_init_default_params(p_dec_api_param, 25, 1, 200000, input_width, input_height);
437 if (ret)
438 {
439 ni_log(NI_LOG_ERROR, "Error: Failed to init default decoder config\n");
440 goto end;
441 }
442
443 ret = ni_device_session_context_init(&dec_ctx);
444 if (ret)
445 {
446 ni_log(NI_LOG_ERROR, "Error: Failed to init decoder context\n");
447 goto end;
448 }
449
450 dec_ctx.codec_format = dec_codec_format;
451 dec_ctx.src_bit_depth = bit_depth;
452 dec_ctx.bit_depth_factor = 1;
453 if (10 == dec_ctx.src_bit_depth)
454 {
455 dec_ctx.bit_depth_factor = 2;
456 }
457 if ((NI_CODEC_FORMAT_H264 == dec_codec_format) || (NI_CODEC_FORMAT_H265 == dec_codec_format))
458 dec_ctx.enable_user_data_sei_passthru = user_data_sei_passthru;
459
460 // check and set ni_decoder_params from --xcoder-params
461 ret = ni_retrieve_decoder_params(dec_conf_params, p_dec_api_param, &dec_ctx);
462 if (ret)
463 {
464 ni_log(NI_LOG_ERROR, "Error: decoder config params parsing error\n");
465 goto end;
466 }
467
468 // Decode, use all the parameters specified by user
469 ret = decoder_open_session(&dec_ctx, xcoderGUID, p_dec_api_param);
470 if (ret)
471 {
472 ni_log(NI_LOG_ERROR, "Error: Failed to open decoder session\n");
473 goto end;
474 }
475
476 for (i = 0; i < output_total; i++)
477 {
478 if (ni_device_session_context_init(&enc_ctx[i]) < 0)
479 {
480 ni_log(NI_LOG_ERROR, "Error: init encoder %d context error\n", i);
481 ret = -1;
482 goto end;
483 }
484 }
485
486 for (i = 0; i < output_total; i++)
487 {
488 enc_ctx[i].codec_format = enc_codec_format;
489 }
490
491 if (dec_codec_format == NI_CODEC_FORMAT_H264)
492 p_stream_info = &avc_sps;
493 else if (dec_codec_format == NI_CODEC_FORMAT_H265)
494 p_stream_info = &hevc_sps;
495 else if (dec_codec_format == NI_CODEC_FORMAT_VP9)
496 {
497 p_stream_info = &vp9_info;
498 fps_num = vp9_info.timebase.den;
499 fps_den = vp9_info.timebase.num;
500 }
501
502 output_width = input_width;
503 output_height = input_height;
504
505 if (filter_conf_params[0])
506 {
507 if (!dec_ctx.hw_action) {
508 ni_log(NI_LOG_ERROR, "Error: filters are only supported when hwframe is enabled (out=hw)\n");
509 ret = -1;
510 goto end;
511 }
512 ret = retrieve_filter_params(filter_conf_params, &scale_params, &drawbox_params, &ai_pre_params);
513 if (ret)
514 {
515 ni_log(NI_LOG_ERROR, "Error: failed to parse filter parameters: %s\n", filter_conf_params);
516 goto end;
517 }
518 if (ai_pre_params.enabled)
519 {
520 ni_log(NI_LOG_ERROR, "Error: ni_quadra_ai_pre is not supported in this demo\n");
521 ret = -1;
522 goto end;
523 }
524 }
525
526 if (scale_params.enabled)
527 {
528 ret = ni_device_session_context_init(&sca_ctx);
529 if (ret)
530 {
531 ni_log(NI_LOG_ERROR, "Error: Failed to init scale context\n");
532 goto end;
533 }
534 output_width = scale_params.width;
535 output_height = scale_params.height;
536 }
537 else if (drawbox_params.enabled)
538 {
539 ret = ni_device_session_context_init(&crop_ctx);
540 if (ret)
541 {
542 ni_log(NI_LOG_ERROR, "Error: Failed to init crop context\n");
543 goto end;
544 }
545 ret = ni_device_session_context_init(&pad_ctx);
546 if (ret)
547 {
548 ni_log(NI_LOG_ERROR, "Error: Failed to init pad context\n");
549 goto end;
550 }
551 ret = ni_device_session_context_init(&ovly_ctx);
552 if (ret)
553 {
554 ni_log(NI_LOG_ERROR, "Error: Failed to init overlay context\n");
555 goto end;
556 }
557 ret = ni_device_session_context_init(&fmt_ctx);
558 if (ret)
559 {
560 ni_log(NI_LOG_ERROR, "Error: Failed to init format context\n");
561 goto end;
562 }
563 }
564
565 ni_log(NI_LOG_INFO, "Starting to transcode: HWFrames %d, video resolution %dx%d -> %dx%d\n",
566 dec_ctx.hw_action, input_width, input_height, output_width, output_height);
567
569
570 // init and create decoding thread
571 dec_send_param.p_ctx = &ctx;
572 dec_send_param.p_dec_ctx = &dec_ctx;
573 dec_send_param.input_width = input_width;
574 dec_send_param.input_height = input_height;
575 dec_send_param.p_stream_info = p_stream_info;
576 dec_send_param.frame_list = &frame_list;
577
578 dec_recv_param.p_ctx = &ctx;
579 dec_recv_param.p_dec_ctx = &dec_ctx;
580 dec_recv_param.p_sca_ctx = &sca_ctx;
581 dec_recv_param.p_crop_ctx = &crop_ctx;
582 dec_recv_param.p_pad_ctx = &pad_ctx;
583 dec_recv_param.p_ovly_ctx = &ovly_ctx;
584 dec_recv_param.p_fmt_ctx = &fmt_ctx;
585 dec_recv_param.xcoderGUID = xcoderGUID;
586 dec_recv_param.input_width = input_width;
587 dec_recv_param.input_height = input_height;
588 dec_recv_param.frame_list = &frame_list;
589 dec_recv_param.scale_params = &scale_params;
590 dec_recv_param.drawbox_params = &drawbox_params;
591
592 if (ni_pthread_create(&dec_send_tid, NULL, decoder_send_thread,
594 {
596 "Error: create decoder send thread failed in transcode "
597 "mode\n");
598 return -1;
599 }
600 if (ni_pthread_create(&dec_recv_tid, NULL, decoder_receive_thread,
602 {
604 "Error: create decoder receive thread failed in "
605 "transcode mode\n");
606 return -1;
607 }
608
609 // polling the first received decoded frame
610 while (frame_list_is_empty(&frame_list) && !ctx.end_all_threads)
611 {
612 ni_usleep(100);
613 }
614
615 if (!ctx.end_all_threads)
616 {
617 p_ni_frame = &frame_list.frames[frame_list.head].data.frame;
618 p_hwframe = dec_ctx.hw_action == NI_CODEC_HW_ENABLE ?
619 (niFrameSurface1_t *)p_ni_frame->p_data[3] : NULL;
620
621 if (scale_params.enabled)
622 enc_pix_fmt = gc620_to_ni_pix_fmt(scale_params.format);
623 else if (drawbox_params.enabled)
624 enc_pix_fmt = NI_PIX_FMT_YUV420P;
625 else
626 enc_pix_fmt = dec_ctx.pixel_format;
627
628 ret = encoder_open(&ctx, enc_ctx, p_enc_api_param, output_total, enc_conf_params, enc_gop_params,
629 p_ni_frame, output_width, output_height, fps_num, fps_den, bitrate,
630 enc_codec_format, enc_pix_fmt, p_ni_frame->aspect_ratio_idc,
631 xcoderGUID, p_hwframe, 1, false);
632 if (ret != 0)
633 {
634 goto end;
635 }
636
637 // init and create encoding thread
638 enc_send_param.p_ctx = &ctx;
639 enc_send_param.p_enc_ctx = enc_ctx;
640 enc_send_param.output_width = output_width;
641 enc_send_param.output_height = output_height;
642 enc_send_param.output_total = output_total;
643 enc_send_param.frame_list = &frame_list;
644
645 enc_recv_param.p_ctx = &ctx;
646 enc_recv_param.p_enc_ctx = enc_ctx;
647 enc_recv_param.output_width = output_width;
648 enc_recv_param.output_height = output_height;
649 enc_recv_param.p_file = output_fp;
650 enc_recv_param.output_total = output_total;
651 enc_recv_param.frame_list = &frame_list;
652
653 if (ni_pthread_create(&enc_send_tid, NULL, encoder_send_thread,
655 {
656 ni_log(NI_LOG_ERROR, "Error: create encoder send thread failed "
657 "in transcode mode\n");
658 return -1;
659 }
660 if (ni_pthread_create(&enc_recv_tid, NULL, encoder_receive_thread,
662 {
663 ni_log(NI_LOG_ERROR, "Error: create encoder recieve thread "
664 "failed in transcode mode\n");
665 return -1;
666 }
667
668 ni_pthread_join(enc_send_tid, NULL);
669 ni_pthread_join(enc_recv_tid, NULL);
670 }
671 ni_pthread_join(dec_send_tid, NULL);
672 ni_pthread_join(dec_recv_tid, NULL);
673
674end:
675 decoder_stat_report_and_close(&ctx, &dec_ctx);
676 encoder_stat_report_and_close(&ctx, enc_ctx, output_total);
677
678#ifdef _WIN32
680 for (i = 0; i < output_total; i++)
681 {
682 ni_device_close(enc_ctx[i].device_handle);
683 }
684 if (scale_params.enabled)
685 {
687 }
688 if (drawbox_params.enabled)
689 {
694 }
695#elif __linux__
698 for (i = 0; i < output_total; i++)
699 {
700 ni_device_close(enc_ctx[i].device_handle);
701 ni_device_close(enc_ctx[i].blk_io_handle);
702 }
703 if (scale_params.enabled)
704 {
707 }
708 if (drawbox_params.enabled)
709 {
718 }
719#endif
720
721 hwframe_list_release(&frame_list);
722
724 for (i = 0; i < output_total; i++)
725 {
727 if (output_fp[i] != NULL)
728 {
729 fclose(output_fp[i]);
730 }
731 }
732 if (scale_params.enabled)
733 {
735 }
736 if (drawbox_params.enabled)
737 {
742 }
743
744 free(ctx.file_cache);
745
746 for(i = 0; i < MAX_OUTPUT_FILES; ++i)
747 {
748 free(ctx.enc_pts_queue[i]);
749 ctx.enc_pts_queue[i] = NULL;
750 }
751
752 free(p_dec_api_param);
753 free(p_enc_api_param);
754
755 return ret;
756}
int main()
Definition client.cpp:51
void decoder_stat_report_and_close(ni_demo_context_t *p_ctx, ni_session_context_t *p_dec_ctx)
int probe_h264_stream_info(ni_demo_context_t *p_ctx, ni_h264_sps_t *sps)
void * decoder_send_thread(void *args)
int decoder_open_session(ni_session_context_t *p_dec_ctx, int iXcoderGUID, ni_xcoder_params_t *p_dec_params)
decoder session open
int probe_h265_stream_info(ni_demo_context_t *p_ctx, ni_h265_sps_t *sps)
void * decoder_receive_thread(void *args)
int probe_vp9_stream_info(ni_demo_context_t *p_ctx, ni_vp9_header_info_t *vp9_info)
#define NI_XCODER_REVISION
Definition ni_defs.h:98
ni_retcode_t ni_device_session_context_init(ni_session_context_t *p_ctx)
Initialize already allocated session context to a known state.
ni_retcode_t ni_decoder_init_default_params(ni_xcoder_params_t *p_param, int fps_num, int fps_denom, long bit_rate, int width, int height)
Initialize default decoder parameters.
void ni_device_close(ni_device_handle_t device_handle)
Close device and release resources.
void ni_device_session_context_clear(ni_session_context_t *p_ctx)
Clear already allocated session context.
@ NI_CODEC_HW_ENABLE
@ NI_CODEC_FORMAT_H265
@ NI_CODEC_FORMAT_AV1
@ NI_CODEC_FORMAT_H264
@ NI_CODEC_FORMAT_VP9
ni_pix_fmt_t
@ NI_PIX_FMT_YUV420P
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)
void * encoder_receive_thread(void *args)
void encoder_stat_report_and_close(ni_demo_context_t *p_ctx, ni_session_context_t *p_enc_ctx_list, int output_total)
void * encoder_send_thread(void *args)
int retrieve_filter_params(char filter_params[], ni_scale_params_t *scale_params, ni_drawbox_params_t *drawbox_params, ni_ai_pre_params_t *ai_pre_params)
ni_pix_fmt_t gc620_to_ni_pix_fmt(int pix_fmt)
bool frame_list_is_empty(ni_test_frame_list_t *list)
int read_and_cache_file(ni_demo_context_t *ctx, char *filename)
void hwframe_list_release(ni_test_frame_list_t *list)
void print_version(void)
#define MAX_OUTPUT_FILES
#define FILE_NAME_LEN
char * optarg
Definition ni_getopt.c:33
int getopt_long(int argc, char *argv[], const char *optstring, const struct option *longopts, int *longindex)
Definition ni_getopt.c:99
Implementation of getopt() and getopt_long() for Windows environment.
#define no_argument
Definition ni_getopt.h:85
#define required_argument
Definition ni_getopt.h:86
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
void ni_log_set_level(ni_log_level_t level)
Set ni_log_level.
Definition ni_log.c:202
void ni_log(ni_log_level_t level, const char *fmt,...)
print log message using ni_log_callback
Definition ni_log.c:183
Logging definitions.
ni_log_level_t
Definition ni_log.h:58
@ NI_LOG_DEBUG
Definition ni_log.h:64
@ NI_LOG_ERROR
Definition ni_log.h:62
@ NI_LOG_INFO
Definition ni_log.h:63
@ NI_LOG_INVALID
Definition ni_log.h:59
int ni_pthread_create(ni_pthread_t *thread, const ni_pthread_attr_t *attr, void *(*start_routine)(void *), void *arg)
create a new thread
Definition ni_util.c:4836
ni_retcode_t ni_fopen(FILE **fp, const char *filename, const char *mode)
Definition ni_util.c:998
ni_retcode_t ni_strcpy(char *dest, size_t dmax, const char *src)
Definition ni_util.c:460
int ni_retrieve_decoder_params(char xcoderParams[], ni_xcoder_params_t *params, ni_session_context_t *ctx)
retrieve decoder config parameter values from –decoder-params
Definition ni_util.c:4646
void ni_usleep(int64_t usec)
Definition ni_util.c:366
uint64_t ni_gettime_ns(void)
Definition ni_util.c:2701
int ni_pthread_join(ni_pthread_t thread, void **value_ptr)
join with a terminated thread
Definition ni_util.c:4863
Utility definitions.
ni_pts_queue * enc_pts_queue[MAX_OUTPUT_FILES]
uint8_t aspect_ratio_idc
uint8_t * p_data[NI_MAX_NUM_DATA_POINTERS]
int bit_depth_luma
bit_depth_luma_minus8 + 8
ni_h265_window_t pic_conf_win
unsigned int left_offset
unsigned int bottom_offset
unsigned int right_offset
unsigned int top_offset
ni_device_handle_t device_handle
ni_device_handle_t blk_io_handle
union _ni_session_data_io::@19 data
ni_session_data_io_t frames[NI_MAX_BUFFERED_FRAME]
struct _ni_vp9_header_info::@3 timebase
ni_demo_context_t * p_ctx
ni_drawbox_params_t * drawbox_params
ni_session_context_t * p_sca_ctx
ni_scale_params_t * scale_params
ni_session_context_t * p_pad_ctx
ni_session_context_t * p_dec_ctx
ni_session_context_t * p_ovly_ctx
ni_session_context_t * p_crop_ctx
ni_test_frame_list_t * frame_list
ni_session_context_t * p_fmt_ctx
ni_demo_context_t * p_ctx
ni_session_context_t * p_dec_ctx
ni_test_frame_list_t * frame_list
ni_session_context_t * p_enc_ctx
ni_demo_context_t * p_ctx
ni_test_frame_list_t * frame_list
ni_session_context_t * p_enc_ctx
ni_demo_context_t * p_ctx
ni_test_frame_list_t * frame_list