libxcoder 5.6.0
Loading...
Searching...
No Matches
ni_xcoder_transcode_filter.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_transcode_filter.c
24 *
25 * \brief Video transcoding and filtering demo application directly using
26 * 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 "Video transcoding demo application directly using Netint Libxcoder version %s\n"
47 "Usage: ni_xcoder_transcode_filter [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, f_index = 0;
98 int output_total = 0;
99 int input_width = 0, input_height = 0, bit_depth = 8;
100 int output_width[MAX_OUTPUT_FILES] = {0};
101 int output_height[MAX_OUTPUT_FILES] = {0};
102 int dec_codec_format = -1, enc_codec_format = -1;
103 ni_log_level_t log_level;
104 int xcoderGUID = 0;
105 char *n;
106 char dec_conf_params[2048] = {0};
107 char filter_conf_params[MAX_OUTPUT_FILES][2048] = {0};
108 char enc_conf_params[MAX_OUTPUT_FILES][2048] = {0};
109 char enc_gop_params[MAX_OUTPUT_FILES][2048] = {0};
110 int user_data_sei_passthru = 0;
111 ni_h264_sps_t avc_sps = {0};
112 ni_h265_sps_t hevc_sps = {0};
113 ni_vp9_header_info_t vp9_info = {0};
114 ni_xcoder_params_t *p_dec_api_param = NULL;
115 ni_xcoder_params_t *p_enc_api_param = NULL;
116 ni_session_context_t dec_ctx = {0};
119 ni_session_context_t crop_ctx = {0};
120 ni_session_context_t pad_ctx = {0};
121 ni_session_context_t ovly_ctx = {0};
122 ni_session_context_t fmt_ctx = {0};
123 int send_rc = NI_TEST_RETCODE_SUCCESS, receive_rc = NI_TEST_RETCODE_SUCCESS, rx_size = 0;
124 void *p_stream_info = NULL;
125 int fps_num = 30, fps_den = 1, bitrate = 200000;
126 uint64_t current_time, previous_time;
127 ni_session_data_io_t in_pkt = {0};
128 ni_session_data_io_t out_frame = {0};
129 ni_session_data_io_t filter_out_frame[MAX_OUTPUT_FILES] = {0};
131 ni_session_data_io_t enc_in_frame = {0};
132 ni_session_data_io_t out_packet[MAX_OUTPUT_FILES] = {0};
133 niFrameSurface1_t *p_hwframe = NULL;
135 int encoder_opened = 0, end_of_all_streams = 0;
136 ni_scale_params_t scale_params[MAX_OUTPUT_FILES] = {0};
137 ni_drawbox_params_t drawbox_params = {0};
138 ni_pix_fmt_t enc_pix_fmt[MAX_OUTPUT_FILES];
139 int hw_frame_ref_flag = 0;
140 int recycle_hw_frame_for_scaler = 0;
141
142 int opt;
143 int opt_index;
144 const char *opt_string = "hvi:o:m:n:l:c:r:d:e:g:uf:";
145 static struct option long_options[] = {
146 {"help", no_argument, NULL, 'h'},
147 {"version", no_argument, NULL, 'v'},
148 {"input", required_argument, NULL, 'i'},
149 {"output", required_argument, NULL, 'o'},
150 {"dec-codec", required_argument, NULL, 'n'},
151 {"enc-codec", required_argument, NULL, 'm'},
152 {"loglevel", required_argument, NULL, 'l'},
153 {"card", required_argument, NULL, 'c'},
154 {"repeat", required_argument, NULL, 'r'},
155 {"decoder-params", required_argument, NULL, 'd'},
156 {"encoder-params", required_argument, NULL, 'e'},
157 {"encoder-gop", required_argument, NULL, 'g'},
158 {"user-data-sei-passthru", no_argument, NULL, 'u'},
159 {"vf", required_argument, NULL, 'f'},
160 {NULL, 0, NULL, 0},
161 };
162
163 while ((opt = getopt_long(argc, argv, opt_string, long_options, &opt_index)) != -1)
164 {
165 switch (opt)
166 {
167 case 'h':
168 print_usage();
169 ret = 0;
170 goto end;
171 case 'v':
173 ret = 0;
174 goto end;
175 case 'i':
176 ni_strcpy(in_filename, FILE_NAME_LEN, optarg);
177 break;
178 case 'o':
179 if (o_index == MAX_OUTPUT_FILES)
180 {
181 ni_log(NI_LOG_ERROR, "Error: number of output files cannot exceed %d\n", MAX_OUTPUT_FILES);
182 ret = -1;
183 goto end;
184 }
185
186 for (i = 0; i < o_index; i++)
187 {
188 if (0 == strcmp(out_filename[i], optarg))
189 {
190 ni_log(NI_LOG_ERROR, "Error: output file names must be unique: %s\n", optarg);
191 ret = -1;
192 goto end;
193 }
194 }
195
196 ni_strcpy(out_filename[o_index], FILE_NAME_LEN, optarg);
197 o_index++;
198 break;
199 case 'm':
200 // Accept both upper and lower case
201 for (i = 0; i < strlen(optarg); i++)
202 {
203 optarg[i] = (char)tolower((unsigned char)optarg[i]);
204 }
205 if (strcmp(optarg, "a") == 0 || strcmp(optarg, "avc") == 0)
206 {
207 dec_codec_format = NI_CODEC_FORMAT_H264;
208 }
209 else if (strcmp(optarg, "h") == 0 || strcmp(optarg, "hevc") == 0)
210 {
211 dec_codec_format = NI_CODEC_FORMAT_H265;
212 }
213 else if (strcmp(optarg, "v") == 0 || strcmp(optarg, "vp9") == 0)
214 {
215 dec_codec_format = NI_CODEC_FORMAT_VP9;
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, v|vp9]\n", optarg);
221 ret = -1;
222 goto end;
223 }
224 break;
225 case 'n':
226 // Accept both upper and lower case
227 for (i = 0; i < strlen(optarg); i++)
228 {
229 optarg[i] = (char)tolower((unsigned char)optarg[i]);
230 }
231 if (strcmp(optarg, "a") == 0 || strcmp(optarg, "avc") == 0)
232 {
233 enc_codec_format = NI_CODEC_FORMAT_H264;
234 }
235 else if (strcmp(optarg, "h") == 0 || strcmp(optarg, "hevc") == 0)
236 {
237 enc_codec_format = NI_CODEC_FORMAT_H265;
238 }
239 else if (strcmp(optarg, "x") == 0 || strcmp(optarg, "av1") == 0)
240 {
241 enc_codec_format = NI_CODEC_FORMAT_AV1;
242 }
243 else
244 {
245 ni_log(NI_LOG_ERROR, "Error: Invalid value \"%s\" for -n | --enc-codec option\n"
246 "Must be one of [a|avc, h|hevc, x|av1]\n", optarg);
247 ret = -1;
248 goto end;
249 }
250 break;
251 case 'l':
252 log_level = arg_to_ni_log_level(optarg);
253 if (log_level != NI_LOG_INVALID)
254 {
255 ni_log_set_level(log_level);
256 }
257 else
258 {
259 ni_log(NI_LOG_ERROR, "Error: Invalid value \"%s\" for -l | --loglevel option\n"
260 "Must be one of [none, fatal, error, info, debug, trace]\n", optarg);
261 ret = -1;
262 goto end;
263 }
264 break;
265 case 'c':
266 xcoderGUID = (int)strtol(optarg, &n, 10);
267 if (n == optarg || *n != '\0' || xcoderGUID < 0)
268 {
269 ni_log(NI_LOG_ERROR, "Error: Invalid value \"%s\" for -c | --card option\n"
270 "Must be a non-negative integer\n", optarg);
271 ret = -1;
272 goto end;
273 }
274 break;
275 case 'r':
276 ctx.loops_left = strtol(optarg, &n, 10);
277 if (n == optarg || *n != '\0' || !(ctx.loops_left >= 1))
278 {
279 ni_log(NI_LOG_ERROR, "Error: Invalid value \"%s\" for -r | --repeat option\n"
280 "Must be a positive integer\n", optarg);
281 ret = -1;
282 goto end;
283 }
284 break;
285 case 'd':
286 ni_strcpy(dec_conf_params, sizeof(dec_conf_params), optarg);
287 break;
288 case 'e':
289 if (e_index == MAX_OUTPUT_FILES)
290 {
291 ni_log(NI_LOG_ERROR, "Error: number of encoder config cannot exceed %d\n", MAX_OUTPUT_FILES);
292 ret = -1;
293 goto end;
294 }
295 ni_strcpy(enc_conf_params[e_index], sizeof(enc_conf_params[e_index]), optarg);
296 e_index++;
297 break;
298 case 'g':
299 if (g_index == MAX_OUTPUT_FILES)
300 {
301 ni_log(NI_LOG_ERROR, "Error: number of encoder gop settings cannot exceed %d\n", MAX_OUTPUT_FILES);
302 ret = -1;
303 goto end;
304 }
305 ni_strcpy(enc_gop_params[g_index], sizeof(enc_gop_params[g_index]), optarg);
306 g_index++;
307 break;
308 case 'u':
309 user_data_sei_passthru = 1;
310 break;
311 case 'f':
312 if (f_index == MAX_OUTPUT_FILES)
313 {
314 ni_log(NI_LOG_ERROR, "Error: number of filter config cannot exceed %d\n", MAX_OUTPUT_FILES);
315 ret = -1;
316 goto end;
317 }
318 ni_strcpy(filter_conf_params[f_index], sizeof(filter_conf_params[f_index]), optarg);
319 f_index++;
320 break;
321 default:
322 print_usage();
323 ret = -1;
324 goto end;
325 }
326 }
327
328 if (!in_filename[0]) {
329 ni_log(NI_LOG_ERROR, "Error: Missing input file argument (-i | --input)\n");
330 ret = -1;
331 goto end;
332 }
333
334 if (o_index == 0) {
335 ni_log(NI_LOG_ERROR, "Error: Missing output file argument (-o | --output)\n");
336 ret = -1;
337 goto end;
338 }
339
340 if (dec_codec_format == -1) {
341 ni_log(NI_LOG_ERROR, "Error: Missing decoder codec argument (-m | --dec-codec)\n");
342 ret = -1;
343 goto end;
344 }
345
346 if (enc_codec_format == -1) {
347 ni_log(NI_LOG_ERROR, "Error: Missing encoder codec argument (-n | --enc-codec)\n");
348 ret = -1;
349 goto end;
350 }
351
352 ret = read_and_cache_file(&ctx, in_filename);
353 if (ret)
354 {
355 ni_log(NI_LOG_ERROR, "Error: Read input file failure\n");
356 goto end;
357 }
358
359 output_total = o_index;
360 for (i = 0; i < output_total; i++)
361 {
362 if (strcmp(out_filename[i], "null") != 0 &&
363 strcmp(out_filename[i], "/dev/null") != 0)
364 {
365 output_fp[i] = NULL;
366 ni_fopen(&(output_fp[i]), out_filename[i], "wb");
367 if (!output_fp[i])
368 {
369 ni_log(NI_LOG_ERROR, "Error: Failed to open %s\n", out_filename[i]);
370 ret = -1;
371 goto end;
372 }
373 ni_log(NI_LOG_INFO, "Opened output file: %s\n", out_filename[i]);
374 } else
375 {
376 output_fp[i] = NULL;
377 ni_log(NI_LOG_INFO, "Note: Requested NULL output for index %d, no output file will be generated\n", i);
378 }
379
380 frame_to_enc[i] = NULL;
381 enc_pix_fmt[i] = NI_PIX_FMT_YUV420P;
382 p_hwframe2[i] = NULL;
383 }
384
385 p_dec_api_param = malloc(sizeof(ni_xcoder_params_t));
386 if (!p_dec_api_param)
387 {
388 ni_log(NI_LOG_ERROR, "Error: failed to allocate p_dec_api_param\n");
389 ret = -1;
390 goto end;
391 }
392
393 p_enc_api_param = calloc(output_total, sizeof(ni_xcoder_params_t));
394 if (!p_enc_api_param)
395 {
396 ni_log(NI_LOG_ERROR, "Error: Failed to allocate memory for p_enc_api_param\n");
397 ret = -1;
398 goto end;
399 }
400
401 if (dec_codec_format == NI_CODEC_FORMAT_H264)
402 {
403 ret = probe_h264_stream_info(&ctx, &avc_sps);
404 if (ret)
405 {
407 "ERROR: Failed to probe input file as H.264, file format not supported!\n");
408 goto end;
409 }
410
411 bit_depth = avc_sps.bit_depth_luma;
412 input_width = avc_sps.width;
413 input_height = avc_sps.height;
414 ni_log(NI_LOG_DEBUG, "Using probed H.264 source info: %d bits, resolution %dx%d\n",
415 bit_depth, input_width, input_height);
416 } else if (dec_codec_format == NI_CODEC_FORMAT_H265)
417 {
418 ret = probe_h265_stream_info(&ctx, &hevc_sps);
419 if (ret)
420 {
422 "ERROR: Failed to probe input file as H.265, file format not supported!\n");
423 goto end;
424 }
425 bit_depth = hevc_sps.bit_depth_chroma;
426 input_width = (int)(hevc_sps.width -
427 (hevc_sps.pic_conf_win.left_offset +
428 hevc_sps.pic_conf_win.right_offset));
429 input_height = (int)(hevc_sps.height -
430 (hevc_sps.pic_conf_win.top_offset +
431 hevc_sps.pic_conf_win.bottom_offset));
432 ni_log(NI_LOG_INFO, "Using probed H.265 source info: %d bits, resolution %dx%d\n",
433 bit_depth, input_width, input_height);
434 } else if (dec_codec_format == NI_CODEC_FORMAT_VP9)
435 {
436 ret = probe_vp9_stream_info(&ctx, &vp9_info);
437 if (ret)
438 {
440 "ERROR: Failed to probe input file as VP9, file format not supported!\n");
441 goto end;
442 }
443 bit_depth = vp9_info.profile ? 10 : 8;
444 input_width = vp9_info.width;
445 input_height = vp9_info.height;
447 "Using probed VP9 source info: %d bits, resolution %dx%d, timebase %u/%u\n",
448 bit_depth, input_width, input_height,
449 vp9_info.timebase.den, vp9_info.timebase.num);
450 }
451
452 // set up decoder config params with some hard-coded values
453 ret = ni_decoder_init_default_params(p_dec_api_param, 25, 1, 200000, input_width, input_height);
454 if (ret)
455 {
456 ni_log(NI_LOG_ERROR, "Error: Failed to init default decoder config\n");
457 goto end;
458 }
459
460 ret = ni_device_session_context_init(&dec_ctx);
461 if (ret)
462 {
463 ni_log(NI_LOG_ERROR, "Error: Failed to init decoder context\n");
464 goto end;
465 }
466
467 dec_ctx.codec_format = dec_codec_format;
468 dec_ctx.src_bit_depth = bit_depth;
469 dec_ctx.bit_depth_factor = 1;
470 if (10 == dec_ctx.src_bit_depth)
471 {
472 dec_ctx.bit_depth_factor = 2;
473 }
474 if ((NI_CODEC_FORMAT_H264 == dec_codec_format) || (NI_CODEC_FORMAT_H265 == dec_codec_format))
475 dec_ctx.enable_user_data_sei_passthru = user_data_sei_passthru;
476
477 // check and set ni_decoder_params from --xcoder-params
478 ret = ni_retrieve_decoder_params(dec_conf_params, p_dec_api_param, &dec_ctx);
479 if (ret)
480 {
481 ni_log(NI_LOG_ERROR, "Error: decoder config params parsing error\n");
482 goto end;
483 }
484
485 // Decode, use all the parameters specified by user
486 ret = decoder_open_session(&dec_ctx, xcoderGUID, p_dec_api_param);
487 if (ret)
488 {
489 ni_log(NI_LOG_ERROR, "Error: Failed to open decoder session\n");
490 goto end;
491 }
492
493 for (i = 0; i < output_total; i++)
494 {
495 if (ni_device_session_context_init(&enc_ctx[i]) < 0)
496 {
497 ni_log(NI_LOG_ERROR, "Error: init encoder %d context error\n", i);
498 ret = -1;
499 goto end;
500 }
501 }
502
503 for (i = 0; i < output_total; i++)
504 {
505 enc_ctx[i].codec_format = enc_codec_format;
506 output_width[i] = input_width;
507 output_height[i] = input_height;
508 }
509
510 if (dec_codec_format == NI_CODEC_FORMAT_H264)
511 p_stream_info = &avc_sps;
512 else if (dec_codec_format == NI_CODEC_FORMAT_H265)
513 p_stream_info = &hevc_sps;
514 else if (dec_codec_format == NI_CODEC_FORMAT_VP9)
515 {
516 p_stream_info = &vp9_info;
517 fps_num = vp9_info.timebase.den;
518 fps_den = vp9_info.timebase.num;
519 }
520
521 for (i = 0; i < output_total; i++)
522 {
523 if (filter_conf_params[i][0])
524 {
525 if (!dec_ctx.hw_action) {
526 ni_log(NI_LOG_ERROR, "Error: filters are only supported when hwframe is enabled (out=hw)\n");
527 ret = -1;
528 goto end;
529 }
530
531 ret = retrieve_filter_params(filter_conf_params[i], &scale_params[i], &drawbox_params);
532 if (ret)
533 {
534 ni_log(NI_LOG_ERROR, "Error: failed to parse filter parameters: %s\n", filter_conf_params[i]);
535 goto end;
536 }
537 }
538
539 if (scale_params[i].enabled)
540 {
541 ret = ni_device_session_context_init(&sca_ctx[i]);
542 if (ret)
543 {
544 ni_log(NI_LOG_ERROR, "Error: Failed to init scale context\n");
545 goto end;
546 }
547 output_width[i] = scale_params[i].width;
548 output_height[i] = scale_params[i].height;
549 }
550 else if ((drawbox_params.enabled)) // drawbox is only supported for a single instance in this example.
551 {
552 ret = ni_device_session_context_init(&crop_ctx);
553 if (ret)
554 {
555 ni_log(NI_LOG_ERROR, "Error: Failed to init crop context\n");
556 goto end;
557 }
558 ret = ni_device_session_context_init(&pad_ctx);
559 if (ret)
560 {
561 ni_log(NI_LOG_ERROR, "Error: Failed to init pad context\n");
562 goto end;
563 }
564 ret = ni_device_session_context_init(&ovly_ctx);
565 if (ret)
566 {
567 ni_log(NI_LOG_ERROR, "Error: Failed to init overlay context\n");
568 goto end;
569 }
570 ret = ni_device_session_context_init(&fmt_ctx);
571 if (ret)
572 {
573 ni_log(NI_LOG_ERROR, "Error: Failed to init format context\n");
574 goto end;
575 }
576 break;
577 }
578 }
579
580 for (i = 0; i < output_total; i++)
581 {
582 if (drawbox_params.enabled && scale_params[i].enabled){
583 ni_log(NI_LOG_ERROR, "Error: Mixing scale and drawbox filter is not supported in this demo\n");
584 goto end;
585 }
586 ni_log(NI_LOG_INFO, "(Task %d) Starting to transcode: HWFrames %d, video resolution %dx%d -> %dx%d\n",
587 i, dec_ctx.hw_action, input_width, input_height, output_width[i], output_height[i]);
588 }
589
592
593 while (!end_of_all_streams &&
594 (send_rc == NI_TEST_RETCODE_SUCCESS || receive_rc == NI_TEST_RETCODE_SUCCESS ||
595 (send_rc == NI_TEST_RETCODE_EAGAIN && receive_rc == NI_TEST_RETCODE_EAGAIN)))
596 {
597 // bitstream Sending
598decode_send:
599 send_rc = decoder_send_data(&ctx, &dec_ctx, &in_pkt, input_width, input_height, p_stream_info);
600 if (send_rc < 0)
601 {
602 ni_log(NI_LOG_ERROR, "Error: decoder send packet failed\n");
603 ret = send_rc;
604 break;
605 }
606
607 // YUV Receiving: not writing to file
608 receive_rc = decoder_receive_data(&ctx, &dec_ctx, &out_frame, input_width,
609 input_height, NULL, 0, &rx_size);
610
611 for (i = 0; i < output_total; i++)
612 {
613 frame_to_enc[i] = &out_frame;
614 }
615
616 if (receive_rc < 0)
617 {
618 ni_log(NI_LOG_ERROR, "Error: decoder receive frame failed\n");
619 ret = receive_rc;
620 break;
621 }
622 else if (receive_rc == NI_TEST_RETCODE_EAGAIN)
623 {
624 if (!dec_ctx.hw_action)
625 {
627 } else
628 {
629 ni_frame_buffer_free(&(out_frame.data.frame));
630 }
631
632 // use first encode config low delay flag for call flow
633 if (p_enc_api_param[0].low_delay_mode <= 0 && encoder_opened)
634 {
635 ni_log(NI_LOG_DEBUG, "no decoder output, jump to encoder receive!\n");
636 goto encode_recv;
637 } else
638 {
639 ni_log(NI_LOG_DEBUG, "no decoder output, encode low_delay, jump to decoder send!\n");
640 goto decode_send;
641 }
642 }
643 else if (receive_rc != NI_TEST_RETCODE_END_OF_STREAM)
644 {
645
646 p_hwframe = (niFrameSurface1_t *)out_frame.data.frame.p_data[3];
647 recycle_hw_frame_for_scaler = 1;
648 for (i = 0; i < output_total; i++)
649 {
650 if (scale_params[i].enabled)
651 {
652 if(!hw_frame_ref_flag)
653 {
654 hw_frame_ref_flag = 1;
655 ni_hw_frame_ref(p_hwframe);
656 }
657
658 scale_filter(&sca_ctx[i], &out_frame.data.frame, &filter_out_frame[i], xcoderGUID, scale_params[i].width,
659 scale_params[i].height, ni_to_gc620_pix_fmt(dec_ctx.pixel_format), scale_params[i].format);
660 frame_to_enc[i] = &filter_out_frame[i];
661 }
662 else if (drawbox_params.enabled)
663 {
664 if(!hw_frame_ref_flag)
665 {
666 hw_frame_ref_flag = 1;
667 ni_hw_frame_ref(p_hwframe);
668 }
669
670 drawbox_filter(&crop_ctx, &pad_ctx, &ovly_ctx, &fmt_ctx, &out_frame.data.frame, &filter_out_frame[0],
671 &drawbox_params, xcoderGUID, ni_to_gc620_pix_fmt(dec_ctx.pixel_format), GC620_I420);
672 for (i = 0; i < output_total; i++)
673 {
674 frame_to_enc[i] = &filter_out_frame[0];
675 }
676 break;
677 }
678
679 if (!scale_params[i].enabled)
680 recycle_hw_frame_for_scaler = 0;
681 }
682
683 // If the decoder generates a hardware frame, that frame is passed to the filter or the encoder directly.
684 // Once the (scaler) filter has used it, the frame should be recycled/unreferenced. (It is done here.)
685 // The filter then creates a new hardware frame, which is sent to the encoder and later recycled.
686 // When one transcoder uses a filter and another transcoder does not, the hardware frame produced
687 // by the decoder must NOT be recycled after the filter, because it will still be used by
688 // the encoder and will be recycled later. recycle_hw_frame_for_scaler is a flag for this purpose.
689 if((hw_frame_ref_flag) && (recycle_hw_frame_for_scaler))
690 {
691 hw_frame_ref_flag = 0;
693 }
694
695 if (!encoder_opened)
696 {
697 for (i = 0; i < output_total; i++)
698 {
699 p_hwframe2[i] = dec_ctx.hw_action == NI_CODEC_HW_ENABLE ?
700 (niFrameSurface1_t *)frame_to_enc[i]->data.frame.p_data[3] : NULL;
701
702 if (scale_params[i].enabled)
703 enc_pix_fmt[i] = gc620_to_ni_pix_fmt(scale_params[i].format);
704 else if (drawbox_params.enabled)
705 enc_pix_fmt[i] = NI_PIX_FMT_YUV420P;
706 else
707 enc_pix_fmt[i] = dec_ctx.pixel_format;
708 }
709
710 ret = encoder_open2(&ctx, enc_ctx, p_enc_api_param, output_total, enc_conf_params,
711 enc_gop_params, &out_frame.data.frame, output_width, output_height,
712 fps_num, fps_den, bitrate, enc_codec_format, enc_pix_fmt,
713 out_frame.data.frame.aspect_ratio_idc, xcoderGUID, p_hwframe2, 0, false);
714 if (ret != 0)
715 {
716 break;
717 }
718 encoder_opened = 1;
719
720 do
721 {
722 receive_rc = encoder_receive2(&ctx, enc_ctx, &enc_in_frame, out_packet,
723 output_width, output_height, output_total, output_fp);
724 }
725 while (receive_rc == NI_TEST_RETCODE_EAGAIN);
726
727 if (receive_rc == NI_TEST_RETCODE_SUCCESS)
728 {
729 ni_log(NI_LOG_INFO, "Got encoded sequence header packet\n");
730 }
731 else
732 {
733 ni_log(NI_LOG_ERROR, "Failed to get encoded sequence header packet, retcode %d\n", receive_rc);
734 ret = receive_rc;
735 break;
736 }
737 }
738 }
739
740 //encode_send
741 for (i = 0; i < output_total; i++)
742 {
743 ctx.curr_enc_index = i;
744 // YUV Sending
745 send_rc = encoder_send_data2(&ctx, &enc_ctx[i], frame_to_enc[i], &enc_in_frame, output_width[i], output_height[i]);
746
747 if (send_rc < 0) //Error
748 {
749 if (dec_ctx.hw_action)
750 {
751 p_hwframe = (niFrameSurface1_t *)frame_to_enc[i]->data.frame.p_data[3];
752 ni_hw_frame_ref(p_hwframe);
753 } else
754 {
755 ni_decoder_frame_buffer_free(&frame_to_enc[i]->data.frame);
756 }
757 break;
758 } else if (send_rc == NI_TEST_RETCODE_EAGAIN)
759 {
760 // need to resend
761 i--;
762 continue;
763 } else if (dec_ctx.hw_action && !ctx.enc_eos_sent[i])
764 {
765 p_hwframe = (niFrameSurface1_t *)frame_to_enc[i]->data.frame.p_data[3];
766 ni_hw_frame_ref(p_hwframe);
767 }
768
769 // encoder send handling
770 if (dec_ctx.hw_action)
771 {
772 ni_frame_wipe_aux_data(&frame_to_enc[i]->data.frame);
773 } else
774 {
775 ni_decoder_frame_buffer_free(&frame_to_enc[i]->data.frame);
776 }
777 }
778
779 if (send_rc < 0)
780 {
781 break;
782 }
783
784encode_recv:
785 receive_rc = encoder_receive2(&ctx, enc_ctx, &enc_in_frame, out_packet,
786 output_width, output_height, output_total, output_fp);
787
788 for (i = 0; receive_rc >= 0 && i < output_total; i++)
789 {
790 if (!ctx.enc_eos_received[i])
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 ni_log(NI_LOG_INFO, "Decoder stats: received %u frames, fps %.2f, total bytes %u\n",
806 (float)ctx.num_frames_received / (float)(current_time - ctx.start_time) * (float)1000000000,
808 for (i = 0; i < output_total; i++)
809 {
810 ni_log(NI_LOG_INFO, "Encoder %d stats: received %u packets, fps %.2f, total bytes %u\n",
811 i, ctx.num_packets_received[i],
812 (float)enc_ctx[i].frame_num / (float)(current_time - ctx.start_time) * (float)1000000000,
814 }
816 }
817 }
818
819 decoder_stat_report_and_close(&ctx, &dec_ctx);
820 encoder_stat_report_and_close(&ctx, enc_ctx, output_total);
821
822end:
824 if (dec_ctx.hw_action == NI_CODEC_HW_ENABLE)
825 {
826 ni_frame_buffer_free(&out_frame.data.frame);
827 } else
828 {
830 }
831 for (i = 0; i < output_total; i++)
832 {
833 ni_frame_buffer_free(&filter_out_frame[i].data.frame);
834 }
835
836 ni_frame_buffer_free(&enc_in_frame.data.frame);
837 for (i = 0; i < output_total; i++)
838 {
839 ni_packet_buffer_free(&out_packet[i].data.packet);
840 }
841
843 for (i = 0; i < output_total; i++)
844 {
846 if (output_fp[i] != NULL)
847 {
848 fclose(output_fp[i]);
849 }
850 if (scale_params[i].enabled)
851 {
853 }
854 }
855 if (drawbox_params.enabled)
856 {
861 }
862
863 free(ctx.file_cache);
864
865 for(i = 0; i < MAX_OUTPUT_FILES; ++i)
866 {
867 free(ctx.enc_pts_queue[i]);
868 ctx.enc_pts_queue[i] = NULL;
869 }
870
871 free(p_dec_api_param);
872 free(p_enc_api_param);
873
874 return ret;
875}
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)
int decoder_receive_data(ni_demo_context_t *p_ctx, ni_session_context_t *p_dec_ctx, ni_session_data_io_t *p_out_data, int output_video_width, int output_video_height, FILE *p_file, int write_to_file, int *p_rx_size)
Receive decoded output data from decoder.
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)
int probe_vp9_stream_info(ni_demo_context_t *p_ctx, ni_vp9_header_info_t *vp9_info)
int decoder_send_data(ni_demo_context_t *p_ctx, ni_session_context_t *p_dec_ctx, ni_session_data_io_t *p_in_data, int input_video_width, int input_video_height, void *stream_info)
Send decoder input data.
#define NI_XCODER_REVISION
Definition ni_defs.h:98
void ni_frame_wipe_aux_data(ni_frame_t *frame)
Free and remove all auxiliary data from the frame.
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...
ni_retcode_t ni_packet_buffer_free(ni_packet_t *p_packet)
Free packet buffer that was previously allocated with ni_packet_buffer_alloc.
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_session_context_clear(ni_session_context_t *p_ctx)
Clear already allocated session context.
ni_retcode_t ni_decoder_frame_buffer_free(ni_frame_t *p_frame)
Free decoder frame buffer that was previously allocated with ni_decoder_frame_buffer_alloc,...
#define GC620_I420
@ 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_open2(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)
int encoder_receive2(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)
int encoder_send_data2(ni_demo_context_t *p_ctx, ni_session_context_t *p_enc_ctx, ni_session_data_io_t *p_dec_out_data, ni_session_data_io_t *p_enc_in_data, int input_video_width, int input_video_height)
void encoder_stat_report_and_close(ni_demo_context_t *p_ctx, ni_session_context_t *p_enc_ctx_list, int output_total)
int scale_filter(ni_session_context_t *p_ctx, ni_frame_t *p_frame_in, ni_session_data_io_t *p_data_out, int iXcoderGUID, int scale_width, int scale_height, int in_format, int out_format)
Do a scale and/or format-change operation.
int retrieve_filter_params(char filter_params[], ni_scale_params_t *scale_params, ni_drawbox_params_t *drawbox_params)
int drawbox_filter(ni_session_context_t *p_crop_ctx, ni_session_context_t *p_pad_ctx, ni_session_context_t *p_overlay_ctx, ni_session_context_t *p_fmt_ctx, ni_frame_t *p_frame_in, ni_session_data_io_t *p_data_out, ni_drawbox_params_t *p_box_params, int iXcoderGUID, int input_format, int output_format)
Use crop->pad->overlay to simulate a drawbox filter.
ni_pix_fmt_t gc620_to_ni_pix_fmt(int pix_fmt)
void ni_hw_frame_unref(uint16_t hwframe_index)
int ni_to_gc620_pix_fmt(ni_pix_fmt_t pix_fmt)
int read_and_cache_file(ni_demo_context_t *ctx, char *filename)
void print_version(void)
void ni_hw_frame_ref(const niFrameSurface1_t *p_surface)
#define MAX_OUTPUT_FILES
#define NI_TEST_RETCODE_SUCCESS
#define NI_TEST_RETCODE_EAGAIN
#define NI_TEST_RETCODE_END_OF_STREAM
#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
struct timeval current_time
struct timeval previous_time
ni_retcode_t ni_fopen(FILE **fp, const char *filename, const char *mode)
Definition ni_util.c:983
ni_retcode_t ni_strcpy(char *dest, size_t dmax, const char *src)
Definition ni_util.c:453
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:4560
uint64_t ni_gettime_ns(void)
Definition ni_util.c:2622
Utility definitions.
uint64_t dec_total_bytes_received
uint64_t num_packets_received[MAX_OUTPUT_FILES]
ni_pts_queue * enc_pts_queue[MAX_OUTPUT_FILES]
int enc_eos_received[MAX_OUTPUT_FILES]
int enc_eos_sent[MAX_OUTPUT_FILES]
uint64_t enc_total_bytes_received[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
union _ni_session_data_io::@19 data
struct _ni_vp9_header_info::@3 timebase