libxcoder 5.9.0
Loading...
Searching...
No Matches
ni_encode_utils.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 encode_utils.c
24 *
25 * \brief Video encoding utility functions shared by Libxcoder API examples
26 ******************************************************************************/
27
28#include "ni_generic_utils.h"
29#include "ni_encode_utils.h"
30#include "ni_log.h"
31#include "ni_av_codec.h"
32#include "ni_util.h"
33
34/*!*****************************************************************************
35 * \brief Set up hard coded demo ROI map
36 *
37 * \param
38 *
39 * \return none
40 ******************************************************************************/
42{
43 ni_xcoder_params_t *p_param =
45 uint32_t i, j, sumQp = 0;
46 uint32_t mbWidth, mbHeight, numMbs;
47 // mode 1: Set QP for center 1/3 of picture to highest - lowest quality
48 // the rest to lowest - highest quality;
49 // mode non-1: reverse of mode 1
50 int importanceLevelCentre = p_param->roi_demo_mode == 1 ? 40 : 10;
51 int importanceLevelRest = p_param->roi_demo_mode == 1 ? 10 : 40;
52 int32_t width, height;
53
54 if (!p_enc_ctx->roi_map)
55 {
56 p_enc_ctx->roi_map =
57 (ni_enc_quad_roi_custom_map *)calloc(1, p_enc_ctx->roi_len);
58 }
59 if (!p_enc_ctx->roi_map)
60 {
61 return;
62 }
63 uint32_t roiMapBlockUnitSize = 64; // HEVC
64 uint32_t max_cu_size = 64; // HEVC
65 if (NI_CODEC_FORMAT_H264 == p_enc_ctx->codec_format)
66 {
67 max_cu_size = 16;
68 roiMapBlockUnitSize = 16;
69 }
70
71 width = p_param->source_width;
72 height = p_param->source_height;
73 // AV1 non-8x8-aligned resolution is implicitly cropped due to Quadra HW limitation
74 if (NI_CODEC_FORMAT_AV1 == p_enc_ctx->codec_format)
75 {
76 width = (width / 8) * 8;
77 height = (height / 8) * 8;
78 }
79
80 mbWidth =
81 ((width + max_cu_size - 1) & (~(max_cu_size - 1))) /
82 roiMapBlockUnitSize;
83 mbHeight =
84 ((height + max_cu_size - 1) & (~(max_cu_size - 1))) /
85 roiMapBlockUnitSize;
86 numMbs = mbWidth * mbHeight;
87
88 // copy roi MBs QPs into custom map
89 bool bIsCenter;
90 // number of qp info (8x8) per mb or ctb
91 uint32_t entryPerMb = (roiMapBlockUnitSize / 8) * (roiMapBlockUnitSize / 8);
92
93 for (i = 0; i < numMbs; i++)
94 {
95 if ((i % mbWidth > mbWidth / 3) && (i % mbWidth < mbWidth * 2 / 3))
96 bIsCenter = 1;
97 else
98 bIsCenter = 0;
99
100 for (j = 0; j < entryPerMb; j++)
101 {
102 /*
103 g_quad_roi_map[i*4+j].field.skip_flag = 0; // don't force
104 skip mode g_quad_roi_map[i*4+j].field.roiAbsQp_flag = 1; //
105 absolute QP g_quad_roi_map[i*4+j].field.qp_info = bIsCenter
106 ? importanceLevelCentre : importanceLevelRest;
107 */
108 p_enc_ctx->roi_map[i * entryPerMb + j].field.ipcm_flag =
109 0; // don't force skip mode
110 p_enc_ctx->roi_map[i * entryPerMb + j].field.roiAbsQp_flag =
111 1; // absolute QP
112 p_enc_ctx->roi_map[i * entryPerMb + j].field.qp_info =
113 bIsCenter ? importanceLevelCentre : importanceLevelRest;
114 }
115 sumQp += p_enc_ctx->roi_map[i * entryPerMb].field.qp_info;
116 }
117 p_enc_ctx->roi_avg_qp =
118 // NOLINTNEXTLINE(clang-analyzer-core.DivideZero)
119 (sumQp + (numMbs >> 1)) / numMbs; // round off
120}
121
122// convert various reconfig and demo modes (stored in encoder configuration) to
123// aux data and store them in frame
125{
126 ni_xcoder_params_t *api_param =
128 ni_aux_data_t *aux_data = NULL;
129
130 switch (api_param->reconf_demo_mode)
131 {
133 if (p_enc_ctx->frame_num ==
134 api_param->reconf_hash[p_ctx->reconfig_count][0])
135 {
136 aux_data = ni_frame_new_aux_data(
137 frame, NI_FRAME_AUX_DATA_BITRATE, sizeof(int32_t));
138 if (!aux_data)
139 {
141 "Error %s(): no mem for reconf BR aux_data\n",
142 __func__);
143 return;
144 }
145 *((int32_t *)aux_data->data) =
146 api_param->reconf_hash[p_ctx->reconfig_count][1];
147 ni_log(NI_LOG_DEBUG, "%s(): frame #%lu reconfig BR %d by frame aux data\n",
148 __func__, p_enc_ctx->frame_num,
149 api_param->reconf_hash[p_ctx->reconfig_count][1]);
150
151 p_ctx->reconfig_count++;
152 }
153 break;
155 if (p_enc_ctx->frame_num ==
156 api_param->reconf_hash[p_ctx->reconfig_count][0])
157 {
158 aux_data = ni_frame_new_aux_data(
159 frame, NI_FRAME_AUX_DATA_INTRAPRD, sizeof(int32_t));
160 if (!aux_data)
161 {
162 return;
163 }
164 int32_t intraprd = *((int32_t *)aux_data->data) =
165 api_param->reconf_hash[p_ctx->reconfig_count][1];
167 "xcoder_send_frame: frame #%lu reconf "
168 "intraPeriod %d\n",
169 p_enc_ctx->frame_num,
170 intraprd);
171 p_ctx->reconfig_count++;
172 }
173 break;
175 if (p_enc_ctx->frame_num ==
176 api_param->reconf_hash[p_ctx->reconfig_count][0])
177 {
178 p_enc_ctx->enc_change_params->enable_option |=
181 api_param->reconf_hash[p_ctx->reconfig_count][1];
183 api_param->reconf_hash[p_ctx->reconfig_count][2];
184 p_enc_ctx->enc_change_params->colorTrc =
185 api_param->reconf_hash[p_ctx->reconfig_count][3];
186 p_enc_ctx->enc_change_params->colorSpace =
187 api_param->reconf_hash[p_ctx->reconfig_count][4];
189 api_param->reconf_hash[p_ctx->reconfig_count][5];
191 api_param->reconf_hash[p_ctx->reconfig_count][6];
193 api_param->reconf_hash[p_ctx->reconfig_count][7];
194
195 // frame reconf_len needs to be set here
196 frame->reconf_len = sizeof(ni_encoder_change_params_t);
197 p_ctx->reconfig_count++;
198 }
199 break;
201 // the reconf file data line format for this is:
202 // <frame-number>:useCurSrcAsLongtermPic,useLongtermRef where
203 // values will stay the same on every frame until changed.
204 if (p_enc_ctx->frame_num ==
205 api_param->reconf_hash[p_ctx->reconfig_count][0])
206 {
207 aux_data = ni_frame_new_aux_data(
209 sizeof(ni_long_term_ref_t));
210 if (!aux_data)
211 {
213 "Error %s(): no mem for reconf LTR aux_data\n",
214 __func__);
215 return;
216 }
217 ni_long_term_ref_t *ltr = (ni_long_term_ref_t *)aux_data->data;
219 (uint8_t)api_param->reconf_hash[p_ctx->reconfig_count][1];
220 ltr->use_long_term_ref =
221 (uint8_t)api_param->reconf_hash[p_ctx->reconfig_count][2];
222
224 "%s(): frame #%lu reconf LTR "
225 "use_cur_src_as_long_term_pic %u use_long_term_ref "
226 "%u\n",
227 __func__, p_enc_ctx->frame_num,
229
230 p_ctx->reconfig_count++;
231 }
232 break;
235 if (p_enc_ctx->frame_num ==
236 api_param->reconf_hash[p_ctx->reconfig_count][0])
237 {
238 aux_data = ni_frame_new_aux_data(
240 if (!aux_data) {
242 "Error %s(): no mem for reconf max&min QP aux_data\n",
243 __func__);
244 return;
245 }
246 ni_rc_min_max_qp *qp_info = (ni_rc_min_max_qp *)aux_data->data;
247 qp_info->minQpI = api_param->reconf_hash[p_ctx->reconfig_count][1];
248 qp_info->maxQpI = api_param->reconf_hash[p_ctx->reconfig_count][2];
249 qp_info->maxDeltaQp = api_param->reconf_hash[p_ctx->reconfig_count][3];
250 qp_info->minQpPB = api_param->reconf_hash[p_ctx->reconfig_count][4];
251 qp_info->maxQpPB = api_param->reconf_hash[p_ctx->reconfig_count][5];
252
253 p_ctx->reconfig_count++;
254 }
255 break;
257 if (p_enc_ctx->frame_num ==
258 api_param->reconf_hash[p_ctx->reconfig_count][0])
259 {
260 aux_data = ni_frame_new_aux_data(
261 frame, NI_FRAME_AUX_DATA_LTR_INTERVAL, sizeof(int32_t));
262 if (!aux_data)
263 {
264 ni_log(NI_LOG_ERROR, "Error %s(): no mem for reconf LTR interval "
265 "aux_data\n",
266 __func__);
267 return;
268 }
269 *((int32_t *)aux_data->data) =
270 api_param->reconf_hash[p_ctx->reconfig_count][1];
271 ni_log(NI_LOG_DEBUG, "%s(): frame #%lu reconf LTR interval %d\n",
272 __func__, p_enc_ctx->frame_num,
273 *((int32_t *)aux_data->data));
274
275 p_ctx->reconfig_count++;
276 }
277 break;
279 if (p_enc_ctx->frame_num ==
280 api_param->reconf_hash[p_ctx->reconfig_count][0])
281 {
282 aux_data = ni_frame_new_aux_data(
284 sizeof(int32_t));
285 if (!aux_data)
286 {
287 ni_log(NI_LOG_ERROR, "Error %s(): no mem for reconf invalid ref "
288 "frame aux_data\n",
289 __func__);
290 return;
291 }
292 *((int32_t *)aux_data->data) =
293 api_param->reconf_hash[p_ctx->reconfig_count][1];
294 ni_log(NI_LOG_DEBUG, "%s(): frame #%lu reconf invalid ref frame %d\n",
295 __func__, p_enc_ctx->frame_num,
296 *((int32_t *)aux_data->data));
297
298 p_ctx->reconfig_count++;
299 }
300 break;
302 if (p_enc_ctx->frame_num ==
303 api_param->reconf_hash[p_ctx->reconfig_count][0])
304 {
305 aux_data = ni_frame_new_aux_data(
307 if (!aux_data)
308 {
310 "Error %s(): no mem for reconf framerate aux_data\n",
311 __func__);
312 return;
313 }
314 ni_framerate_t *framerate = (ni_framerate_t *)aux_data->data;
315 framerate->framerate_num =
316 (int32_t)api_param->reconf_hash[p_ctx->reconfig_count][1];
317 framerate->framerate_denom =
318 (int32_t)api_param->reconf_hash[p_ctx->reconfig_count][2];
319
321 "%s(): frame #%lu reconfig framerate (%d/%d) by frame aux data\n",
322 __func__, p_enc_ctx->frame_num, framerate->framerate_num,
323 framerate->framerate_denom);
324
325 p_ctx->reconfig_count++;
326 }
327 break;
329 if (p_enc_ctx->frame_num ==
330 api_param->reconf_hash[p_ctx->reconfig_count][0])
331 {
332 aux_data = ni_frame_new_aux_data(
333 frame, NI_FRAME_AUX_DATA_MAX_FRAME_SIZE, sizeof(int32_t));
334 if (!aux_data)
335 {
337 "Error %s(): no mem for reconf maxFrameSize aux_data\n",
338 __func__);
339 return;
340 }
341 *((int32_t *)aux_data->data) =
342 api_param->reconf_hash[p_ctx->reconfig_count][1];
343 ni_log(NI_LOG_DEBUG, "%s(): frame #%lu reconfig maxFrameSize %d by frame aux data\n",
344 __func__, p_enc_ctx->frame_num,
345 api_param->reconf_hash[p_ctx->reconfig_count][1]);
346
347 p_ctx->reconfig_count++;
348 }
349 break;
351 if (p_enc_ctx->frame_num ==
352 api_param->reconf_hash[p_ctx->reconfig_count][0])
353 {
354 aux_data = ni_frame_new_aux_data(
355 frame, NI_FRAME_AUX_DATA_CRF, sizeof(int32_t));
356 if (!aux_data) {
358 "Error %s(): no mem for reconf crf aux_data\n",
359 __func__);
360 return;
361 }
362 *((int32_t *)aux_data->data) =
363 api_param->reconf_hash[p_ctx->reconfig_count][1];
364 ni_log(NI_LOG_DEBUG, "%s(): frame #%lu reconfig crf %d by frame aux data\n",
365 __func__, p_enc_ctx->frame_num,
366 api_param->reconf_hash[p_ctx->reconfig_count][1]);
367
368 p_ctx->reconfig_count++;
369 }
370 break;
372 if (p_enc_ctx->frame_num ==
373 api_param->reconf_hash[p_ctx->reconfig_count][0])
374 {
375 aux_data = ni_frame_new_aux_data(
376 frame, NI_FRAME_AUX_DATA_CRF_FLOAT, sizeof(float));
377 if (!aux_data) {
379 "Error %s(): no mem for reconf crf aux_data\n",
380 __func__);
381 return;
382 }
383 float crf = (float)(api_param->reconf_hash[p_ctx->reconfig_count][1] +
384 (float)api_param->reconf_hash[p_ctx->reconfig_count][2] / 100.0);
385 *((float *)aux_data->data) = crf;
387 "%s(): frame #%lu reconfig float type crf %f by frame "
388 "aux data\n", __func__, p_enc_ctx->frame_num, crf);
389 p_ctx->reconfig_count++;
390 }
391 break;
392
394 if (p_enc_ctx->frame_num ==
395 api_param->reconf_hash[p_ctx->reconfig_count][0])
396 {
397 aux_data = ni_frame_new_aux_data(
398 frame, NI_FRAME_AUX_DATA_VBV_MAX_RATE, sizeof(int32_t));
399 if (!aux_data) {
401 "Error %s(): no mem for reconf vbfMaxRate aux_data\n",
402 __func__);
403 return;
404 }
405 *((int32_t *)aux_data->data) =
406 api_param->reconf_hash[p_ctx->reconfig_count][1];
407 aux_data = ni_frame_new_aux_data(
408 frame, NI_FRAME_AUX_DATA_VBV_BUFFER_SIZE, sizeof(int32_t));
409 if (!aux_data) {
411 "Error %s(): no mem for reconf vbvBufferSize aux_data\n",
412 __func__);
413 return;
414 }
415 *((int32_t *)aux_data->data) =
416 api_param->reconf_hash[p_ctx->reconfig_count][2];
418 "%s(): frame #%lu reconfig vbfMaxRate %d vbvBufferSize "
419 "%d by frame aux data\n",
420 __func__, p_enc_ctx->frame_num,
421 api_param->reconf_hash[p_ctx->reconfig_count][1],
422 api_param->reconf_hash[p_ctx->reconfig_count][2]);
423
424 p_ctx->reconfig_count++;
425 }
426 break;
428 if (p_enc_ctx->frame_num ==
429 api_param->reconf_hash[p_ctx->reconfig_count][0]) {
430 int maxFrameSizeRatio = api_param->reconf_hash[p_ctx->reconfig_count][1];
431 if (maxFrameSizeRatio < 1) {
432 ni_log(NI_LOG_ERROR, "maxFrameSizeRatio %d cannot < 1\n",
433 maxFrameSizeRatio);
434 return;
435 }
436 aux_data = ni_frame_new_aux_data(
437 frame, NI_FRAME_AUX_DATA_MAX_FRAME_SIZE, sizeof(int32_t));
438 if (!aux_data) {
440 "Error %s(): no mem for reconf maxFrameSizeRatio aux_data\n",
441 __func__);
442 return;
443 }
444
445 int32_t bitrate, framerate_num, framerate_denom;
446 uint32_t min_maxFrameSize, maxFrameSize;
447 bitrate = (p_enc_ctx->target_bitrate > 0) ? p_enc_ctx->target_bitrate : api_param->bitrate;
448
449 if ((p_enc_ctx->framerate.framerate_num > 0) && (p_enc_ctx->framerate.framerate_denom > 0))
450 {
451 framerate_num = p_enc_ctx->framerate.framerate_num;
452 framerate_denom = p_enc_ctx->framerate.framerate_denom;
453 }
454 else
455 {
456 framerate_num = (int32_t) api_param->fps_number;
457 framerate_denom = (int32_t) api_param->fps_denominator;
458 }
459
460 min_maxFrameSize = ((uint32_t)bitrate / framerate_num * framerate_denom) / 8;
461 maxFrameSize = min_maxFrameSize * maxFrameSizeRatio > NI_MAX_FRAME_SIZE ?
462 NI_MAX_FRAME_SIZE : min_maxFrameSize * maxFrameSizeRatio;
463 *((int32_t *)aux_data->data) = maxFrameSize;
465 "xcoder_send_frame: frame #%lu reconf "
466 "maxFrameSizeRatio %d maxFrameSize %d\n",
467 p_enc_ctx->frame_num, maxFrameSizeRatio, maxFrameSize);
468
469 p_ctx->reconfig_count++;
470 }
471 break;
473 if (p_enc_ctx->frame_num ==
474 api_param->reconf_hash[p_ctx->reconfig_count][0]) {
475 aux_data = ni_frame_new_aux_data(
476 frame, NI_FRAME_AUX_DATA_SLICE_ARG, sizeof(int16_t));
477 if (!aux_data) {
479 "Error %s(): no mem for reconf sliceArg aux_data\n",
480 __func__);
481 return;
482 }
483 *((int16_t *)aux_data->data) =
484 api_param->reconf_hash[p_ctx->reconfig_count][1];
485 ni_log2(p_enc_ctx, NI_LOG_TRACE,
486 "xcoder_send_frame: frame #%lu reconf "
487 "sliceArg %d\n",
488 p_enc_ctx->frame_num,
489 api_param->reconf_hash[p_ctx->reconfig_count][1]);
490
491 p_ctx->reconfig_count++;
492 }
493 break;
494
495 // set LTR and/or invalidate reference frames on the same frame.
496 // reconf file line format:
497 // <frame-number>:useCurSrcAsLongtermPic,invalidFrameNum
498 // invalidFrameNum -1 skips reference invalidation.
499 // useLongtermRef is not sent; firmware ignores that flag.
501 if (p_enc_ctx->frame_num ==
502 api_param->reconf_hash[p_ctx->reconfig_count][0])
503 {
504 uint8_t use_cur_src_as_long_term_pic =
505 (uint8_t)api_param->reconf_hash[p_ctx->reconfig_count][1];
506 int32_t invalid_frame_num =
507 api_param->reconf_hash[p_ctx->reconfig_count][2];
508
509 if (use_cur_src_as_long_term_pic > 0)
510 {
511 aux_data = ni_frame_new_aux_data(
513 sizeof(ni_long_term_ref_t));
514 if (!aux_data)
515 {
517 "Error %s(): no mem for reconf LTR aux_data\n",
518 __func__);
519 return;
520 }
521 ni_long_term_ref_t *ltr =
522 (ni_long_term_ref_t *)aux_data->data;
524 use_cur_src_as_long_term_pic;
525 ltr->use_long_term_ref = 0;
527 "%s(): frame #%lu reconf LTR "
528 "use_cur_src_as_long_term_pic %u\n",
529 __func__, p_enc_ctx->frame_num,
531 }
532
533 if (invalid_frame_num != -1)
534 {
535 aux_data = ni_frame_new_aux_data(
537 sizeof(int32_t));
538 if (!aux_data)
539 {
541 "Error %s(): no mem for reconf invalid ref "
542 "frame aux_data\n",
543 __func__);
544 return;
545 }
546 *((int32_t *)aux_data->data) = invalid_frame_num;
548 "%s(): frame #%lu reconf invalid ref frame %d\n",
549 __func__, p_enc_ctx->frame_num, invalid_frame_num);
550 }
551
552 p_ctx->reconfig_count++;
553 }
554 break;
555
557 if (p_enc_ctx->frame_num ==
558 api_param->reconf_hash[p_ctx->reconfig_count][0])
559 {
560 ni_force_idr_frame_type(p_enc_ctx);
561 ni_log(NI_LOG_DEBUG, "%s(): frame #%lu force IDR frame\n", __func__,
562 p_enc_ctx->frame_num);
563 p_ctx->reconfig_count++;
564 }
565 break;
567 if (p_enc_ctx->frame_num ==
568 api_param->reconf_hash[p_ctx->reconfig_count][0])
569 {
570 ni_reconfig_bitrate(p_enc_ctx,
571 api_param->reconf_hash[p_ctx->reconfig_count][1]);
572 ni_log(NI_LOG_DEBUG, "%s(): frame #%lu API reconfig BR %d\n",
573 __func__, p_enc_ctx->frame_num,
574 api_param->reconf_hash[p_ctx->reconfig_count][1]);
575 p_ctx->reconfig_count++;
576 }
577 break;
579 if (p_enc_ctx->frame_num ==
580 api_param->reconf_hash[p_ctx->reconfig_count][0]) {
581 int32_t intraprd =
582 api_param->reconf_hash[p_ctx->reconfig_count][1];
583 ni_reconfig_intraprd(p_enc_ctx, intraprd);
585 "xcoder_send_frame: frame #%lu API reconfig intraPeriod %d\n",
586 p_enc_ctx->frame_num,
587 intraprd);
588
589 p_ctx->reconfig_count++;
590 }
591 break;
593 if (p_enc_ctx->frame_num ==
594 api_param->reconf_hash[p_ctx->reconfig_count][0])
595 {
596 ni_vui_hrd_t vui;
597 vui.colorDescPresent =
598 (uint8_t)api_param->reconf_hash[p_ctx->reconfig_count][1];
599 vui.colorPrimaries =
600 (uint8_t)api_param->reconf_hash[p_ctx->reconfig_count][2];
601 vui.colorTrc =
602 (uint8_t)api_param->reconf_hash[p_ctx->reconfig_count][3];
603 vui.colorSpace =
604 (uint8_t)api_param->reconf_hash[p_ctx->reconfig_count][4];
605 vui.aspectRatioWidth =
606 (uint16_t)api_param->reconf_hash[p_ctx->reconfig_count][5];
608 (uint16_t)api_param->reconf_hash[p_ctx->reconfig_count][6];
609 vui.videoFullRange =
610 (uint8_t)api_param->reconf_hash[p_ctx->reconfig_count][7];
611
612 ni_reconfig_vui(p_enc_ctx, &vui);
613 ni_log(NI_LOG_DEBUG, "%s(): frame #%lu API reconfig VUI HRD "
614 "colorDescPresent %d colorPrimaries %d "
615 "colorTrc %d colorSpace %d aspectRatioWidth %d "
616 "aspectRatioHeight %d videoFullRange %d\n",
617 __func__, p_enc_ctx->frame_num,
618 api_param->reconf_hash[p_ctx->reconfig_count][1],
619 api_param->reconf_hash[p_ctx->reconfig_count][2],
620 api_param->reconf_hash[p_ctx->reconfig_count][3],
621 api_param->reconf_hash[p_ctx->reconfig_count][4],
622 api_param->reconf_hash[p_ctx->reconfig_count][5],
623 api_param->reconf_hash[p_ctx->reconfig_count][6],
624 api_param->reconf_hash[p_ctx->reconfig_count][7]);
625 p_ctx->reconfig_count++;
626 }
627 break;
629 if (p_enc_ctx->frame_num ==
630 api_param->reconf_hash[p_ctx->reconfig_count][0])
631 {
634 (uint8_t)api_param->reconf_hash[p_ctx->reconfig_count][1];
636 (uint8_t)api_param->reconf_hash[p_ctx->reconfig_count][2];
637
638 ni_set_ltr(p_enc_ctx, &ltr);
639 ni_log(NI_LOG_DEBUG, "%s(): frame #%lu API set LTR\n", __func__,
640 p_enc_ctx->frame_num);
641 p_ctx->reconfig_count++;
642 }
643 break;
646 if (p_enc_ctx->frame_num ==
647 api_param->reconf_hash[p_ctx->reconfig_count][0])
648 {
649 ni_rc_min_max_qp qp_info;
650 qp_info.minQpI = (int32_t)api_param->reconf_hash[p_ctx->reconfig_count][1];
651 qp_info.maxQpI = (int32_t)api_param->reconf_hash[p_ctx->reconfig_count][2];
652 qp_info.maxDeltaQp = (int32_t)api_param->reconf_hash[p_ctx->reconfig_count][3];
653 qp_info.minQpPB = (int32_t)api_param->reconf_hash[p_ctx->reconfig_count][4];
654 qp_info.maxQpPB = (int32_t)api_param->reconf_hash[p_ctx->reconfig_count][5];
655 ni_reconfig_min_max_qp(p_enc_ctx, &qp_info);
657 "%s(): frame %llu minQpI %d maxQpI %d maxDeltaQp %d minQpPB %d maxQpPB %d\n",
658 __func__, p_enc_ctx->frame_num,
659 qp_info.minQpI, qp_info.maxQpI, qp_info.maxDeltaQp, qp_info.minQpPB, qp_info.maxQpPB);
660 p_ctx->reconfig_count++;
661 }
662 break;
664 if (p_enc_ctx->frame_num ==
665 api_param->reconf_hash[p_ctx->reconfig_count][0])
666 {
667 ni_set_ltr_interval(p_enc_ctx,
668 api_param->reconf_hash[p_ctx->reconfig_count][1]);
669 ni_log(NI_LOG_DEBUG, "%s(): frame #%lu API set LTR interval %d\n",
670 __func__, p_enc_ctx->frame_num,
671 api_param->reconf_hash[p_ctx->reconfig_count][1]);
672 p_ctx->reconfig_count++;
673 }
674 break;
676 if (p_enc_ctx->frame_num ==
677 api_param->reconf_hash[p_ctx->reconfig_count][0])
678 {
680 p_enc_ctx, api_param->reconf_hash[p_ctx->reconfig_count][1]);
681 ni_log(NI_LOG_DEBUG, "%s(): frame #%lu API set frame ref invalid "
682 "%d\n",
683 __func__, p_enc_ctx->frame_num,
684 api_param->reconf_hash[p_ctx->reconfig_count][1]);
685 p_ctx->reconfig_count++;
686 }
687 break;
689 if (p_enc_ctx->frame_num ==
690 api_param->reconf_hash[p_ctx->reconfig_count][0])
691 {
692 ni_framerate_t framerate;
693 framerate.framerate_num =
694 (int32_t)api_param->reconf_hash[p_ctx->reconfig_count][1];
695 framerate.framerate_denom =
696 (int32_t)api_param->reconf_hash[p_ctx->reconfig_count][2];
697 ni_reconfig_framerate(p_enc_ctx, &framerate);
699 "%s(): frame #%lu API reconfig framerate (%d/%d)\n",
700 __func__, p_enc_ctx->frame_num,
701 api_param->reconf_hash[p_ctx->reconfig_count][1],
702 api_param->reconf_hash[p_ctx->reconfig_count][2]);
703 p_ctx->reconfig_count++;
704 }
705 break;
707 if (p_enc_ctx->frame_num ==
708 api_param->reconf_hash[p_ctx->reconfig_count][0])
709 {
711 api_param->reconf_hash[p_ctx->reconfig_count][1]);
712 ni_log(NI_LOG_DEBUG, "%s(): frame #%lu API reconfig maxFrameSize %d\n",
713 __func__, p_enc_ctx->frame_num,
714 api_param->reconf_hash[p_ctx->reconfig_count][1]);
715 p_ctx->reconfig_count++;
716 }
717 break;
719 if (p_enc_ctx->frame_num ==
720 api_param->reconf_hash[p_ctx->reconfig_count][0])
721 {
722 ni_reconfig_crf(p_enc_ctx,
723 api_param->reconf_hash[p_ctx->reconfig_count][1]);
724 ni_log(NI_LOG_DEBUG, "%s(): frame #%lu API reconfig crf %d\n",
725 __func__, p_enc_ctx->frame_num,
726 api_param->reconf_hash[p_ctx->reconfig_count][1]);
727 p_ctx->reconfig_count++;
728 }
729 break;
731 if (p_enc_ctx->frame_num ==
732 api_param->reconf_hash[p_ctx->reconfig_count][0])
733 {
734 float crf = (float)(api_param->reconf_hash[p_ctx->reconfig_count][1] +
735 (float)api_param->reconf_hash[p_ctx->reconfig_count][2] / 100.0);
736 ni_reconfig_crf2(p_enc_ctx, crf);
737 ni_log(NI_LOG_DEBUG, "%s(): frame #%lu API reconfig crf %f\n",
738 __func__, p_enc_ctx->frame_num, crf);
739 p_ctx->reconfig_count++;
740 }
741 break;
743 if (p_enc_ctx->frame_num ==
744 api_param->reconf_hash[p_ctx->reconfig_count][0])
745 {
747 p_enc_ctx, api_param->reconf_hash[p_ctx->reconfig_count][1],
748 api_param->reconf_hash[p_ctx->reconfig_count][2]);
749 ni_log(NI_LOG_DEBUG, "%s(): frame #%lu API reconfig vbvMaxRate %d vbvBufferSize %d\n",
750 __func__, p_enc_ctx->frame_num,
751 api_param->reconf_hash[p_ctx->reconfig_count][1],
752 api_param->reconf_hash[p_ctx->reconfig_count][2]);
753 p_ctx->reconfig_count++;
754 }
755 break;
757 if (p_enc_ctx->frame_num ==
758 api_param->reconf_hash[p_ctx->reconfig_count][0])
759 {
761 p_enc_ctx, api_param->reconf_hash[p_ctx->reconfig_count][1]);
763 "xcoder_send_frame: frame #%lu reconf maxFrameSizeRatio %d\n",
764 p_enc_ctx->frame_num, api_param->reconf_hash[p_ctx->reconfig_count][1]);
765
766 p_ctx->reconfig_count++;
767 }
768 break;
770 if (p_enc_ctx->frame_num ==
771 api_param->reconf_hash[p_ctx->reconfig_count][0]) {
773 p_enc_ctx, api_param->reconf_hash[p_ctx->reconfig_count][1]);
775 "xcoder_send_frame: frame #%lu API reconfig sliceArg %d\n",
776 p_enc_ctx->frame_num,
777 api_param->reconf_hash[p_ctx->reconfig_count][1]);
778
779 p_ctx->reconfig_count++;
780 }
781 break;
783 if (p_enc_ctx->frame_num ==
784 api_param->reconf_hash[p_ctx->reconfig_count][0])
785 {
786 uint8_t use_cur_src_as_long_term_pic =
787 (uint8_t)api_param->reconf_hash[p_ctx->reconfig_count][1];
788 int32_t invalid_frame_num =
789 api_param->reconf_hash[p_ctx->reconfig_count][2];
790
791 if (use_cur_src_as_long_term_pic > 0)
792 {
795 use_cur_src_as_long_term_pic;
796 ltr.use_long_term_ref = 0;
797 ni_set_ltr(p_enc_ctx, &ltr);
799 "%s(): frame #%lu API set LTR "
800 "use_cur_src_as_long_term_pic %u\n",
801 __func__, p_enc_ctx->frame_num,
802 use_cur_src_as_long_term_pic);
803 }
804
805 if (invalid_frame_num != -1)
806 {
807 ni_set_frame_ref_invalid(p_enc_ctx, invalid_frame_num);
809 "%s(): frame #%lu API set frame ref invalid %d\n",
810 __func__, p_enc_ctx->frame_num, invalid_frame_num);
811 }
812
813 p_ctx->reconfig_count++;
814 }
815 break;
817 default:;
818 }
819}
820
821/*!*****************************************************************************
822 * \brief Send encoder input data, read from input file
823 *
824 * Note: For optimal performance, yuv_buf should be 4k aligned
825 *
826 * \param
827 *
828 * \return
829 ******************************************************************************/
831 ni_session_data_io_t *p_in_data, void *yuv_buf,
832 int input_video_width, int input_video_height,
833 int is_last_input)
834{
835 int oneSent;
836 ni_frame_t *p_in_frame = &p_in_data->data.frame;
837 uint8_t enc_id = p_ctx->curr_enc_index;
838
839 ni_log(NI_LOG_DEBUG, "===> encoder_send_data <===\n");
840
842 {
843 ni_log(NI_LOG_DEBUG, "encoder_send_data: Sequence Change - waiting "
844 "for previous session to end\n");
846 }
847
848 if (p_ctx->enc_eos_sent[enc_id] == 1)
849 {
850 ni_log(NI_LOG_DEBUG, "encoder_send_data: ALL data (incl. eos) sent "
851 "already!\n");
853 }
854
855 if (p_ctx->enc_resend[enc_id])
856 {
857 goto send_frame;
858 }
859
860 p_in_frame->start_of_stream = 0;
861 if (!p_ctx->enc_sos_sent[enc_id] ||
863 {
864 p_ctx->enc_sos_sent[enc_id] = 1;
865 p_in_frame->start_of_stream = 1;
866 }
867 p_in_frame->end_of_stream = 0;
868 p_in_frame->force_key_frame = 0;
869
870 p_in_frame->video_width = input_video_width;
871 p_in_frame->video_height = input_video_height;
872
873 // reset encoder change data buffer
874 memset(p_enc_ctx->enc_change_params, 0, sizeof(ni_encoder_change_params_t));
875
876 // reset various aux data size
877 p_in_frame->roi_len = 0;
878 p_in_frame->reconf_len = 0;
879 p_in_frame->sei_total_len = 0;
880 p_in_frame->pts = p_ctx->pts[enc_id];
881
882 // collect encode reconfig and demo info and save them as aux data in
883 // the input frame struct.
884 prep_reconf_demo_data(p_ctx, p_enc_ctx, p_in_frame);
885
886 if (yuv_buf == NULL)
887 {
888 if (is_last_input)
889 {
890 p_in_frame->end_of_stream = 1;
891 ni_log(NI_LOG_DEBUG, "encoder_send_data: read chunk size 0, eos!\n");
892 }
893 else
894 {
895 ni_log(NI_LOG_DEBUG, "encoder_send_data: exit to get next input\n");
897 }
898 }
899
900send_frame:
901 // simulate FFmpeg -re option, which controls process input rate to simualte real time environment
902 if (p_ctx->read_framerate > 0)
903 {
904 uint64_t abs_time_ns;
905 abs_time_ns = ni_gettime_ns();
906 if ((abs_time_ns - p_ctx->start_time) < (uint64_t)(1000000000LL / p_ctx->read_framerate * p_ctx->num_frames_sent[enc_id]))
907 {
908 if (!p_ctx->enc_resend[enc_id])
909 p_ctx->enc_resend[enc_id] = 2;
910 if (p_ctx->enc_resend[enc_id] == 2)
912 }
913 else
914 {
915 p_ctx->num_frames_sent[enc_id]++;
916 }
917 }
918
919 oneSent = ni_enc_write_from_yuv_buffer(p_enc_ctx, p_in_frame, yuv_buf);
920 if (oneSent < 0)
921 {
923 "Error: failed ni_device_session_write() for encoder\n");
924 p_ctx->enc_resend[enc_id] = 1;
926 } else if (oneSent == 0 && !p_enc_ctx->ready_to_close)
927 {
928 p_ctx->enc_resend[enc_id] = 1;
930 } else
931 {
932 p_ctx->enc_resend[enc_id] = 0;
933
934 p_ctx->enc_total_bytes_sent[enc_id] += p_in_frame->data_len[0] +
935 p_in_frame->data_len[1] + p_in_frame->data_len[2] + p_in_frame->data_len[3];
936 ni_log(NI_LOG_DEBUG, "encoder_send_data: total sent data size=%lu\n",
937 p_ctx->enc_total_bytes_sent[enc_id]);
938
939 ni_log(NI_LOG_DEBUG, "encoder_send_data: success\n");
940
941 if (p_enc_ctx->ready_to_close)
942 {
944 {
945 p_ctx->enc_eos_sent[enc_id] = 1;
946 }
947 }
948
950 {
953 "encoder_send_data: session_run_state change to %d\n",
954 p_enc_ctx->session_run_state);
955 }
956
957 ni_pts_enqueue(p_ctx->enc_pts_queue[enc_id], p_ctx->pts[enc_id]);
958 ++p_ctx->pts[enc_id];
959 }
960
961 ni_frame_wipe_aux_data(p_in_frame);
963}
964
965/*******************************************************************************
966 * @brief Send encoder input data, directly after receiving from decoder
967 *
968 * @param p_enc_ctx encoder context
969 * p_dec_ctx decoder context
970 * p_dec_out_data frame returned by decoder
971 * p_enc_in_data frame to be sent to encoder
972 *
973 * @return
974 ******************************************************************************/
976 ni_session_data_io_t *p_dec_out_data,
977 ni_session_data_io_t *p_enc_in_data,
978 int input_video_width, int input_video_height)
979{
980 int oneSent;
981 int data_len_to_send;
982 // frame pointer to data frame struct to be sent
983 ni_frame_t *p_in_frame = &(p_enc_in_data->data.frame);
984 ni_xcoder_params_t *api_params =
986 int is_semiplanar = get_pixel_planar(p_enc_ctx->pixel_format) == NI_PIXEL_PLANAR_FORMAT_SEMIPLANAR;
987 int is_hwframe = p_enc_ctx->hw_action != NI_CODEC_HW_NONE;
988 uint8_t enc_id = p_ctx->curr_enc_index;
989
990 ni_log(NI_LOG_DEBUG, "===> encoder_send_data2 <===\n");
991
992 if (p_ctx->enc_eos_sent[enc_id] == 1)
993 {
994 ni_log(NI_LOG_DEBUG, "encoder_send_data2: ALL data (incl. eos) sent "
995 "already!\n");
997 }
998
999 // don't send new data before flushing completed
1001 {
1003 }
1004
1005//#define ENCODER_FLUSH_INJECT
1006// Note that this demo only supports in multi threads transcoding mode
1007// For examples: sudo ./xcoder -c 0 -i input.h265 -m h2h -b 8 -o output.h265 -t
1008#ifdef ENCODER_FLUSH_INJECT
1009 if ((p_enc_ctx->frame_num > 0 && p_enc_ctx->frame_num % 30 == 0) &&
1010 !p_dec_out_data->data.frame.end_of_stream)
1011 {
1012 // send the encoder flush command
1014 {
1015 // need to change the state
1017 ni_log(NI_LOG_INFO, "encoder_send_data2 flush encoder successfully\n");
1019 }
1020 else
1021 {
1022 ni_log(NI_LOG_ERROR, "Error: encoder_send_data2 flush encoder\n");
1023 return -1;
1024 }
1025 }
1026#endif
1027
1028 // frame resend
1029 if (p_ctx->enc_resend[enc_id])
1030 {
1031 goto send_frame;
1032 }
1033
1034 // copy input frame to a new frame struct and prep for the aux data
1035 p_in_frame->end_of_stream = p_dec_out_data->data.frame.end_of_stream;
1036 p_in_frame->ni_pict_type = 0;
1037
1038 // reset encoder change data buffer
1039 memset(p_enc_ctx->enc_change_params, 0,
1041
1042 // extra data starts with metadata header, and reset various aux data
1043 // size
1045 p_in_frame->roi_len = 0;
1046 p_in_frame->reconf_len = 0;
1047 p_in_frame->sei_total_len = 0;
1048 p_in_frame->force_pic_qp = 0;
1049 p_in_frame->pts = p_ctx->pts[enc_id];
1050
1051 // collect encode reconfig and demo info and save them in the decode out
1052 // frame, to be used in the aux data prep and copy later
1053 prep_reconf_demo_data(p_ctx, p_enc_ctx, &(p_dec_out_data->data.frame));
1054
1055 int dst_stride[NI_MAX_NUM_DATA_POINTERS] = {0};
1056 int dst_height_aligned[NI_MAX_NUM_DATA_POINTERS] = {0};
1057 bool alignment_2pass_wa = (
1058 (api_params->cfg_enc_params.lookAheadDepth ||
1059 api_params->cfg_enc_params.crf >= 0 ||
1060 api_params->cfg_enc_params.crfFloat >= 0) &&
1061 (p_enc_ctx->codec_format == NI_CODEC_FORMAT_H265 ||
1062 p_enc_ctx->codec_format == NI_CODEC_FORMAT_AV1));
1063 ni_get_hw_yuv420p_dim(input_video_width, input_video_height,
1064 p_enc_ctx->bit_depth_factor, is_semiplanar,
1065 dst_stride, dst_height_aligned);
1066
1067 if (alignment_2pass_wa && !is_hwframe) {
1068 if (is_semiplanar) {
1069 // for 2-pass encode output mismatch WA, need to extend (and
1070 // pad) CbCr plane height, because 1st pass assume input 32
1071 // align
1072 dst_height_aligned[1] = (((dst_height_aligned[0] + 31) / 32) * 32) / 2;
1073 } else {
1074 // for 2-pass encode output mismatch WA, need to extend (and
1075 // pad) Cr plane height, because 1st pass assume input 32 align
1076 dst_height_aligned[2] = (((dst_height_aligned[0] + 31) / 32) * 32) / 2;
1077 }
1078 }
1079
1080 // ROI demo mode takes higher priority over aux data
1081 // Note: when ROI demo modes enabled, supply ROI map for the specified
1082 // range frames, and 0 map for others
1083 if (api_params->roi_demo_mode && api_params->cfg_enc_params.roi_enable)
1084 {
1085 if (p_enc_ctx->frame_num > 90 && p_enc_ctx->frame_num < 300)
1086 {
1087 p_in_frame->roi_len = p_enc_ctx->roi_len;
1088 } else
1089 {
1090 p_in_frame->roi_len = 0;
1091 }
1092 // when ROI enabled, always have a data buffer for ROI
1093 // Note: this is handled separately from ROI through side/aux data
1094 p_in_frame->extra_data_len += p_enc_ctx->roi_len;
1095 }
1096
1097 int should_send_sei_with_frame = ni_should_send_sei_with_frame(
1098 p_enc_ctx, p_in_frame->ni_pict_type, api_params);
1099
1100 // data buffer for various SEI: HDR mastering display color volume, HDR
1101 // content light level, close caption, User data unregistered, HDR10+
1102 // etc.
1103 uint8_t mdcv_data[NI_MAX_SEI_DATA];
1104 uint8_t cll_data[NI_MAX_SEI_DATA];
1105 uint8_t cc_data[NI_MAX_SEI_DATA];
1106 uint8_t udu_data[NI_MAX_SEI_DATA];
1107 uint8_t hdrp_data[NI_MAX_SEI_DATA];
1108
1109 // prep for auxiliary data (various SEI, ROI) in p_in_frame, based on
1110 // the data returned in decoded frame and also reconfig and demo modes
1111 // collected in prep_reconf_demo_data
1113 p_enc_ctx, p_in_frame, &(p_dec_out_data->data.frame),
1114 p_enc_ctx->codec_format, should_send_sei_with_frame, mdcv_data,
1115 cll_data, cc_data, udu_data, hdrp_data);
1116
1117 p_in_frame->extra_data_len += p_in_frame->sei_total_len;
1118
1119 // data layout requirement: leave space for reconfig data if at least
1120 // one of reconfig, SEI or ROI is present
1121 // Note: ROI is present when enabled, so use encode config flag instead
1122 // of frame's roi_len as it can be 0 indicating a 0'd ROI map
1123 // setting !
1124 if (p_in_frame->reconf_len || p_in_frame->sei_total_len ||
1125 (api_params->roi_demo_mode &&
1126 api_params->cfg_enc_params.roi_enable))
1127 {
1128 p_in_frame->extra_data_len += sizeof(ni_encoder_change_params_t);
1129 }
1130
1131 if (!is_hwframe)
1132 {
1134 p_in_frame, input_video_width, input_video_height, dst_stride,
1135 p_enc_ctx->codec_format == NI_CODEC_FORMAT_H264,
1136 (int)(p_in_frame->extra_data_len), alignment_2pass_wa);
1137 if (!p_in_frame->p_data[0])
1138 {
1139 ni_log(NI_LOG_ERROR, "Error: cannot allocate YUV frame buffer!");
1141 }
1142 } else
1143 {
1144 ni_frame_buffer_alloc_hwenc(p_in_frame, input_video_width,
1145 input_video_height,
1146 (int)(p_in_frame->extra_data_len));
1147 if (!p_in_frame->p_data[3])
1148 {
1149 ni_log(NI_LOG_ERROR, "Error: cannot allocate YUV frame buffer!");
1151 }
1152 }
1153
1155 "p_dst alloc linesize = %d/%d/%d src height=%d "
1156 "dst height aligned = %d/%d/%d force_key_frame=%d, "
1157 "extra_data_len=%u"
1158 " sei_size=%u (hdr_content_light_level %u hdr_mastering_display_"
1159 "color_vol %u hdr10+ %u hrd %d) reconf_size=%u roi_size=%u "
1160 "force_pic_qp=%u udu_sei_size=%u "
1161 "use_cur_src_as_long_term_pic %u use_long_term_ref %u\n",
1162 dst_stride[0], dst_stride[1], dst_stride[2], input_video_height,
1163 dst_height_aligned[0], dst_height_aligned[1], dst_height_aligned[2],
1164 p_in_frame->force_key_frame, p_in_frame->extra_data_len,
1165 p_in_frame->sei_total_len,
1168 p_in_frame->sei_hdr_plus_len, 0, /* hrd is 0 size for now */
1169 p_in_frame->reconf_len, p_in_frame->roi_len,
1170 p_in_frame->force_pic_qp, p_in_frame->sei_user_data_unreg_len,
1171 p_in_frame->use_cur_src_as_long_term_pic,
1172 p_in_frame->use_long_term_ref);
1173
1174 uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS];
1175 int src_stride[NI_MAX_NUM_DATA_POINTERS];
1176 int src_height[NI_MAX_NUM_DATA_POINTERS];
1177
1178 src_height[0] = p_dec_out_data->data.frame.video_height;
1179 src_height[1] = src_height[2] = src_height[0] / 2;
1180 src_height[3] = 0;
1181
1182 src_stride[0] =
1183 (int)(p_dec_out_data->data.frame.data_len[0]) / src_height[0];
1184 src_stride[1] =
1185 (int)(p_dec_out_data->data.frame.data_len[1]) / src_height[1];
1186 src_stride[2] = src_stride[1];
1187 if (is_semiplanar)
1188 {
1189 src_height[2] = 0;
1190 src_stride[2] = 0;
1191 }
1192 src_stride[3] = 0;
1193
1194 p_src[0] = p_dec_out_data->data.frame.p_data[0];
1195 p_src[1] = p_dec_out_data->data.frame.p_data[1];
1196 p_src[2] = p_dec_out_data->data.frame.p_data[2];
1197 p_src[3] = p_dec_out_data->data.frame.p_data[3];
1198
1199 if (!is_hwframe)
1200 { // YUV part of the encoder input data layout
1202 (uint8_t **)(p_in_frame->p_data), p_src, input_video_width,
1203 input_video_height, p_enc_ctx->bit_depth_factor, is_semiplanar,
1204 ((ni_xcoder_params_t *)p_enc_ctx->p_session_config)
1205 ->cfg_enc_params.conf_win_right,
1206 dst_stride, dst_height_aligned, src_stride, src_height);
1207 } else
1208 {
1209 ni_copy_hw_descriptors((uint8_t **)(p_in_frame->p_data), p_src);
1210 }
1211 // auxiliary data part of the encoder input data layout
1212 ni_enc_copy_aux_data(p_enc_ctx, p_in_frame,
1213 &(p_dec_out_data->data.frame),
1214 p_enc_ctx->codec_format, mdcv_data, cll_data,
1215 cc_data, udu_data, hdrp_data, is_hwframe,
1216 is_semiplanar);
1217
1218 p_in_frame->video_width = input_video_width;
1219 p_in_frame->video_height = input_video_height;
1220
1221 p_in_frame->start_of_stream = 0;
1222 if (!p_ctx->enc_sos_sent[enc_id])
1223 {
1224 p_ctx->enc_sos_sent[enc_id] = 1;
1225 p_in_frame->start_of_stream = 1;
1226 }
1227
1228send_frame:
1229 data_len_to_send = (int)(p_in_frame->data_len[0] + p_in_frame->data_len[1] +
1230 p_in_frame->data_len[2] + p_in_frame->data_len[3]);
1231
1232 if (data_len_to_send > 0 || p_in_frame->end_of_stream)
1233 {
1234 oneSent = ni_device_session_write(p_enc_ctx, p_enc_in_data,
1236 p_in_frame->end_of_stream = 0;
1237 } else
1238 {
1240 }
1241
1242 if (oneSent < 0)
1243 {
1244 ni_log(NI_LOG_ERROR, "Error: encoder_send_data2\n");
1245 p_ctx->enc_resend[enc_id] = 1;
1247 } else if (oneSent == 0)
1248 {
1249 if (p_ctx->enc_eos_sent[enc_id] == 0 && p_enc_ctx->ready_to_close)
1250 {
1251 p_ctx->enc_resend[enc_id] = 0;
1252 p_ctx->enc_eos_sent[enc_id] = 1;
1253 } else
1254 {
1255 p_ctx->enc_resend[enc_id] = 1;
1257 }
1258 } else
1259 {
1260 p_ctx->enc_resend[enc_id] = 0;
1261
1262 if (p_enc_ctx->ready_to_close)
1263 {
1264 p_ctx->enc_eos_sent[enc_id] = 1;
1265 }
1266
1267 ni_pts_enqueue(p_ctx->enc_pts_queue[enc_id], p_ctx->pts[enc_id]);
1268 ++p_ctx->pts[enc_id];
1269
1270 ni_log(NI_LOG_DEBUG, "encoder_send_data2: success\n");
1271 }
1272
1274}
1275
1276/*!*****************************************************************************
1277 * \brief Send encoder input data, read from uploader instance hwframe
1278 *
1279 * \param
1280 *
1281 * \return
1282 ******************************************************************************/
1284 ni_session_data_io_t *p_in_data,
1285 int input_video_width, int input_video_height, int eos)
1286{
1287 int oneSent;
1288 ni_frame_t *p_in_frame = &(p_in_data->data.frame);
1289 uint8_t enc_id = p_ctx->curr_enc_index;
1290
1291 ni_log(NI_LOG_DEBUG, "===> encoder_send_data3 <===\n");
1292
1293 if (p_ctx->enc_eos_sent[enc_id] == 1)
1294 {
1295 ni_log(NI_LOG_DEBUG, "encoder_send_data3: ALL data (incl. eos) sent "
1296 "already!\n");
1297 return 0;
1298 }
1299
1300 if (p_ctx->enc_resend[enc_id])
1301 {
1302 goto send_frame;
1303 }
1304
1305 p_in_frame->start_of_stream = 0;
1306 if (!p_ctx->enc_sos_sent[enc_id])
1307 {
1308 p_ctx->enc_sos_sent[enc_id] = 1;
1309 p_in_frame->start_of_stream = 1;
1310 }
1311 p_in_frame->end_of_stream = eos;
1312 p_in_frame->force_key_frame = 0;
1313 p_in_frame->video_width = input_video_width;
1314 p_in_frame->video_height = input_video_height;
1315 p_in_frame->pts = p_ctx->pts[enc_id];
1316 if (eos)
1317 {
1318 ni_log(NI_LOG_DEBUG, "encoder_send_data3: read chunk size 0, eos!\n");
1319 }
1320
1321 // only metadata header for now
1323
1324send_frame:
1325 oneSent =
1326 ni_device_session_write(p_enc_ctx, p_in_data, NI_DEVICE_TYPE_ENCODER);
1327 if (oneSent < 0)
1328 {
1330 "Error: failed ni_device_session_write() for encoder\n");
1331 p_ctx->enc_resend[enc_id] = 1;
1332 return -1;
1333 } else if (oneSent == 0 && !p_enc_ctx->ready_to_close)
1334 {
1335 p_ctx->enc_resend[enc_id] = 1;
1336 ni_log(NI_LOG_DEBUG, "NEEDED TO RESEND");
1338 } else
1339 {
1340 p_ctx->enc_resend[enc_id] = 0;
1341
1342 ni_log(NI_LOG_DEBUG, "encoder_send_data3: total sent data size=%u\n",
1343 p_in_frame->data_len[3]);
1344
1345 ni_log(NI_LOG_DEBUG, "encoder_send_data3: success\n");
1346
1347 if (p_enc_ctx->ready_to_close)
1348 {
1349 p_ctx->enc_eos_sent[enc_id] = 1;
1350 }
1351
1352 ni_pts_enqueue(p_ctx->enc_pts_queue[enc_id], p_ctx->pts[enc_id]);
1353 ++p_ctx->pts[enc_id];
1354 }
1355
1356 return 0;
1357}
1358
1359/*!*****************************************************************************
1360 * \brief Encoder session open
1361 *
1362 * \param
1363 *
1364 * \return 0 if successful, < 0 otherwise
1365 ******************************************************************************/
1366int encoder_open_session(ni_session_context_t *p_enc_ctx, int dst_codec_format,
1367 int iXcoderGUID, ni_xcoder_params_t *p_enc_params,
1368 int width, int height, ni_pix_fmt_t pix_fmt,
1369 bool check_zerocopy)
1370{
1371 int ret = 0;
1372 bool isrgba = false;
1373
1374 p_enc_ctx->p_session_config = p_enc_params;
1375 p_enc_ctx->session_id = NI_INVALID_SESSION_ID;
1376 p_enc_ctx->codec_format = dst_codec_format;
1377
1378 // on a sequence change the device handles are deliberately left open by
1379 // encoder_close_session; keep them (and the card GUID they belong to) so
1380 // ni_device_session_open re-uses them rather than opening new ones
1382 {
1383 // assign the card GUID in the encoder context and let session open
1384 // take care of the rest
1385 p_enc_ctx->device_handle = NI_INVALID_DEVICE_HANDLE;
1386 p_enc_ctx->blk_io_handle = NI_INVALID_DEVICE_HANDLE;
1387 p_enc_ctx->hw_id = iXcoderGUID;
1388 }
1389
1390 // default: little endian
1392
1393 switch (pix_fmt)
1394 {
1395 case NI_PIX_FMT_YUV420P:
1396 case NI_PIX_FMT_NV12:
1397 p_enc_ctx->src_bit_depth = 8;
1398 p_enc_ctx->bit_depth_factor = 1;
1399 break;
1401 case NI_PIX_FMT_P010LE:
1402 p_enc_ctx->src_bit_depth = 10;
1403 p_enc_ctx->bit_depth_factor = 2;
1404 break;
1405 case NI_PIX_FMT_ABGR:
1406 case NI_PIX_FMT_ARGB:
1407 case NI_PIX_FMT_RGBA:
1408 case NI_PIX_FMT_BGRA:
1409 p_enc_ctx->src_bit_depth = 8;
1410 p_enc_ctx->bit_depth_factor = 4;
1411 isrgba = true;
1412 break;
1413 default:
1414 p_enc_ctx->src_bit_depth = 8;
1415 p_enc_ctx->bit_depth_factor = 1;
1416 pix_fmt = NI_PIX_FMT_YUV420P;
1417 break;
1418 //ni_log(NI_LOG_ERROR, "%s: Invalid pixel format %s\n", __func__,
1419 // ni_pixel_format_name(pix_fmt));
1420 //return NI_RETCODE_INVALID_PARAM;
1421 }
1422
1423 // original resolution this stream started with, this is used by encoder sequence change
1424 p_enc_ctx->ori_width = width;
1425 p_enc_ctx->ori_height = height;
1426 p_enc_ctx->ori_bit_depth_factor = p_enc_ctx->bit_depth_factor;
1427 p_enc_ctx->ori_pix_fmt = pix_fmt;
1428 p_enc_ctx->pixel_format = pix_fmt;
1429
1430 int linesize_aligned = width;
1431 if (!isrgba)
1432 {
1433 if (linesize_aligned < NI_MIN_WIDTH)
1434 {
1435 p_enc_params->cfg_enc_params.conf_win_right +=
1436 (NI_MIN_WIDTH - width) / 2 * 2;
1437 linesize_aligned = NI_MIN_WIDTH;
1438 } else
1439 {
1440 linesize_aligned = ((width + 1) / 2) * 2;
1441 p_enc_params->cfg_enc_params.conf_win_right +=
1442 (linesize_aligned - width) / 2 * 2;
1443 }
1444 }
1445 p_enc_params->source_width = linesize_aligned;
1446
1447 int height_aligned = height;
1448 if (!isrgba)
1449 {
1450 if (height_aligned < NI_MIN_HEIGHT)
1451 {
1452 p_enc_params->cfg_enc_params.conf_win_bottom +=
1453 (NI_MIN_HEIGHT - height) / 2 * 2;
1454 height_aligned = NI_MIN_HEIGHT;
1455 } else
1456 {
1457 height_aligned = ((height + 1) / 2) * 2;
1458 p_enc_params->cfg_enc_params.conf_win_bottom +=
1459 (height_aligned - height) / 2 * 2;
1460 }
1461 }
1462 p_enc_params->source_height = height_aligned;
1463
1464 // default planar encoder input data
1465 p_enc_params->cfg_enc_params.planar = get_pixel_planar(pix_fmt);
1466
1467 if (check_zerocopy)
1468 {
1469
1470 // config linesize for zero copy (if input resolution is zero copy compatible)
1471 int src_stride[NI_MAX_NUM_DATA_POINTERS];
1472
1473 // NOTE - FFmpeg / Gstreamer users should use linesize array in frame structure instead of src_stride in the following sample code
1474 src_stride[0] = width * p_enc_ctx->bit_depth_factor;
1475
1476 if (isrgba)
1477 src_stride[1] = src_stride[2] = 0;
1478 else
1479 {
1480 bool isnv12frame = (p_enc_params->cfg_enc_params.planar == NI_PIXEL_PLANAR_FORMAT_SEMIPLANAR) ? true : false;
1481 src_stride[1] = isnv12frame ? src_stride[0] : src_stride[0] / 2;
1482 src_stride[2] = isnv12frame ? 0 : src_stride[0] / 2;
1483 }
1484
1486 p_enc_params, width, height,
1487 (const int *)src_stride, true);
1488 }
1489
1491 if (ret != NI_RETCODE_SUCCESS)
1492 {
1493 ni_log(NI_LOG_ERROR, "Error: %s failure!\n", __func__);
1494 } else
1495 {
1496 ni_log(NI_LOG_INFO, "Encoder device %d session open successful.\n", iXcoderGUID);
1497 }
1498
1499 // set up ROI QP map for ROI demo modes if enabled
1500 if (p_enc_params->cfg_enc_params.roi_enable &&
1501 (1 == p_enc_params->roi_demo_mode || 2 == p_enc_params->roi_demo_mode))
1502 {
1503 set_demo_roi_map(p_enc_ctx);
1504 }
1505
1506 return ret;
1507}
1508
1509/*!*****************************************************************************
1510 * \brief Compute the FW-side buffer sizes for a given resolution, matching
1511 * VCEncChangeResolutionCheck / EncAsicGetSize. The calculation assumes
1512 * ref_alignment = 64.
1513 ******************************************************************************/
1514static void get_fw_buffer_size(int width, int height, int bit_depth,
1515 int *internal_image_luma_size,
1516 int *luma_size, int *luma_size_4n, int *chroma_size)
1517{
1518 int width_4n;
1519 int height_4n;
1520
1521 if (!internal_image_luma_size || !luma_size || !luma_size_4n || !chroma_size)
1522 {
1523 return;
1524 }
1525
1526 width_4n = ((width + 15) / 16) * 4;
1527 width = NI_ALIGN(width, 64);
1528 height = NI_ALIGN(height, 64);
1529 height_4n = height / 4;
1530
1531 *luma_size = NI_ALIGN(NI_ALIGN(width * 4 * bit_depth / 8, 16), 64) *
1532 height / 4;
1533 *luma_size_4n = NI_ALIGN(NI_ALIGN(width_4n * 4 * bit_depth / 8, 16), 64) *
1534 height_4n / 4;
1535 *internal_image_luma_size = (*luma_size + *luma_size_4n + 0xf) & ~0xf;
1536 *internal_image_luma_size = NI_ALIGN(*internal_image_luma_size, 64);
1537 *chroma_size = *luma_size / 2;
1538}
1539
1540/*!*****************************************************************************
1541 * \brief Reopen or reconfig encoder upon sequence change
1542 *
1543 * \param
1544 *
1545 * \return 0 - success got packet
1546 * 1 - received eos
1547 * 2 - got nothing, need retry
1548 * -1 - failure
1549 ******************************************************************************/
1551 ni_session_data_io_t *p_in_data,
1552 ni_session_data_io_t *p_out_data)
1553{
1554 int ret = NI_TEST_RETCODE_SUCCESS;
1555 int new_stride, ori_stride;
1556 int internal_image_luma_size, luma_size, luma_size_4n, chroma_size;
1557 int ori_internal_image_luma_size, ori_luma_size, ori_luma_size_4n, ori_chroma_size;
1558 int pass1_internal_image_luma_size, pass1_luma_size, pass1_luma_size_4n, pass1_chroma_size;
1559 int ori_pass1_internal_image_luma_size, ori_pass1_luma_size;
1560 int ori_pass1_luma_size_4n, ori_pass1_chroma_size;
1561 bool pass1_buffer_too_small = false;
1562 bool bIsSmallPicture = false;
1563 ni_frame_t *p_buffered_frame = &(p_in_data->data.frame);
1564 ni_xcoder_params_t *p_api_param = (ni_xcoder_params_t *)p_enc_ctx->p_session_config;
1565 int new_width, new_height;
1566 ni_pix_fmt_t new_pix_fmt;
1567 bool is_semiplanar;
1568 bool is_rgba;
1569 int src_stride[NI_MAX_NUM_DATA_POINTERS];
1570
1571 new_width = p_buffered_frame->video_width;
1572 new_height = p_buffered_frame->video_height;
1573 new_pix_fmt = p_buffered_frame->pixel_format;
1574
1575 // check if resolution is zero copy compatible and set linesize according to new resolution
1576 is_semiplanar = (new_pix_fmt == NI_PIX_FMT_NV12 || new_pix_fmt == NI_PIX_FMT_P010LE);
1577
1578 is_rgba = (new_pix_fmt == NI_PIX_FMT_ABGR || new_pix_fmt == NI_PIX_FMT_ARGB
1579 || new_pix_fmt == NI_PIX_FMT_RGBA || new_pix_fmt == NI_PIX_FMT_BGRA);
1580
1581 // NOTE - FFmpeg / Gstreamer users should use linesize array in frame structure instead of src_stride in the following sample code
1582 src_stride[0] = new_width * p_enc_ctx->bit_depth_factor;
1583 if (is_rgba)
1584 {
1585 src_stride[1] = 0;
1586 src_stride[2] = 0;
1587 }
1588 else
1589 {
1590 src_stride[1] = is_semiplanar ? src_stride[0] : src_stride[0] / 2;
1591 src_stride[2] = is_semiplanar ? 0 : src_stride[0] / 2;
1592 }
1593
1594 if (ni_encoder_frame_zerocopy_check(p_enc_ctx,
1595 p_api_param, new_width, new_height,
1596 (const int *)src_stride, true) == NI_RETCODE_SUCCESS)
1597 {
1598 new_stride = p_api_param->luma_linesize; // new sequence is zero copy compatible
1599 }
1600 else
1601 {
1602 new_stride = NI_ALIGN(new_width * p_enc_ctx->bit_depth_factor, 128);
1603 }
1604
1605 if (p_enc_ctx->ori_luma_linesize && p_enc_ctx->ori_chroma_linesize)
1606 {
1607 ori_stride = p_enc_ctx->ori_luma_linesize; // previous sequence was zero copy compatible
1608 }
1609 else
1610 {
1611 ori_stride = NI_ALIGN(p_enc_ctx->ori_width * p_enc_ctx->bit_depth_factor, 128);
1612 }
1613
1614 get_fw_buffer_size(new_width, new_height,
1615 p_enc_ctx->bit_depth_factor == 2 ? 10 : 8,
1616 &internal_image_luma_size, &luma_size, &luma_size_4n,
1617 &chroma_size);
1618 get_fw_buffer_size(p_enc_ctx->ori_width, p_enc_ctx->ori_height,
1619 p_enc_ctx->ori_bit_depth_factor == 2 ? 10 : 8,
1620 &ori_internal_image_luma_size, &ori_luma_size,
1621 &ori_luma_size_4n, &ori_chroma_size);
1622
1623 // RGBA: host input size uses width (no stride align). Recon/ref sizes keep
1624 // get_fw_buffer_size results to match VCEncChangeResolutionCheck / EncAsicGetSize.
1625 if (is_rgba)
1626 {
1627 new_stride = new_width;
1628 ori_stride = p_enc_ctx->ori_width;
1629 }
1630
1631 if (p_api_param->cfg_enc_params.lookAheadDepth ||
1632 p_api_param->cfg_enc_params.crf >= 0 ||
1633 p_api_param->cfg_enc_params.crfFloat >= 0) {
1634 ni_log(NI_LOG_DEBUG, "xcoder_encode_reinit 2-pass "
1635 "lookaheadDepth %d and/or CRF %d and/or CRFFloat %f\n",
1636 p_api_param->cfg_enc_params.lookAheadDepth,
1637 p_api_param->cfg_enc_params.crf,
1638 p_api_param->cfg_enc_params.crfFloat);
1639 if ((new_width < NI_2PASS_ENCODE_MIN_WIDTH) ||
1640 (new_height < NI_2PASS_ENCODE_MIN_HEIGHT)) {
1641 bIsSmallPicture = true;
1642 }
1643 }
1644 else {
1645 if ((new_width < NI_MIN_WIDTH) ||
1646 (new_height < NI_MIN_HEIGHT)) {
1647 bIsSmallPicture = true;
1648 }
1649 }
1650
1651 // Match 2-pass WA gating: lookAheadDepth and/or CRF also allocate pass-1 buffers.
1652 if (p_api_param->cfg_enc_params.lookAheadDepth ||
1653 p_api_param->cfg_enc_params.crf >= 0 ||
1654 p_api_param->cfg_enc_params.crfFloat >= 0) {
1655 // 2-pass workaround requires 32x32-padded input, then apply inLoopDSRatio to pass-1 buffers:
1656 // 0 = 1:1 (no DS), 1 = 1:2 (default).
1657 int ds_shift = p_api_param->cfg_enc_params.inLoopDSRatio;
1658 int pass1_width = NI_ALIGN(new_width, 32) >> ds_shift;
1659 int pass1_height = NI_ALIGN(new_height, 32) >> ds_shift;
1660 int ori_pass1_width = NI_ALIGN(p_enc_ctx->ori_width, 32) >> ds_shift;
1661 int ori_pass1_height = NI_ALIGN(p_enc_ctx->ori_height, 32) >> ds_shift;
1662
1663 get_fw_buffer_size(pass1_width, pass1_height,
1664 p_enc_ctx->bit_depth_factor == 2 ? 10 : 8,
1665 &pass1_internal_image_luma_size, &pass1_luma_size,
1666 &pass1_luma_size_4n, &pass1_chroma_size);
1667 get_fw_buffer_size(ori_pass1_width, ori_pass1_height,
1668 p_enc_ctx->ori_bit_depth_factor == 2 ? 10 : 8,
1669 &ori_pass1_internal_image_luma_size,
1670 &ori_pass1_luma_size, &ori_pass1_luma_size_4n,
1671 &ori_pass1_chroma_size);
1672
1673 pass1_buffer_too_small =
1674 ori_pass1_luma_size < pass1_luma_size ||
1675 ori_pass1_luma_size_4n < pass1_luma_size_4n ||
1676 ori_pass1_internal_image_luma_size <
1677 pass1_internal_image_luma_size ||
1678 ori_pass1_chroma_size < pass1_chroma_size;
1679
1680 ni_log(NI_LOG_INFO, "%s pass-1 buffers (inLoopDSRatio %d) "
1681 "original %dx%d luma %d/%d internal %d chroma %d "
1682 "new %dx%d luma %d/%d internal %d chroma %d too_small %d\n",
1683 __func__, ds_shift, ori_pass1_width, ori_pass1_height,
1684 ori_pass1_luma_size, ori_pass1_luma_size_4n,
1685 ori_pass1_internal_image_luma_size, ori_pass1_chroma_size,
1686 pass1_width, pass1_height, pass1_luma_size, pass1_luma_size_4n,
1687 pass1_internal_image_luma_size, pass1_chroma_size,
1688 pass1_buffer_too_small);
1689 }
1690
1691 if (p_api_param->cfg_enc_params.multicoreJointMode) {
1692 ni_log(NI_LOG_DEBUG, "xcoder_encode_reinit multicore "
1693 "joint mode\n");
1694 if ((new_width < NI_MULTICORE_ENCODE_MIN_WIDTH) ||
1695 (new_height < NI_MULTICORE_ENCODE_MIN_HEIGHT)) {
1696 bIsSmallPicture = true;
1697 }
1698 }
1699
1700 if (p_api_param->cfg_enc_params.crop_width || p_api_param->cfg_enc_params.crop_height) {
1701 ni_log(NI_LOG_DEBUG, "xcoder_encode_reinit needs to close and re-open "
1702 "due to crop width x height\n");
1703 bIsSmallPicture = true;
1704 }
1705
1706 ni_log(NI_LOG_DEBUG, "xcoder_encode_reinit resolution: %dx%d->%dx%d "
1707 "pix fmt: %d->%d bIsSmallPicture %d codec %d\n",
1708 ori_stride, p_enc_ctx->ori_height, new_stride, new_height,
1709 p_enc_ctx->ori_pix_fmt, new_pix_fmt, bIsSmallPicture,
1710 p_enc_ctx->codec_format);
1711
1712 ni_log(NI_LOG_INFO, "%s resolution changing %dx%d -> %dx%d "
1713 "original stride %d height %d luma size %d/%d internal %d chroma %d pix fmt %d "
1714 "new stride %d height %d luma size %d/%d internal %d chroma %d pix fmt %d\n",
1715 __func__, p_enc_ctx->ori_width, p_enc_ctx->ori_height, new_width,
1716 new_height, ori_stride, p_enc_ctx->ori_height, ori_luma_size,
1717 ori_luma_size_4n, ori_internal_image_luma_size, ori_chroma_size,
1718 p_enc_ctx->ori_pix_fmt, new_stride, new_height, luma_size,
1719 luma_size_4n, internal_image_luma_size, chroma_size, new_pix_fmt);
1720
1721 // fast sequence change without close / open only if new resolution < original resolution
1722 if (ori_stride*p_enc_ctx->ori_height < new_stride*new_height ||
1723 ori_luma_size < luma_size ||
1724 ori_luma_size_4n < luma_size_4n ||
1725 ori_internal_image_luma_size < internal_image_luma_size ||
1726 ori_chroma_size < chroma_size ||
1727 pass1_buffer_too_small ||
1728 p_enc_ctx->ori_pix_fmt != new_pix_fmt ||
1729 bIsSmallPicture ||
1730 p_enc_ctx->codec_format == NI_CODEC_FORMAT_JPEG ||
1732 {
1733 ni_log(NI_LOG_INFO, "XCoder encode sequence change by close / re-open session\n");
1734 encoder_close_session(p_enc_ctx, p_in_data, p_out_data);
1735 ret = encoder_open_session(p_enc_ctx, p_enc_ctx->codec_format,
1736 p_enc_ctx->hw_id, p_api_param, new_width,
1737 new_height, new_pix_fmt, true);
1738 if (NI_RETCODE_SUCCESS != ret)
1739 {
1740 ni_log(NI_LOG_ERROR, "Failed to Re-open Encoder Session upon Sequence Change (status = %d)\n", ret);
1741 // the sequence change did not complete - drop back to NORMAL so the
1742 // state does not stay stuck at SEQ_CHANGE_DRAINING (the handles kept
1743 // open by encoder_close_session are released by the caller's cleanup)
1745 return ret;
1746 }
1747 p_out_data->data.packet.end_of_stream = 0;
1748 p_in_data->data.frame.start_of_stream = 1;
1749 // clear crop parameters upon sequence change because cropping values may not be compatible to new resolution
1750 p_api_param->cfg_enc_params.crop_width = p_api_param->cfg_enc_params.crop_height = 0;
1751 p_api_param->cfg_enc_params.hor_offset = p_api_param->cfg_enc_params.ver_offset = 0;
1752 }
1753 else
1754 {
1755 if (p_enc_ctx->codec_format == NI_CODEC_FORMAT_AV1) {
1756 // AV1 8x8 alignment HW limitation is now worked around by FW cropping input resolution
1757 if (new_width % NI_PARAM_AV1_ALIGN_WIDTH_HEIGHT)
1759 "resolution change: AV1 Picture Width not aligned to %d - picture will be cropped\n",
1761
1762 if (new_height % NI_PARAM_AV1_ALIGN_WIDTH_HEIGHT)
1764 "resolution change: AV1 Picture Height not aligned to %d - picture will be cropped\n",
1766 }
1767 ni_log(NI_LOG_INFO, "XCoder encode sequence change by re-config session (fast path)\n");
1768 ret = encoder_sequence_change(p_enc_ctx, p_in_data, p_out_data, new_width, new_height, new_pix_fmt);
1769 }
1770
1771 // this state is referenced when sending first frame after sequence change;
1772 // only claim it if the change succeeded, otherwise fall back to NORMAL so
1773 // the next send does not take the post-sequence-change path
1776
1777 ni_log(NI_LOG_DEBUG, "%s: session_run_state change to %d \n", __func__,
1778 p_enc_ctx->session_run_state);
1779
1780 return ret;
1781}
1782
1783void write_av1_ivf_header(ni_demo_context_t *p_ctx, uint32_t width, uint32_t height, uint32_t frame_num,
1784 uint32_t frame_denom, FILE *p_file)
1785{
1786 // write the global ivf start header
1787 if (!p_ctx->ivf_header_written[p_ctx->curr_enc_index] && p_file != NULL && !p_ctx->av1_output_obu)
1788 {
1789 uint8_t start_header[32] = {
1790 0x44, 0x4b, 0x49, 0x46, /* signature: 'DKIF' */
1791 0x00, 0x00, /* version: 0 */
1792 0x20, 0x00, /* length of header in bytes: 32 */
1793 0x41, 0x56, 0x30, 0x31, /* codec FourCC: AV01 */
1794 0x00, 0x07, /* width in pixels(little endian), default 1280 */
1795 0xd0, 0x02, /* height in pixels(little endian), default 720 */
1796 0x1e, 0x00, 0x00, 0x00, /* time base numerator, default 30 */
1797 0x01, 0x00, 0x00, 0x00, /* time base denominator, default 1 */
1798 0x00, 0x00, 0x00, 0x00, /* number of frames in file */
1799 0x00, 0x00, 0x00, 0x00 /* reserved */
1800 };
1801
1802 if (width && height)
1803 {
1804 start_header[12] = width & 0xff;
1805 start_header[13] = ((width >> 8) & 0xff);
1806 start_header[14] = height & 0xff;
1807 start_header[15] = ((height >> 8) & 0xff);
1808 }
1809
1810 if (frame_num && frame_denom)
1811 {
1812 start_header[16] = frame_num & 0xff;
1813 start_header[17] = ((frame_num >> 8) & 0xff);
1814 start_header[18] = ((frame_num >> 16) & 0xff);
1815 start_header[19] = ((frame_num >> 24) & 0xff);
1816 start_header[20] = frame_denom & 0xff;
1817 start_header[21] = ((frame_denom >> 8) & 0xff);
1818 start_header[22] = ((frame_denom >> 16) & 0xff);
1819 start_header[23] = ((frame_denom >> 24) & 0xff);
1820 }
1821
1822 if (fwrite(start_header, sizeof(start_header), 1, p_file) != 1)
1823 {
1824 ni_log(NI_LOG_ERROR, "Error: writing ivf start header fail!\n");
1825 ni_log(NI_LOG_ERROR, "Error: ferror rc = %d\n", ferror(p_file));
1826 }
1827
1828 p_ctx->ivf_header_written[p_ctx->curr_enc_index] = 1;
1829 }
1830}
1831
1832void write_av1_ivf_packet(ni_demo_context_t *p_ctx, ni_packet_t *p_out_pkt, uint32_t meta_size, FILE *p_file)
1833{
1834 int i;
1835 uint8_t enc_id = p_ctx->curr_enc_index;
1836
1837 if (!p_file)
1838 {
1839 return;
1840 }
1841
1842 // write ivf frame header
1843 if (!p_ctx->av1_output_obu)
1844 {
1845 uint32_t pts = p_ctx->av1_muxed_num_packets[enc_id];
1846 uint32_t pkt_size = p_out_pkt->data_len - meta_size;
1847
1848 if (p_ctx->av1_seq_header_len[enc_id] > 0)
1849 {
1850 pkt_size += p_ctx->av1_seq_header_len[enc_id] - meta_size;
1851 }
1852 for (i = 0; i < p_out_pkt->av1_buffer_index; i++)
1853 {
1854 pkt_size += p_out_pkt->av1_data_len[i] - meta_size;
1855 }
1856
1857 // ivf frame header
1858 // bytes 0-3: size of frame in bytes(not including the 12-byte header
1859 // byte 4-11: 64-bit pts (here pts=num_of_packets(32-bit), thus here only saves 32-bit
1860 uint8_t ivf_frame_header[12] = {((pkt_size & 0xff)),
1861 ((pkt_size >> 8) & 0xff),
1862 ((pkt_size >> 16) & 0xff),
1863 ((pkt_size >> 24) & 0xff),
1864 ((pts & 0xff)),
1865 ((pts >> 8) & 0xff),
1866 ((pts >> 16) & 0xff),
1867 ((pts >> 24) & 0xff),
1868 0x00, 0x00, 0x00, 0x00};
1869 if (fwrite(ivf_frame_header, 12, 1, p_file) != 1)
1870 {
1871 ni_log(NI_LOG_ERROR, "Error: writing ivf frame header fail!\n");
1872 ni_log(NI_LOG_ERROR, "Error: ferror rc = %d\n", ferror(p_file));
1873 }
1874 }
1875
1876 // write the leftover sequence header if there is any
1877 if (p_ctx->av1_seq_header_len[enc_id] > 0)
1878 {
1879 if (fwrite(p_ctx->p_av1_seq_header[enc_id] + meta_size,
1880 p_ctx->av1_seq_header_len[enc_id] - meta_size, 1, p_file) != 1)
1881 {
1882 ni_log(NI_LOG_ERROR, "Error: writing av1 sequence header fail!\n");
1883 ni_log(NI_LOG_ERROR, "Error: ferror rc = %d\n", ferror(p_file));
1884 }
1885 ni_aligned_free(p_ctx->p_av1_seq_header[enc_id]);
1886 p_ctx->av1_seq_header_len[enc_id] = 0;
1887 }
1888
1889 // write the leftover av1 packets
1890 for (i = 0; i < p_out_pkt->av1_buffer_index; i++)
1891 {
1892 if (fwrite((uint8_t *)p_out_pkt->av1_p_data[i] + meta_size,
1893 p_out_pkt->av1_data_len[i] - meta_size, 1, p_file) != 1)
1894 {
1895 ni_log(NI_LOG_ERROR, "Error: writing av1 packets fail!\n");
1896 ni_log(NI_LOG_ERROR, "Error: ferror rc = %d\n", ferror(p_file));
1897 }
1898 }
1899
1900 // write the current packet
1901 if (fwrite((uint8_t *)p_out_pkt->p_data + meta_size,
1902 p_out_pkt->data_len - meta_size, 1, p_file) != 1)
1903 {
1904 ni_log(NI_LOG_ERROR, "Error: writing av1 packets fail!\n");
1905 ni_log(NI_LOG_ERROR, "Error: ferror rc = %d\n", ferror(p_file));
1906 }
1907
1908 p_ctx->av1_muxed_num_packets[enc_id]++;
1909}
1910
1911int write_av1_ivf_trailer(ni_demo_context_t *p_ctx, ni_packet_t *p_out_pkt, uint32_t meta_size, FILE *p_file)
1912{
1913 uint32_t muxed_num_packets = p_ctx->av1_muxed_num_packets[p_ctx->curr_enc_index];
1914 if (p_file)
1915 {
1916 // write the leftover packets
1917 if (p_out_pkt->av1_buffer_index > 0)
1918 {
1919 write_av1_ivf_packet(p_ctx, p_out_pkt, meta_size, p_file);
1920 }
1921
1922 // update frame_count in ivf start header
1923 if (muxed_num_packets && !p_ctx->av1_output_obu)
1924 {
1925 uint8_t frame_cnt[4] = {
1926 (muxed_num_packets & 0xff),
1927 ((muxed_num_packets >> 8) & 0xff),
1928 ((muxed_num_packets >> 16) & 0xff),
1929 ((muxed_num_packets >> 24) & 0xff)};
1930 fseek(p_file, 24, SEEK_SET);
1931 if (fwrite(frame_cnt, 4, 1, p_file) != 1)
1932 {
1933 ni_log(NI_LOG_ERROR, "Error: failed to update frame_cnt in ivf "
1934 "header!\n");
1935 ni_log(NI_LOG_ERROR, "Error: ferror rc = %d\n", ferror(p_file));
1936 return -1;
1937 }
1938 }
1939 }
1940
1941 return 0;
1942}
1943
1944/*!*****************************************************************************
1945 * \brief Receive output data from encoder
1946 *
1947 * \param p_in_data is passed in to specify new frame resolution upon sequence
1948 * change
1949 *
1950 * \return 0 - success got packet
1951 * 1 - received eos
1952 * 2 - got nothing, need retry
1953 * -1 - failure
1954 ******************************************************************************/
1956 ni_session_data_io_t *p_out_data, int output_video_width,
1957 int output_video_height, FILE *p_file, ni_session_data_io_t * p_in_data)
1958{
1959 int packet_size = NI_MAX_TX_SZ;
1960 int rc = 0;
1961 int end_flag = 0;
1962 int rx_size = 0;
1963 uint8_t enc_id = p_ctx->curr_enc_index;
1964 ni_packet_t *p_out_pkt = &(p_out_data->data.packet);
1965 int meta_size = p_enc_ctx->meta_size;
1966 ni_xcoder_params_t *p_api_param = (ni_xcoder_params_t *)p_enc_ctx->p_session_config;
1967 int64_t pts = -1;
1968 int64_t dts = -1;
1969
1970 ni_log(NI_LOG_DEBUG, "===> encoder_receive_data <===\n");
1971 if (NI_INVALID_SESSION_ID == p_enc_ctx->session_id)
1972 {
1973 // keep-alive-thread timeout will set session_id to invalid, should exit
1975 "encode session id invalid, the session should be closed\n");
1977 }
1978
1979receive_data:
1980 rc = ni_packet_buffer_alloc(p_out_pkt, packet_size);
1981 if (rc != NI_RETCODE_SUCCESS)
1982 {
1983 ni_log(NI_LOG_ERROR, "Error: malloc packet failed, ret = %d!\n", rc);
1985 }
1986
1987 rc = ni_device_session_read(p_enc_ctx, p_out_data, NI_DEVICE_TYPE_ENCODER);
1988
1989 end_flag = p_out_pkt->end_of_stream;
1990 rx_size = rc;
1991
1992 ni_log(NI_LOG_DEBUG, "encoder_receive_data: received data size=%d\n", rx_size);
1993
1994 if (rx_size > meta_size)
1995 {
1996 if (p_enc_ctx->codec_format == NI_CODEC_FORMAT_AV1)
1997 {
1998 if (p_enc_ctx->pkt_num == 0)
1999 {
2000 write_av1_ivf_header(p_ctx, output_video_width, output_video_height,
2001 p_api_param->fps_number,
2002 p_api_param->fps_denominator, p_file);
2003 // store the sequence header for next packet writing
2004 p_ctx->p_av1_seq_header[enc_id] = (uint8_t *)p_out_pkt->p_data;
2005 p_ctx->av1_seq_header_len[enc_id] = p_out_pkt->data_len;
2006 p_out_pkt->p_buffer = NULL;
2007 p_out_pkt->p_data = NULL;
2008 p_out_pkt->buffer_size = 0;
2009 p_out_pkt->data_len = 0;
2010 } else
2011 {
2012 // store the av1 unshown frames for next packet writing
2013 if (!p_out_pkt->av1_show_frame)
2014 {
2015 p_out_pkt->av1_p_buffer[p_out_pkt->av1_buffer_index] =
2016 p_out_pkt->p_buffer;
2017 p_out_pkt->av1_p_data[p_out_pkt->av1_buffer_index] =
2018 p_out_pkt->p_data;
2019 p_out_pkt->av1_buffer_size[p_out_pkt->av1_buffer_index] =
2020 p_out_pkt->buffer_size;
2021 p_out_pkt->av1_data_len[p_out_pkt->av1_buffer_index] =
2022 p_out_pkt->data_len;
2023 p_out_pkt->av1_buffer_index++;
2024 p_out_pkt->p_buffer = NULL;
2025 p_out_pkt->p_data = NULL;
2026 p_out_pkt->buffer_size = 0;
2027 p_out_pkt->data_len = 0;
2028 if (p_out_pkt->av1_buffer_index >= MAX_AV1_ENCODER_GOP_NUM)
2029 {
2030 ni_log(NI_LOG_ERROR, "Error: recv AV1 not shown frame "
2031 "number %d >= %d\n", p_out_pkt->av1_buffer_index,
2034 }
2035 } else
2036 {
2037 ni_log(NI_LOG_DEBUG, "AV1 output packet "
2038 "pts %lld dts %lld\n", p_out_pkt->pts, p_out_pkt->dts);
2039 write_av1_ivf_packet(p_ctx, p_out_pkt, p_enc_ctx->meta_size, p_file);
2040 ni_packet_buffer_free_av1(p_out_pkt);
2041 }
2042
2043 // recycle hw frame before next read
2044 if (p_enc_ctx->hw_action)
2045 {
2046 // encoder only returns valid recycle index
2047 // when there's something to recycle.
2048 // This range is suitable for all memory bins
2049 if (p_out_pkt->recycle_index > 0 &&
2050 p_out_pkt->recycle_index <
2052 {
2053 ni_hw_frame_unref(p_out_pkt->recycle_index);
2054 p_out_pkt->recycle_index = 0; //clear to not double count
2055 }
2056 }
2057 }
2058 } else
2059 {
2060 if (p_file &&
2061 (fwrite((uint8_t *)p_out_pkt->p_data + meta_size,
2062 p_out_pkt->data_len - meta_size, 1, p_file) != 1))
2063 {
2064 ni_log(NI_LOG_ERROR, "Error: writing data %u bytes error!\n",
2065 p_out_pkt->data_len - meta_size);
2066 ni_log(NI_LOG_ERROR, "Error: ferror rc = %d\n", ferror(p_file));
2067 }
2068 }
2069
2070 p_ctx->enc_total_bytes_received[enc_id] += rx_size - meta_size;
2071
2072 if (p_enc_ctx->pkt_num == 0)
2073 {
2074 p_enc_ctx->pkt_num = 1;
2075 }
2076
2077 // The first packet is the sequence head packet and it will be read before the first frame is sent
2078 if(p_ctx->num_packets_received[enc_id] != 0)
2079 {
2080 pts = p_out_pkt->pts;
2081 ni_pts_dequeue(p_ctx->enc_pts_queue[enc_id], &dts);
2082 ni_log(NI_LOG_DEBUG, "PTS: %d, DTS: %d\n", pts, dts);
2083 }
2084
2085 (p_ctx->num_packets_received[enc_id])++;
2086
2087 ni_log(NI_LOG_DEBUG, "Got: Packets= %u\n", p_ctx->num_packets_received[enc_id]);
2088 } else if (rx_size != 0)
2089 {
2090 ni_log(NI_LOG_ERROR, "Error: received %d bytes, <= metadata size %d!\n",
2091 rx_size, meta_size);
2093 } else if (end_flag)
2094 {
2096 p_enc_ctx->session_run_state)
2097 {
2098 // after sequence change completes, reset codec state
2099 ni_log(NI_LOG_INFO, "encoder_receive_data: sequence "
2100 "change completed, return SEQ_CHANGE_DONE and will reopen "
2101 "or reconfig codec!\n");
2102 rc = encoder_reinit_session(p_enc_ctx, p_in_data, p_out_data);
2103 ni_log(NI_LOG_TRACE, "encoder_receive_data: encoder_reinit_session ret %d\n", rc);
2104 if (rc == NI_RETCODE_SUCCESS)
2105 {
2107 }
2108 else
2109 {
2111 }
2112 }
2113
2115 {
2116 // restart the encoder after sending flushing command
2117 rc = ni_device_session_restart(p_enc_ctx,
2118 p_in_data->data.frame.video_width,
2119 p_in_data->data.frame.video_height,
2121 ni_log(NI_LOG_INFO, "ni_device_session_restart() ret %d\n", rc);
2122 if (rc == NI_RETCODE_SUCCESS)
2123 {
2124 // need to reset the packet end_of_stream and run state
2125 p_out_pkt->end_of_stream = 0;
2128 }
2129 else
2130 {
2132 }
2133 }
2134
2135 if (p_enc_ctx->codec_format == NI_CODEC_FORMAT_AV1)
2136 {
2137 rc = write_av1_ivf_trailer(p_ctx, p_out_pkt, p_enc_ctx->meta_size, p_file);
2138 ni_packet_buffer_free_av1(p_out_pkt);
2139 if (rc < 0)
2140 {
2142 }
2143 }
2144 ni_log(NI_LOG_INFO, "Encoder Receiving done.\n");
2146 } else if (p_api_param->low_delay_mode && p_enc_ctx->frame_num >= p_enc_ctx->pkt_num) {
2147 ni_log(NI_LOG_DEBUG, "low delay mode and NO pkt, keep reading ..\n");
2148 ni_usleep(200);
2149 goto receive_data;
2150 } else { //rx_size == 0 && !end_flag
2151 ni_log(NI_LOG_DEBUG, "no packet received from encoder, return EAGAIN and retry\n");
2153 }
2154
2155 ni_log(NI_LOG_DEBUG, "encoder_receive_data: success\n");
2156
2158}
2159
2160/*!*****************************************************************************
2161 * \brief encoder session close
2162 *
2163 * \param
2164 *
2165 * \return 0 if successful, < 0 otherwise
2166 ******************************************************************************/
2168 ni_session_data_io_t *p_in_data,
2169 ni_session_data_io_t *p_out_data)
2170{
2171 int ret = 0;
2173
2174 ni_log(NI_LOG_DEBUG, "encoder_close_session - session_run_state %d\n", p_enc_ctx->session_run_state);
2175
2176 // keep the device handle(s) open across a sequence change so the memory bin
2177 // buffers get recycled instead of leaked; encoder_open_session leaves them
2178 // alone in that state and ni_device_session_open re-uses them
2180 {
2181 ni_log(NI_LOG_DEBUG, "encoder_close_session - close encoder blk_io_handle %d device_handle %d\n", p_enc_ctx->blk_io_handle, p_enc_ctx->device_handle);
2182#ifdef _WIN32
2183 ni_device_close(p_enc_ctx->device_handle);
2184#elif __linux__
2185 ni_device_close(p_enc_ctx->device_handle);
2186 ni_device_close(p_enc_ctx->blk_io_handle);
2187#endif
2188 p_enc_ctx->device_handle = NI_INVALID_DEVICE_HANDLE;
2189 p_enc_ctx->blk_io_handle = NI_INVALID_DEVICE_HANDLE;
2190 p_enc_ctx->auto_dl_handle = NI_INVALID_DEVICE_HANDLE;
2191 p_enc_ctx->sender_handle = NI_INVALID_DEVICE_HANDLE;
2192 }
2193
2194 if (p_enc_ctx->codec_format == NI_CODEC_FORMAT_AV1 &&
2195 p_out_data->data.packet.av1_buffer_index)
2196 {
2197 ni_packet_buffer_free_av1(&(p_out_data->data.packet));
2198 }
2199 ni_frame_buffer_free(&(p_in_data->data.frame));
2200 ni_packet_buffer_free(&(p_out_data->data.packet));
2201 return ret;
2202}
2203
2205 ni_session_data_io_t *p_in_data,
2206 ni_session_data_io_t *p_out_data,
2207 int width, int height, ni_pix_fmt_t pix_fmt)
2208{
2209 ni_retcode_t ret = 0;
2210 int bit_depth;
2211 int bit_depth_factor;
2212
2213 ni_log(NI_LOG_DEBUG, "XCoder encode sequence change (reconfig): session_run_state %d\n", p_enc_ctx->session_run_state);
2214
2215 switch (pix_fmt)
2216 {
2217 case NI_PIX_FMT_YUV420P:
2218 case NI_PIX_FMT_NV12:
2219 bit_depth = 8;
2220 bit_depth_factor = 1;
2221 break;
2223 case NI_PIX_FMT_P010LE:
2224 bit_depth = 10;
2225 bit_depth_factor = 2;
2226 break;
2227 default:
2228 bit_depth = 8;
2229 bit_depth_factor = 1;
2230 break;
2231 }
2232
2233 ret = ni_device_session_sequence_change(p_enc_ctx, width, height, bit_depth_factor, NI_DEVICE_TYPE_ENCODER);
2234 if (NI_RETCODE_SUCCESS != ret)
2235 {
2236 ni_log(NI_LOG_ERROR, "Failed to send Sequence Change to Encoder Session (status = %d)\n", ret);
2237 return ret;
2238 }
2239
2240 // update session context
2241 p_enc_ctx->bit_depth_factor = bit_depth_factor;
2242 p_enc_ctx->src_bit_depth = bit_depth;
2243 // xcoder demo only support little endian (for 10-bit pixel format)
2245 p_enc_ctx->ready_to_close = 0;
2246 p_enc_ctx->frame_num = 0; // need to reset frame_num because pkt_num is set to 1 when header received after sequnce change, and low delay mode compares frame_num and pkt_num
2247 p_enc_ctx->pkt_num = 0; // also need to reset pkt_num because before header received, pkt_num > frame_num will also cause low delay mode stuck
2248 p_enc_ctx->pixel_format = p_in_data->data.frame.pixel_format;
2249 p_out_data->data.packet.end_of_stream = 0;
2250 p_in_data->data.frame.start_of_stream = 1;
2251 return ret;
2252}
2253
2255 ni_session_context_t *enc_ctx_list,
2256 ni_xcoder_params_t *p_api_param_list,
2257 int output_total, char p_enc_conf_params[][2048],
2258 char p_enc_conf_gop[][2048],
2259 ni_frame_t *p_ni_frame, int width, int height,
2260 int fps_num, int fps_den, int bitrate,
2261 int codec_format, ni_pix_fmt_t pix_fmt,
2262 int aspect_ratio_idc, int xcoder_guid,
2263 niFrameSurface1_t *p_surface, int multi_thread,
2264 bool check_zerocopy)
2265{
2266 int i, ret = 0;
2267 int color_prim = NI_COL_PRI_UNSPECIFIED;
2268 int color_trc = NI_COL_TRC_UNSPECIFIED;
2269 int color_space = NI_COL_SPC_UNSPECIFIED;
2270 int sar_num = 0;
2271 int sar_den = 0;
2272 int video_full_range_flag = 0;
2273
2274 if (p_ni_frame != NULL)
2275 {
2276 // open the encode session when the first frame arrives and the session
2277 // is not opened yet, with the source stream and user-configured encode
2278 // info both considered when constructing VUI in the stream headers
2279 color_prim = p_ni_frame->color_primaries;
2280 color_trc = p_ni_frame->color_trc;
2281 color_space = p_ni_frame->color_space;
2282 sar_num = p_ni_frame->sar_width;
2283 sar_den = p_ni_frame->sar_height;
2284 video_full_range_flag = p_ni_frame->video_full_range_flag;
2285
2286 // calculate the source fps and set it as the default target fps, based
2287 // on the timing_info passed in from the decoded frame
2288 if (p_ni_frame->vui_num_units_in_tick && p_ni_frame->vui_time_scale)
2289 {
2290 if (NI_CODEC_FORMAT_H264 == p_ni_frame->src_codec)
2291 {
2292 if (0 == p_ni_frame->vui_time_scale % 2)
2293 {
2294 fps_num = (int)(p_ni_frame->vui_time_scale / 2);
2295 fps_den = (int)(p_ni_frame->vui_num_units_in_tick);
2296 } else
2297 {
2298 fps_num = (int)(p_ni_frame->vui_time_scale);
2299 fps_den = (int)(2 * p_ni_frame->vui_num_units_in_tick);
2300 }
2301 } else if (NI_CODEC_FORMAT_H265 == p_ni_frame->src_codec)
2302 {
2303 fps_num = p_ni_frame->vui_time_scale;
2304 fps_den = p_ni_frame->vui_num_units_in_tick;
2305 }
2306 }
2307 }
2308
2309 for (i = 0; i < output_total; i++)
2310 {
2311
2312 if(!p_ctx->enc_pts_queue[i])
2313 {
2314 p_ctx->enc_pts_queue[i] = (ni_pts_queue *)calloc(1, sizeof(ni_pts_queue));
2315 if(!p_ctx->enc_pts_queue[i])
2316 {
2317 ni_log(NI_LOG_ERROR, "Failed to allocate ni_pts_queue\n");
2318 return -1;
2319 }
2320 }
2321
2322 // set up encoder p_config, using some info from source
2323 ret = ni_encoder_init_default_params(&p_api_param_list[i], fps_num,
2324 fps_den, bitrate, width, height,
2325 enc_ctx_list[i].codec_format);
2326 if (ret < 0)
2327 {
2328 ni_log(NI_LOG_ERROR, "Error encoder[%d] init default set up error\n", i);
2329 return -1;
2330 }
2331
2332 // check and set ni_encoder_params from --xcoder-params
2333 // Note: the parameter setting has to be in this order so that user
2334 // configured values can overwrite the source/default ones if
2335 // desired.
2336 if (ni_retrieve_xcoder_params(p_enc_conf_params[i],
2337 &p_api_param_list[i], &enc_ctx_list[i]))
2338 {
2339 ni_log(NI_LOG_ERROR, "Error: encoder[%d] p_config parsing error\n", i);
2340 return -1;
2341 }
2342
2343 if (ni_retrieve_xcoder_gop(p_enc_conf_gop[i],
2344 &p_api_param_list[i], &enc_ctx_list[i]))
2345 {
2346 ni_log(NI_LOG_ERROR, "Error: encoder[%d] p_config_gop parsing error\n", i);
2347 return -1;
2348 }
2349
2350 // set async mode in enc_ctx if encoding is multi-threaded
2351 if (multi_thread)
2352 {
2353 ni_log(NI_LOG_INFO, "Encoder[%d] is multi-threaded, set async mode "
2354 "in the session context!\n", i);
2355 enc_ctx_list[i].async_mode = 1;
2356 p_api_param_list[i].cfg_enc_params.enable_acq_limit = 1;
2357 }
2358
2359 // check color primaries configuration
2360 if (color_prim != p_api_param_list[i].color_primaries &&
2361 NI_COL_PRI_UNSPECIFIED != p_api_param_list[i].color_primaries)
2362 {
2363 ni_log(NI_LOG_DEBUG, "Encoder[%d] user-configured color primaries "
2364 "%d to overwrite source %d\n",
2365 i, p_api_param_list[i].color_primaries, color_prim);
2366 color_prim = p_api_param_list[i].color_primaries;
2367 }
2368
2369 // check color transfer characteristic configuration
2370 if (color_trc != p_api_param_list[i].color_transfer_characteristic &&
2371 NI_COL_TRC_UNSPECIFIED != p_api_param_list[i].color_transfer_characteristic)
2372 {
2373 ni_log(NI_LOG_DEBUG, "Encoder[%d] user-configured color trc %d to "
2374 "overwrite source %d\n", i,
2375 p_api_param_list[i].color_transfer_characteristic, color_trc);
2376 color_trc = p_api_param_list[i].color_transfer_characteristic;
2377 }
2378
2379 // check color space configuration
2380 if (color_space != p_api_param_list[i].color_space &&
2381 NI_COL_SPC_UNSPECIFIED != p_api_param_list[i].color_space)
2382 {
2383 ni_log(NI_LOG_DEBUG, "Encoder[%d] user-configured color space %d "
2384 "to overwrite source %d\n",
2385 i, p_api_param_list[i].color_space, color_space);
2386 color_space = p_api_param_list[i].color_space;
2387 }
2388
2389 // check video full range flag configuration
2390 if (p_api_param_list[i].video_full_range_flag >= 0)
2391 {
2392 ni_log(NI_LOG_DEBUG, "Encoder[%d] user-configured video full range "
2393 "flag %d\n", i, p_api_param_list[i].video_full_range_flag);
2394 video_full_range_flag = p_api_param_list[i].video_full_range_flag;
2395 }
2396
2397 // check aspect ratio indicator configuration
2398 if (aspect_ratio_idc > 0 && aspect_ratio_idc < NI_NUM_PIXEL_ASPECT_RATIO)
2399 {
2400 sar_num = ni_h264_pixel_aspect_list[aspect_ratio_idc].num;
2401 sar_den = ni_h264_pixel_aspect_list[aspect_ratio_idc].den;
2402 } else if (p_api_param_list[i].sar_denom)
2403 {
2404 sar_num = p_api_param_list[i].sar_num;
2405 sar_den = p_api_param_list[i].sar_denom;
2406 }
2407
2408 // check hwframe configuration
2409 if (p_surface != NULL)
2410 {
2411 //Items in this else condition could be improved by being handled in libxcoder
2412 enc_ctx_list[i].hw_action = NI_CODEC_HW_ENABLE;
2413 p_api_param_list[i].hwframes = 1;
2414 enc_ctx_list[i].sender_handle =
2415 (ni_device_handle_t)(int64_t)p_surface->device_handle;
2416 p_api_param_list[i].rootBufId = p_surface->ui16FrameIdx;
2417 }
2418
2419 // VUI setting including color setting is done by specifying them in the
2420 // encoder config
2421 p_api_param_list[i].cfg_enc_params.colorDescPresent = 0;
2422 if ((color_prim != NI_COL_PRI_UNSPECIFIED) ||
2423 (color_space != NI_COL_SPC_UNSPECIFIED) ||
2424 (color_trc != NI_COL_TRC_UNSPECIFIED))
2425 {
2426 p_api_param_list[i].cfg_enc_params.colorDescPresent = 1;
2427 }
2428 p_api_param_list[i].cfg_enc_params.colorPrimaries = color_prim;
2429 p_api_param_list[i].cfg_enc_params.colorTrc = color_trc;
2430 p_api_param_list[i].cfg_enc_params.colorSpace = color_space;
2431 p_api_param_list[i].cfg_enc_params.videoFullRange = video_full_range_flag;
2432 p_api_param_list[i].cfg_enc_params.aspectRatioWidth = sar_num;
2433 p_api_param_list[i].cfg_enc_params.aspectRatioHeight = sar_den;
2434
2435 ret = encoder_open_session(&enc_ctx_list[i], codec_format, xcoder_guid,
2436 &p_api_param_list[i], width, height,
2437 pix_fmt, check_zerocopy);
2438 if (ret != 0)
2439 {
2440 ni_log(NI_LOG_ERROR, "Error encoder[%d] open session failed!\n", i);
2441 return -1;
2442 }
2443
2445 p_ctx->pts[i] = 0;
2446 ni_prepare_pts_queue(p_ctx->enc_pts_queue[i], &p_api_param_list[i], p_ctx->pts[i]);
2447 }
2448
2449 return ret;
2450}
2451
2452// encoder_open2() is used for the encoder with a scaler filter, supporting ladder encoding with multiple resolutions.
2454 ni_session_context_t *enc_ctx_list,
2455 ni_xcoder_params_t *p_api_param_list,
2456 int output_total, char p_enc_conf_params[][2048],
2457 char p_enc_conf_gop[][2048],
2458 ni_frame_t *p_ni_frame, int width[], int height[],
2459 int fps_num, int fps_den, int bitrate,
2460 int codec_format, ni_pix_fmt_t pix_fmt[],
2461 int aspect_ratio_idc, int xcoder_guid,
2462 niFrameSurface1_t *p_surface[], int multi_thread,
2463 bool check_zerocopy)
2464{
2465 int i, ret = 0;
2466 int color_prim = NI_COL_PRI_UNSPECIFIED;
2467 int color_trc = NI_COL_TRC_UNSPECIFIED;
2468 int color_space = NI_COL_SPC_UNSPECIFIED;
2469 int sar_num = 0;
2470 int sar_den = 0;
2471 int video_full_range_flag = 0;
2472
2473 if (p_ni_frame != NULL)
2474 {
2475 // open the encode session when the first frame arrives and the session
2476 // is not opened yet, with the source stream and user-configured encode
2477 // info both considered when constructing VUI in the stream headers
2478 color_prim = p_ni_frame->color_primaries;
2479 color_trc = p_ni_frame->color_trc;
2480 color_space = p_ni_frame->color_space;
2481 sar_num = p_ni_frame->sar_width;
2482 sar_den = p_ni_frame->sar_height;
2483 video_full_range_flag = p_ni_frame->video_full_range_flag;
2484
2485 // calculate the source fps and set it as the default target fps, based
2486 // on the timing_info passed in from the decoded frame
2487 if (p_ni_frame->vui_num_units_in_tick && p_ni_frame->vui_time_scale)
2488 {
2489 if (NI_CODEC_FORMAT_H264 == p_ni_frame->src_codec)
2490 {
2491 if (0 == p_ni_frame->vui_time_scale % 2)
2492 {
2493 fps_num = (int)(p_ni_frame->vui_time_scale / 2);
2494 fps_den = (int)(p_ni_frame->vui_num_units_in_tick);
2495 } else
2496 {
2497 fps_num = (int)(p_ni_frame->vui_time_scale);
2498 fps_den = (int)(2 * p_ni_frame->vui_num_units_in_tick);
2499 }
2500 } else if (NI_CODEC_FORMAT_H265 == p_ni_frame->src_codec)
2501 {
2502 fps_num = p_ni_frame->vui_time_scale;
2503 fps_den = p_ni_frame->vui_num_units_in_tick;
2504 }
2505 }
2506 }
2507
2508 for (i = 0; i < output_total; i++)
2509 {
2510
2511 if(!p_ctx->enc_pts_queue[i])
2512 {
2513 p_ctx->enc_pts_queue[i] = (ni_pts_queue *)calloc(1, sizeof(ni_pts_queue));
2514 if(!p_ctx->enc_pts_queue[i])
2515 {
2516 ni_log(NI_LOG_ERROR, "Failed to allocate ni_pts_queue\n");
2517 return -1;
2518 }
2519 }
2520
2521 // set up encoder p_config, using some info from source
2522 ret = ni_encoder_init_default_params(&p_api_param_list[i], fps_num,
2523 fps_den, bitrate, width[i], height[i],
2524 enc_ctx_list[i].codec_format);
2525 if (ret < 0)
2526 {
2527 ni_log(NI_LOG_ERROR, "Error encoder[%d] init default set up error\n", i);
2528 return -1;
2529 }
2530
2531 // check and set ni_encoder_params from --xcoder-params
2532 // Note: the parameter setting has to be in this order so that user
2533 // configured values can overwrite the source/default ones if
2534 // desired.
2535 if (ni_retrieve_xcoder_params(p_enc_conf_params[i],
2536 &p_api_param_list[i], &enc_ctx_list[i]))
2537 {
2538 ni_log(NI_LOG_ERROR, "Error: encoder[%d] p_config parsing error\n", i);
2539 return -1;
2540 }
2541
2542 if (ni_retrieve_xcoder_gop(p_enc_conf_gop[i],
2543 &p_api_param_list[i], &enc_ctx_list[i]))
2544 {
2545 ni_log(NI_LOG_ERROR, "Error: encoder[%d] p_config_gop parsing error\n", i);
2546 return -1;
2547 }
2548
2549 // set async mode in enc_ctx if encoding is multi-threaded
2550 if (multi_thread)
2551 {
2552 ni_log(NI_LOG_INFO, "Encoder[%d] is multi-threaded, set async mode "
2553 "in the session context!\n", i);
2554 enc_ctx_list[i].async_mode = 1;
2555 p_api_param_list[i].cfg_enc_params.enable_acq_limit = 1;
2556 }
2557
2558 // check color primaries configuration
2559 if (color_prim != p_api_param_list[i].color_primaries &&
2560 NI_COL_PRI_UNSPECIFIED != p_api_param_list[i].color_primaries)
2561 {
2562 ni_log(NI_LOG_DEBUG, "Encoder[%d] user-configured color primaries "
2563 "%d to overwrite source %d\n",
2564 i, p_api_param_list[i].color_primaries, color_prim);
2565 color_prim = p_api_param_list[i].color_primaries;
2566 }
2567
2568 // check color transfer characteristic configuration
2569 if (color_trc != p_api_param_list[i].color_transfer_characteristic &&
2570 NI_COL_TRC_UNSPECIFIED != p_api_param_list[i].color_transfer_characteristic)
2571 {
2572 ni_log(NI_LOG_DEBUG, "Encoder[%d] user-configured color trc %d to "
2573 "overwrite source %d\n", i,
2574 p_api_param_list[i].color_transfer_characteristic, color_trc);
2575 color_trc = p_api_param_list[i].color_transfer_characteristic;
2576 }
2577
2578 // check color space configuration
2579 if (color_space != p_api_param_list[i].color_space &&
2580 NI_COL_SPC_UNSPECIFIED != p_api_param_list[i].color_space)
2581 {
2582 ni_log(NI_LOG_DEBUG, "Encoder[%d] user-configured color space %d "
2583 "to overwrite source %d\n",
2584 i, p_api_param_list[i].color_space, color_space);
2585 color_space = p_api_param_list[i].color_space;
2586 }
2587
2588 // check video full range flag configuration
2589 if (p_api_param_list[i].video_full_range_flag >= 0)
2590 {
2591 ni_log(NI_LOG_DEBUG, "Encoder[%d] user-configured video full range "
2592 "flag %d\n", i, p_api_param_list[i].video_full_range_flag);
2593 video_full_range_flag = p_api_param_list[i].video_full_range_flag;
2594 }
2595
2596 // check aspect ratio indicator configuration
2597 if (aspect_ratio_idc > 0 && aspect_ratio_idc < NI_NUM_PIXEL_ASPECT_RATIO)
2598 {
2599 sar_num = ni_h264_pixel_aspect_list[aspect_ratio_idc].num;
2600 sar_den = ni_h264_pixel_aspect_list[aspect_ratio_idc].den;
2601 } else if (p_api_param_list[i].sar_denom)
2602 {
2603 sar_num = p_api_param_list[i].sar_num;
2604 sar_den = p_api_param_list[i].sar_denom;
2605 }
2606
2607 // check hwframe configuration
2608 if (p_surface[i] != NULL)
2609 {
2610 //Items in this else condition could be improved by being handled in libxcoder
2611 enc_ctx_list[i].hw_action = NI_CODEC_HW_ENABLE;
2612 p_api_param_list[i].hwframes = 1;
2613 enc_ctx_list[i].sender_handle =
2614 (ni_device_handle_t)(int64_t)p_surface[i]->device_handle;
2615 p_api_param_list[i].rootBufId = p_surface[i]->ui16FrameIdx;
2616 }
2617
2618 // VUI setting including color setting is done by specifying them in the
2619 // encoder config
2620 p_api_param_list[i].cfg_enc_params.colorDescPresent = 0;
2621 if ((color_prim != NI_COL_PRI_UNSPECIFIED) ||
2622 (color_space != NI_COL_SPC_UNSPECIFIED) ||
2623 (color_trc != NI_COL_TRC_UNSPECIFIED))
2624 {
2625 p_api_param_list[i].cfg_enc_params.colorDescPresent = 1;
2626 }
2627 p_api_param_list[i].cfg_enc_params.colorPrimaries = color_prim;
2628 p_api_param_list[i].cfg_enc_params.colorTrc = color_trc;
2629 p_api_param_list[i].cfg_enc_params.colorSpace = color_space;
2630 p_api_param_list[i].cfg_enc_params.videoFullRange = video_full_range_flag;
2631 p_api_param_list[i].cfg_enc_params.aspectRatioWidth = sar_num;
2632 p_api_param_list[i].cfg_enc_params.aspectRatioHeight = sar_den;
2633
2634 ret = encoder_open_session(&enc_ctx_list[i], codec_format, xcoder_guid,
2635 &p_api_param_list[i], width[i], height[i],
2636 pix_fmt[i], check_zerocopy);
2637 if (ret != 0)
2638 {
2639 ni_log(NI_LOG_ERROR, "Error encoder[%d] open session failed!\n", i);
2640 return -1;
2641 }
2642
2644 p_ctx->pts[i] = 0;
2645 ni_prepare_pts_queue(p_ctx->enc_pts_queue[i], &p_api_param_list[i], p_ctx->pts[i]);
2646 }
2647
2648 return ret;
2649}
2650
2652 ni_session_context_t *enc_ctx_list,
2653 ni_session_data_io_t *in_frame,
2654 ni_session_data_io_t *pkt, int width, int height,
2655 int output_total, FILE **pfs_list)
2656{
2657 int i, recycle_index;
2658 int recv_fin_flag = NI_TEST_RETCODE_SUCCESS;
2659 uint64_t prev_num_pkt[MAX_OUTPUT_FILES] = {0};
2660 ni_session_data_io_t *p_out_pkt = pkt;
2661
2662 for (i = 0; i < output_total; i++)
2663 {
2664 if (enc_ctx_list[i].codec_format == NI_CODEC_FORMAT_AV1)
2665 {
2666 p_out_pkt = &pkt[i];
2667 }
2668 p_out_pkt->data.packet.end_of_stream = 0;
2669 prev_num_pkt[i] = p_ctx->num_packets_received[i];
2670
2671 p_ctx->curr_enc_index = i;
2672 recv_fin_flag = encoder_receive_data(p_ctx, &enc_ctx_list[i], p_out_pkt, width,
2673 height, pfs_list[i], in_frame);
2674
2675 recycle_index = p_out_pkt->data.packet.recycle_index;
2676 if (prev_num_pkt[i] < p_ctx->num_packets_received[i] &&
2677 enc_ctx_list[i].hw_action && recycle_index > 0 &&
2678 recycle_index < NI_GET_MAX_HWDESC_FRAME_INDEX(enc_ctx_list[i].ddr_config))
2679 {
2680 //encoder only returns valid recycle index
2681 //when there's something to recycle.
2682 //This range is suitable for all memory bins
2683 ni_hw_frame_unref(recycle_index);
2684 } else
2685 {
2686 ni_log(NI_LOG_DEBUG, "enc %d recv, prev_num_pkt %llu "
2687 "number_of_packets_list %u recycle_index %u\n", i,
2688 prev_num_pkt[i], p_ctx->num_packets_received[i], recycle_index);
2689 }
2690
2691 if (prev_num_pkt[i] < p_ctx->num_packets_received[i] &&
2692 enc_ctx_list[i].codec_format == NI_CODEC_FORMAT_AV1 &&
2693 p_ctx->num_packets_received[i] > 1)
2694 {
2695 // For low delay mode encoding, only one packet is received for one
2696 // frame sent. For non low delay mode, there will be multiple
2697 // packets received for one frame sent. So we need to read out all
2698 // the packets encoded.
2699 ni_xcoder_params_t *p_api_param =
2700 (ni_xcoder_params_t *)enc_ctx_list[i].p_session_config;
2701 if (!p_api_param->low_delay_mode)
2702 {
2703 i--;
2704 continue;
2705 }
2706 }
2707
2708 p_ctx->enc_eos_received[i] = p_out_pkt->data.packet.end_of_stream;
2709
2710 if (recv_fin_flag < 0)
2711 {
2712 ni_log(NI_LOG_DEBUG, "enc %d error, quit !\n", i);
2713 break;
2714 } else if (recv_fin_flag == NI_TEST_RETCODE_EAGAIN)
2715 {
2716 ni_usleep(100);
2717 }
2718 }
2719
2720 return recv_fin_flag;
2721}
2722
2723// encoder_receive2() is used for the encoder with a scaler filter, supporting ladder encoding with multiple resolutions.
2725 ni_session_context_t *enc_ctx_list,
2726 ni_session_data_io_t *in_frame,
2727 ni_session_data_io_t *pkt, int width[], int height[],
2728 int output_total, FILE **pfs_list)
2729{
2730 int i, recycle_index;
2731 int recv_fin_flag = NI_TEST_RETCODE_SUCCESS;
2732 uint64_t prev_num_pkt[MAX_OUTPUT_FILES] = {0};
2733 ni_session_data_io_t *p_out_pkt = pkt;
2734
2735 for (i = 0; i < output_total; i++)
2736 {
2737 if (enc_ctx_list[i].codec_format == NI_CODEC_FORMAT_AV1)
2738 {
2739 p_out_pkt = &pkt[i];
2740 }
2741 p_out_pkt->data.packet.end_of_stream = 0;
2742 prev_num_pkt[i] = p_ctx->num_packets_received[i];
2743
2744 p_ctx->curr_enc_index = i;
2745 recv_fin_flag = encoder_receive_data(p_ctx, &enc_ctx_list[i], p_out_pkt, width[i],
2746 height[i], pfs_list[i], in_frame);
2747
2748 recycle_index = p_out_pkt->data.packet.recycle_index;
2749 if (prev_num_pkt[i] < p_ctx->num_packets_received[i] &&
2750 enc_ctx_list[i].hw_action && recycle_index > 0 &&
2751 recycle_index < NI_GET_MAX_HWDESC_FRAME_INDEX(enc_ctx_list[i].ddr_config))
2752 {
2753 //encoder only returns valid recycle index
2754 //when there's something to recycle.
2755 //This range is suitable for all memory bins
2756 ni_hw_frame_unref(recycle_index);
2757 } else
2758 {
2759 ni_log(NI_LOG_DEBUG, "enc %d recv, prev_num_pkt %llu "
2760 "number_of_packets_list %u recycle_index %u\n", i,
2761 prev_num_pkt[i], p_ctx->num_packets_received[i], recycle_index);
2762 }
2763
2764 if (prev_num_pkt[i] < p_ctx->num_packets_received[i] &&
2765 enc_ctx_list[i].codec_format == NI_CODEC_FORMAT_AV1 &&
2766 p_ctx->num_packets_received[i] > 1)
2767 {
2768 // For low delay mode encoding, only one packet is received for one
2769 // frame sent. For non low delay mode, there will be multiple
2770 // packets received for one frame sent. So we need to read out all
2771 // the packets encoded.
2772 ni_xcoder_params_t *p_api_param =
2773 (ni_xcoder_params_t *)enc_ctx_list[i].p_session_config;
2774 if (!p_api_param->low_delay_mode)
2775 {
2776 i--;
2777 continue;
2778 }
2779 }
2780
2781 p_ctx->enc_eos_received[i] = p_out_pkt->data.packet.end_of_stream;
2782
2783 if (recv_fin_flag < 0)
2784 {
2785 ni_log(NI_LOG_DEBUG, "enc %d error, quit !\n", i);
2786 break;
2787 } else if (recv_fin_flag == NI_TEST_RETCODE_EAGAIN)
2788 {
2789 ni_usleep(100);
2790 }
2791 }
2792
2793 return recv_fin_flag;
2794}
2795
2796void encoder_stat_report_and_close(ni_demo_context_t *p_ctx, ni_session_context_t *p_enc_ctx_list, int output_total)
2797{
2798 int i;
2799 int nb_recycled;
2800 uint64_t current_time;
2801
2803
2804 nb_recycled = scan_and_clean_hwdescriptors();
2805
2806 for (i = 0; i < output_total; i++)
2807 {
2808 if (p_ctx)
2809 {
2810 ni_log(NI_LOG_ERROR, "Encoder %d closing, Got: Packets=%u FPS=%.2f Total bytes %llu\n",
2811 (int)i, p_ctx->num_packets_received[i],
2812 (float)p_enc_ctx_list[i].frame_num / (float)(current_time - p_ctx->start_time) * (float)1000000000,
2813 p_ctx->enc_total_bytes_received[i]);
2814 }
2815 ni_device_session_close(&p_enc_ctx_list[i], 1, NI_DEVICE_TYPE_ENCODER);
2816 }
2817
2818 ni_log(NI_LOG_DEBUG, "Cleanup recycled %d internal buffers\n",
2819 nb_recycled);
2820}
2821
2822void *encoder_send_thread(void *args)
2823{
2824 enc_send_param_t *p_enc_send_param = args;
2825 ni_demo_context_t *p_ctx = p_enc_send_param->p_ctx;
2826 ni_session_context_t *p_enc_ctx_list = p_enc_send_param->p_enc_ctx;
2827 ni_test_frame_list_t *frame_list = p_enc_send_param->frame_list;
2828 ni_session_data_io_t *p_dec_frame = NULL;
2829 ni_session_data_io_t enc_in_frame = {0};
2830 ni_frame_t *p_ni_frame = NULL;
2831 niFrameSurface1_t *p_surface;
2832 int i, ret = 0;
2833
2834 ni_log(NI_LOG_INFO, "%s start\n", __func__);
2835
2836 for (;;)
2837 {
2838 while (frame_list_is_empty(frame_list) && !p_ctx->end_all_threads)
2839 {
2840 ni_usleep(100);
2841 }
2842
2843 if (p_ctx->end_all_threads)
2844 {
2845 break;
2846 }
2847
2848 p_dec_frame = &frame_list->frames[frame_list->head];
2849 p_ni_frame = &p_dec_frame->data.frame;
2850
2851 for (i = 0; i < p_enc_send_param->output_total; i++)
2852 {
2853 p_ctx->curr_enc_index = i;
2854 ret = encoder_send_data2(p_ctx, &p_enc_ctx_list[i], p_dec_frame,
2855 &enc_in_frame,
2856 p_enc_send_param->output_width,
2857 p_enc_send_param->output_height);
2858 if (ret < 0) //Error
2859 {
2860 if (p_enc_ctx_list[i].hw_action)
2861 {
2862 //pre close cleanup will clear it out
2863 p_surface = (niFrameSurface1_t *)p_ni_frame->p_data[3];
2864 ni_hw_frame_ref(p_surface);
2865 } else
2866 {
2867 ni_decoder_frame_buffer_free(p_ni_frame);
2868 }
2869 frame_list_drain(frame_list);
2870 ni_log(NI_LOG_ERROR, "Error: encoder send frame failed\n");
2871 break;
2872 } else if (ret == NI_TEST_RETCODE_EAGAIN) {
2873 ni_usleep(100);
2874 i--; //resend frame
2875 continue;
2876 } else if (p_enc_ctx_list[0].hw_action && !p_ctx->enc_eos_sent[i])
2877 {
2878 p_surface = (niFrameSurface1_t *)p_ni_frame->p_data[3];
2879 ni_hw_frame_ref(p_surface);
2880 }
2881 }
2882
2883 if (ret < 0)
2884 {
2885 break;
2886 } else if (p_enc_ctx_list[0].hw_action)
2887 {
2888 ni_frame_wipe_aux_data(p_ni_frame); //reuse buffer
2889 } else
2890 {
2891 ni_decoder_frame_buffer_free(p_ni_frame);
2892 }
2893 frame_list_drain(frame_list);
2894
2895 if (p_enc_send_param->p_ctx->enc_eos_sent[0]) // eos
2896 {
2897 ni_log(NI_LOG_INFO, "%s EOS sent\n", __func__);
2898 break;
2899 }
2900 }
2901
2902 ni_frame_buffer_free(&enc_in_frame.data.frame);
2903
2904 // Broadcast all codec threads to quit on exception such as NVMe IO
2905 if (ret < 0)
2906 {
2907 p_ctx->end_all_threads = 1;
2908 }
2909
2910 ni_log(NI_LOG_TRACE, "%s exit\n", __func__);
2911 return (void *)(int64_t)ret;
2912}
2913
2914void *encoder_receive_thread(void *args)
2915{
2916 enc_recv_param_t *p_enc_recv_param = args;
2917 ni_demo_context_t *p_ctx = p_enc_recv_param->p_ctx;
2918 ni_session_context_t *p_enc_ctx = p_enc_recv_param->p_enc_ctx;
2919 ni_session_data_io_t out_packet[MAX_OUTPUT_FILES] = {0};
2920 int i, ret = 0;
2921 int end_of_all_streams = 0;
2922 uint64_t current_time, previous_time = p_ctx->start_time;
2923
2924 ni_log(NI_LOG_INFO, "encoder_receive_thread start\n");
2925
2926 while (!end_of_all_streams && ret >= 0 && !p_ctx->end_all_threads)
2927 {
2928 ret = encoder_receive(p_ctx, p_enc_ctx,
2929 &p_enc_recv_param->frame_list->frames[p_enc_recv_param->frame_list->head],
2930 out_packet, p_enc_recv_param->output_width,
2931 p_enc_recv_param->output_height, p_enc_recv_param->output_total,
2932 p_enc_recv_param->p_file);
2933 for (i = 0; ret >= 0 && i < p_enc_recv_param->output_total; i++)
2934 {
2935 if (!p_ctx->enc_eos_received[i])
2936 {
2937 ni_log(NI_LOG_DEBUG, "enc %d continues to read!\n", i);
2938 end_of_all_streams = 0;
2939 break;
2940 } else
2941 {
2942 ni_log(NI_LOG_DEBUG, "enc %d eos !\n", i);
2943 end_of_all_streams = 1;
2944 }
2945 }
2946
2948 if (current_time - previous_time >= (uint64_t)1000000000) {
2949 for (i = 0; i < p_enc_recv_param->output_total; i++)
2950 {
2951 ni_log(NI_LOG_INFO, "Encoder %d stats: received %u packets, fps %.2f, total bytes %u\n",
2952 i, p_ctx->num_packets_received[i],
2953 (float)p_enc_ctx[i].frame_num / (float)(current_time - p_ctx->start_time) * (float)1000000000,
2954 p_ctx->enc_total_bytes_received[i]);
2955 }
2957 }
2958 }
2959
2960 for (i = 0; i < p_enc_recv_param->output_total; i++)
2961 {
2962 ni_packet_buffer_free(&out_packet[i].data.packet);
2963 }
2964
2965 // Broadcast all codec threads to quit on exception such as NVMe IO.
2966 if (ret < 0)
2967 {
2968 p_ctx->end_all_threads = 1;
2969 }
2970
2971 ni_log(NI_LOG_TRACE, "%s exit\n", __func__);
2972 return (void *)(int64_t)ret;
2973}
2974
2976{
2977 q->front = 0;
2978 q->rear = 0;
2979 q->size = 0;
2980}
2982{
2983 return q->size == 0;
2984}
2986{
2987 return q->size == NI_MAX_PTS_QUEUE_SIZE;
2988}
2989int ni_pts_enqueue(ni_pts_queue *q, int64_t value)
2990{
2991 if(ni_pts_queue_full(q))
2992 {
2993 ni_log(NI_LOG_ERROR, "Failed to enqueue, ni_pts_queue is full\n");
2994 return 0;
2995 }
2996
2997 q->data[q->rear] = value;
2998 q->rear = (q->rear + 1) % NI_MAX_PTS_QUEUE_SIZE;
2999 ++q->size;
3000 return 1;
3001}
3002int ni_pts_dequeue(ni_pts_queue *q, int64_t *value)
3003{
3004 if(ni_pts_queue_empty(q))
3005 {
3006 ni_log(NI_LOG_ERROR, "Failed to dequeue, ni_pts_queue is empty\n");
3007 }
3008 *value = q->data[q->front];
3009 q->front = (q->front + 1) % NI_MAX_PTS_QUEUE_SIZE;
3010 --q->size;
3011 return 1;
3012}
3013
3014void ni_prepare_pts_queue(ni_pts_queue *q, ni_xcoder_params_t *enc_param, int pts_start)
3015{
3016 int dtsOffset = 0;
3017
3018 switch (enc_param->cfg_enc_params.gop_preset_index)
3019 {
3020 /* dtsOffset is the max number of non-reference frames in a GOP
3021 * (derived from x264/5 algo) In case of IBBBP the first dts of the I
3022 * frame should be input_pts-(3*ticks_per_frame) In case of IBP the
3023 * first dts of the I frame should be input_pts-(1*ticks_per_frame)
3024 * thus we ensure pts>dts in all cases
3025 * */
3026 case 1:
3027 case 9:
3028 case 10:
3029 dtsOffset = 0;
3030 break;
3031 /* ts requires dts/pts of I fraem not same when there are B frames in
3032 * streams */
3033 case 3:
3034 case 4:
3035 case 7:
3036 dtsOffset = 1;
3037 break;
3038 case 5:
3039 dtsOffset = 2;
3040 break;
3041 case -1: // adaptive GOP
3042 case 8:
3043 dtsOffset = 3;
3044 break;
3045 default:
3046 dtsOffset = 7;
3047 break;
3048 }
3049
3051 {
3052 int dts_offset;
3053 dtsOffset = 0;
3054 int has_b_frame = 0;
3055 for (int idx = 0;
3057 idx++)
3058 {
3059 if (enc_param->cfg_enc_params.custom_gop_params.pic_param[idx].poc_offset < idx + 1)
3060 {
3061 dts_offset = (idx + 1) - enc_param->cfg_enc_params.custom_gop_params.pic_param[idx].poc_offset;
3062 if (dtsOffset < dts_offset)
3063 {
3064 dtsOffset = dts_offset;
3065 }
3066 }
3067
3068 if (!has_b_frame &&
3070 {
3071 has_b_frame = 1;
3072 }
3073 }
3074
3075 if (has_b_frame && !dtsOffset)
3076 {
3077 dtsOffset = 1;
3078 }
3079 }
3080
3081 for (int i = 0; i < dtsOffset; ++i)
3082 {
3083 ni_pts_enqueue(q, i - dtsOffset + pts_start);
3084 }
3085}
3086
3087
3088// write bitstream features to log file
3089void ni_write_bitstream_features(ni_session_context_t *p_enc_ctx, ni_packet_t *p_out_pkt, FILE *p_file)
3090{
3092 int video_codec_id = VODEO_CODEC_ID_H264;
3093 int profile = H264_CODEC_PROFILE_MAIN;
3094
3095 if (!p_enc_ctx || !p_out_pkt || !p_file || !p_enc_ctx->p_session_config ||
3096 !(((ni_xcoder_params_t *)(p_enc_ctx->p_session_config))->cfg_enc_params.getBitstreamFeatures))
3097 {
3098 return;
3099 }
3100
3105
3106 video_codec_id = (p_enc_ctx->codec_format == NI_CODEC_FORMAT_H264) ? VODEO_CODEC_ID_H264 :
3109
3110 profile = ((ni_xcoder_params_t *)(p_enc_ctx->p_session_config))->cfg_enc_params.profile;
3111
3112 switch (video_codec_id)
3113 {
3119 break;
3121 profile = (profile == NI_QUADRA_HEVC_PROFILE_MAIN) ? HEVC_CODEC_PROFILE_MAIN :
3123 break;
3124 case VODEO_CODEC_ID_AV1:
3125 profile = (profile == NI_QUADRA_AV1_PROFILE_MAIN) ? AV1_CODEC_PROFILE_MAIN : 0;
3126 break;
3127 default:
3128 profile = 0;
3129 break;
3130 }
3131
3132
3133 int frame_size = (p_enc_ctx->pkt_num == 2) ? p_enc_ctx->headers_length + p_out_pkt->data_len - p_enc_ctx->meta_size : p_out_pkt->data_len - p_enc_ctx->meta_size;
3134 int quality_pixel_count = p_enc_ctx->actual_video_width * p_enc_ctx->active_video_height;
3135 ni_bitstream_features_t *bitstream_features = &p_out_pkt->bitstream_features;
3136
3137 ni_log2(p_enc_ctx, NI_LOG_TRACE, "%s: pkt #%" PRId64 " Bitstream Features - "
3138 "Av_QP: f=%.6f FrameSize: i32=%d InitialQP: i32=%d max_QP: i32=%d MbQPs_1_: f=%.6f "
3139 "FrameType: i32=%d Sec_Codec: i32=%d Seq_Profile: i32=%d "
3140 "MbQPs_5_: f=%.6f MbQPs_6_: f=%.6f AnalyzedMBs: i32=%d "
3141 "MbTypes_5_: i32=%d MbTypes_6_: i32=%d MbTypes_0_: i32=%d MbTypes_1_: i32=%d "
3142 "quality_pixel_count: i32=%d\n",
3143 __func__, p_enc_ctx->pkt_num,
3144 bitstream_features->average_qp, frame_size,
3145 bitstream_features->initial_qp, bitstream_features->max_qp, bitstream_features->avg_forward_pred_block_qp,
3146 itu_frame_type, video_codec_id, profile,
3147 bitstream_features->avg_intra_block_qp, bitstream_features->avg_intra_plane_qp, bitstream_features->analyzed_mbs,
3148 bitstream_features->num_intra_block_blocks, bitstream_features->num_intra_plane_blocks, bitstream_features->num_skip_blocks, bitstream_features->num_forward_pred_blocks,
3149 quality_pixel_count);
3150
3151 fprintf(p_file,
3152 "Av_QP: f=%.6f FrameSize: i32=%d InitialQP: i32=%d max_QP: i32=%d MbQPs_1_: f=%.6f "
3153 "FrameType: i32=%d Sec_Codec: i32=%d Seq_Profile: i32=%d "
3154 "MbQPs_5_: f=%.6f MbQPs_6_: f=%.6f AnalyzedMBs: i32=%d "
3155 "MbTypes_5_: i32=%d MbTypes_6_: i32=%d MbTypes_0_: i32=%d MbTypes_1_: i32=%d "
3156 "quality_pixel_count: i32=%d\n",
3157 bitstream_features->average_qp, frame_size,
3158 bitstream_features->initial_qp, bitstream_features->max_qp, bitstream_features->avg_forward_pred_block_qp,
3159 itu_frame_type, video_codec_id, profile,
3160 bitstream_features->avg_intra_block_qp, bitstream_features->avg_intra_plane_qp, bitstream_features->analyzed_mbs,
3161 bitstream_features->num_intra_block_blocks, bitstream_features->num_intra_plane_blocks, bitstream_features->num_skip_blocks, bitstream_features->num_forward_pred_blocks,
3162 quality_pixel_count);
3163}
int ni_should_send_sei_with_frame(ni_session_context_t *p_enc_ctx, ni_pic_type_t pic_type, ni_xcoder_params_t *p_param)
Whether SEI (HDR) should be sent together with this frame to encoder.
void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, ni_frame_t *p_enc_frame, ni_frame_t *p_dec_frame, ni_codec_format_t codec_format, int should_send_sei_with_frame, uint8_t *mdcv_data, uint8_t *cll_data, uint8_t *cc_data, uint8_t *udu_data, uint8_t *hdrp_data)
Prepare auxiliary data that should be sent together with this frame to encoder based on the auxiliary...
int ni_enc_write_from_yuv_buffer(ni_session_context_t *p_ctx, ni_frame_t *p_enc_frame, uint8_t *p_yuv_buffer)
Send an input data frame to the encoder with YUV data given in the inputs.
void ni_enc_copy_aux_data(ni_session_context_t *p_enc_ctx, ni_frame_t *p_enc_frame, ni_frame_t *p_dec_frame, ni_codec_format_t codec_format, const uint8_t *mdcv_data, const uint8_t *cll_data, const uint8_t *cc_data, const uint8_t *udu_data, const uint8_t *hdrp_data, int is_hwframe, int is_semiplanar)
Copy auxiliary data that should be sent together with this frame to encoder.
Audio/video related utility definitions.
@ NI_COL_TRC_UNSPECIFIED
@ NI_COL_SPC_UNSPECIFIED
@ NI_COL_PRI_UNSPECIFIED
Definition ni_av_codec.h:99
#define NI_NUM_PIXEL_ASPECT_RATIO
Definition ni_av_codec.h:38
#define NI_MAX_NUM_DATA_POINTERS
Definition ni_defs.h:244
#define NI_GET_MAX_HWDESC_FRAME_INDEX(x)
Definition ni_defs.h:292
#define MAX_AV1_ENCODER_GOP_NUM
Definition ni_defs.h:327
#define NI_APP_ENC_FRAME_META_DATA_SIZE
Definition ni_defs.h:322
@ NI_DEVICE_TYPE_ENCODER
Definition ni_defs.h:361
#define NI_MAX_TX_SZ
Definition ni_defs.h:261
ni_retcode_t
Definition ni_defs.h:447
@ NI_RETCODE_SUCCESS
Definition ni_defs.h:448
ni_retcode_t ni_device_session_flush(ni_session_context_t *p_ctx, ni_device_type_t device_type)
Send a flush command to the device If device_type is NI_DEVICE_TYPE_DECODER sends EOS command to deco...
ni_aux_data_t * ni_frame_new_aux_data(ni_frame_t *frame, ni_aux_data_type_t type, int data_size)
Add a new auxiliary data to a frame.
ni_retcode_t ni_reconfig_max_frame_size_ratio(ni_session_context_t *p_ctx, int32_t max_frame_size_ratio)
Reconfigure maxFrameSizeRatio dynamically during encoding.
void ni_frame_wipe_aux_data(ni_frame_t *frame)
Free and remove all auxiliary data from the frame.
ni_retcode_t ni_reconfig_intraprd(ni_session_context_t *p_ctx, int32_t intra_period)
Reconfigure intraPeriod dynamically during encoding.
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_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...
ni_retcode_t ni_device_session_open(ni_session_context_t *p_ctx, ni_device_type_t device_type)
Open a new device session depending on the device_type parameter If device_type is NI_DEVICE_TYPE_DEC...
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_encoder_frame_zerocopy_check(ni_session_context_t *p_enc_ctx, ni_xcoder_params_t *p_enc_params, int width, int height, const int linesize[], bool set_linesize)
Check if incoming frame is encoder zero copy compatible or not.
ni_retcode_t ni_encoder_init_default_params(ni_xcoder_params_t *p_param, int fps_num, int fps_denom, long bit_rate, int width, int height, ni_codec_format_t codec_format)
Initialize default encoder parameters.
int ni_device_session_read(ni_session_context_t *p_ctx, ni_session_data_io_t *p_data, ni_device_type_t device_type)
Read data from the device If device_type is NI_DEVICE_TYPE_DECODER reads data packet from decoder If ...
ni_retcode_t ni_set_ltr(ni_session_context_t *p_ctx, ni_long_term_ref_t *ltr)
Set a frame's support of Long Term Reference frame during encoding.
ni_retcode_t ni_reconfig_max_frame_size(ni_session_context_t *p_ctx, int32_t max_frame_size)
Reconfigure maxFrameSize dynamically during encoding.
ni_retcode_t ni_device_session_sequence_change(ni_session_context_t *p_ctx, int width, int height, int bit_depth_factor, ni_device_type_t device_type)
Send sequence change information to device.
ni_retcode_t ni_set_ltr_interval(ni_session_context_t *p_ctx, int32_t ltr_interval)
Set Long Term Reference interval.
ni_retcode_t ni_reconfig_min_max_qp(ni_session_context_t *p_ctx, ni_rc_min_max_qp *p_min_max_qp)
Reconfigure min&max qp dynamically during encoding.
ni_retcode_t ni_force_idr_frame_type(ni_session_context_t *p_ctx)
Force next frame to be IDR frame during encoding.
ni_retcode_t ni_reconfig_framerate(ni_session_context_t *p_ctx, ni_framerate_t *framerate)
Reconfigure framerate dynamically during encoding.
ni_retcode_t ni_reconfig_crf(ni_session_context_t *p_ctx, int32_t crf)
Reconfigure crf value dynamically during encoding.
ni_retcode_t ni_device_session_restart(ni_session_context_t *p_ctx, int video_width, int video_height, ni_device_type_t device_type)
Send a restart command after flush command Only support Encoder now.
ni_retcode_t ni_reconfig_vbv_value(ni_session_context_t *p_ctx, int32_t vbvMaxRate, int32_t vbvBufferSize)
Reconfigure vbv buffer size and vbv max rate dynamically during encoding.
ni_retcode_t ni_reconfig_crf2(ni_session_context_t *p_ctx, float crf)
Reconfigure crf float point value dynamically during encoding.
ni_retcode_t ni_set_frame_ref_invalid(ni_session_context_t *p_ctx, int32_t frame_num)
Set frame reference invalidation.
void ni_device_close(ni_device_handle_t device_handle)
Close device and release resources.
ni_retcode_t ni_frame_buffer_alloc_hwenc(ni_frame_t *p_frame, int video_width, int video_height, int extra_len)
Allocate memory for the hwDescriptor buffer based on provided parameters taking into account pic size...
ni_retcode_t ni_reconfig_slice_arg(ni_session_context_t *p_ctx, int16_t sliceArg)
Reconfigure sliceArg dynamically during encoding.
ni_retcode_t ni_encoder_sw_frame_buffer_alloc(bool planar, ni_frame_t *p_frame, int video_width, int video_height, int linesize[], int alignment, int extra_len, bool alignment_2pass_wa)
This API is a wrapper for ni_encoder_frame_buffer_alloc(), used for planar pixel formats,...
ni_retcode_t ni_packet_buffer_alloc(ni_packet_t *p_packet, int packet_size)
Allocate memory for the packet buffer based on provided packet size.
ni_retcode_t ni_packet_buffer_free_av1(ni_packet_t *p_packet)
Free packet buffer that was previously allocated with ni_packet_buffer_alloc for AV1 packets merge.
ni_retcode_t ni_reconfig_vui(ni_session_context_t *p_ctx, ni_vui_hrd_t *vui)
Reconfigure VUI HRD dynamically during encoding.
ni_retcode_t ni_reconfig_bitrate(ni_session_context_t *p_ctx, int32_t bitrate)
Reconfigure bitrate dynamically during encoding.
int ni_device_session_write(ni_session_context_t *p_ctx, ni_session_data_io_t *p_data, ni_device_type_t device_type)
Sends data to the device If device_type is NI_DEVICE_TYPE_DECODER sends data packet to decoder If dev...
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 NI_MIN_HEIGHT
@ SESSION_RUN_STATE_NORMAL
@ SESSION_RUN_STATE_SEQ_CHANGE_OPENING
@ SESSION_RUN_STATE_SEQ_CHANGE_DRAINING
@ SESSION_RUN_STATE_FLUSHING
@ AV1_CODEC_PROFILE_MAIN
#define NI_MULTICORE_ENCODE_MIN_WIDTH
@ XCODER_TEST_RECONF_MAX_FRAME_SIZE_RATIO
@ XCODER_TEST_RECONF_VBV_API
@ XCODER_TEST_RECONF_FRAMERATE_API
@ XCODER_TEST_RECONF_RC_MIN_MAX_QP_API
@ XCODER_TEST_RECONF_FRAMERATE
@ XCODER_TEST_RECONF_MAX_FRAME_SIZE
@ XCODER_TEST_RECONF_CRF_FLOAT
@ XCODER_TEST_RECONF_LTR_INTERVAL_API
@ XCODER_TEST_RECONF_SLICE_ARG
@ XCODER_TEST_RECONF_VUI_HRD
@ XCODER_TEST_CRF_API
@ XCODER_TEST_RECONF_LTR_INTERVAL
@ XCODER_TEST_RECONF_LTR_API
@ XCODER_TEST_RECONF_INTRAPRD
@ XCODER_TEST_RECONF_SLICE_ARG_API
@ XCODER_TEST_RECONF_RC_MIN_MAX_QP
@ XCODER_TEST_CRF_FLOAT_API
@ XCODER_TEST_RECONF_VUI_HRD_API
@ XCODER_TEST_FORCE_IDR_FRAME
@ XCODER_TEST_RECONF_BR_API
@ XCODER_TEST_RECONF_LTR_INVALID_REF
@ XCODER_TEST_RECONF_MAX_FRAME_SIZE_API
@ XCODER_TEST_RECONF_LONG_TERM_REF
@ XCODER_TEST_RECONF_MAX_FRAME_SIZE_RATIO_API
@ XCODER_TEST_RECONF_BR
@ XCODER_TEST_RECONF_RC_MIN_MAX_QP_REDUNDANT
@ XCODER_TEST_RECONF_CRF
@ XCODER_TEST_INVALID_REF_FRAME_API
@ XCODER_TEST_INVALID_REF_FRAME
@ XCODER_TEST_RECONF_VBV
@ XCODER_TEST_RECONF_INTRAPRD_API
@ XCODER_TEST_RECONF_RC_MIN_MAX_QP_API_REDUNDANT
@ XCODER_TEST_RECONF_LTR_INVALID_REF_API
@ XCODER_TEST_RECONF_OFF
#define NI_MIN_WIDTH
@ NI_QUADRA_PREDICTED_FRAME
@ NI_QUADRA_PIC_TYPE_IDR
@ NI_QUADRA_BIDIR_PREDICTED_FRAME
@ NI_QUADRA_INTRA_FRAME
@ NI_PIXEL_PLANAR_FORMAT_SEMIPLANAR
#define NI_MAX_SEI_DATA
#define NI_MAX_FRAME_SIZE
struct _ni_encoder_change_params_t ni_encoder_change_params_t
This is a data structure for encoding parameters that have changed.
@ NI_FRAME_AUX_DATA_BITRATE
@ NI_FRAME_AUX_DATA_SLICE_ARG
@ NI_FRAME_AUX_DATA_CRF_FLOAT
@ NI_FRAME_AUX_DATA_MAX_MIN_QP
@ NI_FRAME_AUX_DATA_FRAMERATE
@ NI_FRAME_AUX_DATA_LTR_INTERVAL
@ NI_FRAME_AUX_DATA_VBV_MAX_RATE
@ NI_FRAME_AUX_DATA_INTRAPRD
@ NI_FRAME_AUX_DATA_CRF
@ NI_FRAME_AUX_DATA_MAX_FRAME_SIZE
@ NI_FRAME_AUX_DATA_INVALID_REF_FRAME
@ NI_FRAME_AUX_DATA_LONG_TERM_REF
@ NI_FRAME_AUX_DATA_VBV_BUFFER_SIZE
#define NI_FRAME_LITTLE_ENDIAN
#define NI_2PASS_ENCODE_MIN_HEIGHT
#define NI_2PASS_ENCODE_MIN_WIDTH
@ H264_CODEC_PROFILE_EXTENDED
@ H264_CODEC_PROFILE_HIGH
@ H264_CODEC_PROFILE_BASELINE
@ H264_CODEC_PROFILE_MAIN
#define NI_PARAM_AV1_ALIGN_WIDTH_HEIGHT
#define NI_INVALID_SESSION_ID
@ HEVC_CODEC_PROFILE_MAIN10
@ HEVC_CODEC_PROFILE_MAIN
@ VODEO_CODEC_ID_HEVC
@ VODEO_CODEC_ID_H264
@ VODEO_CODEC_ID_AV1
@ NI_QUADRA_AV1_PROFILE_MAIN
@ NI_CODEC_HW_NONE
@ NI_CODEC_HW_ENABLE
@ NI_CODEC_FORMAT_H265
@ NI_CODEC_FORMAT_AV1
@ NI_CODEC_FORMAT_H264
@ NI_CODEC_FORMAT_JPEG
ni_pix_fmt_t
@ NI_PIX_FMT_ARGB
@ NI_PIX_FMT_P010LE
@ NI_PIX_FMT_YUV420P
@ NI_PIX_FMT_ABGR
@ NI_PIX_FMT_RGBA
@ NI_PIX_FMT_NV12
@ NI_PIX_FMT_BGRA
@ NI_PIX_FMT_YUV420P10LE
@ PIC_TYPE_B
itu_frame_type
@ ITU_FRAME_TYPE_NONE
@ ITU_FRAME_TYPE_B
@ ITU_FRAME_TYPE_P
@ ITU_FRAME_TYPE_I
@ NI_QUADRA_HEVC_PROFILE_MAIN
@ NI_QUADRA_HEVC_PROFILE_MAIN10
#define NI_MULTICORE_ENCODE_MIN_HEIGHT
@ NI_SET_CHANGE_PARAM_VUI_HRD_PARAM
@ NI_QUADRA_H264_PROFILE_BASELINE
@ NI_QUADRA_H264_PROFILE_HIGH
@ NI_QUADRA_H264_PROFILE_MAIN
@ NI_QUADRA_H264_PROFILE_EXTENDED
int encoder_close_session(ni_session_context_t *p_enc_ctx, ni_session_data_io_t *p_in_data, ni_session_data_io_t *p_out_data)
encoder session close
int ni_pts_queue_full(ni_pts_queue *q)
int encoder_reinit_session(ni_session_context_t *p_enc_ctx, ni_session_data_io_t *p_in_data, ni_session_data_io_t *p_out_data)
Reopen or reconfig encoder upon sequence change.
void ni_write_bitstream_features(ni_session_context_t *p_enc_ctx, ni_packet_t *p_out_pkt, FILE *p_file)
void ni_init_pts_queue(ni_pts_queue *q)
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)
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_sequence_change(ni_session_context_t *p_enc_ctx, ni_session_data_io_t *p_in_data, ni_session_data_io_t *p_out_data, int width, int height, ni_pix_fmt_t pix_fmt)
void prep_reconf_demo_data(ni_demo_context_t *p_ctx, ni_session_context_t *p_enc_ctx, ni_frame_t *frame)
void write_av1_ivf_header(ni_demo_context_t *p_ctx, uint32_t width, uint32_t height, uint32_t frame_num, uint32_t frame_denom, FILE *p_file)
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)
int ni_pts_dequeue(ni_pts_queue *q, int64_t *value)
int ni_pts_queue_empty(ni_pts_queue *q)
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)
int ni_pts_enqueue(ni_pts_queue *q, int64_t value)
int encoder_receive_data(ni_demo_context_t *p_ctx, ni_session_context_t *p_enc_ctx, ni_session_data_io_t *p_out_data, int output_video_width, int output_video_height, FILE *p_file, ni_session_data_io_t *p_in_data)
Receive output data from encoder.
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.
void * encoder_receive_thread(void *args)
int encoder_open_session(ni_session_context_t *p_enc_ctx, int dst_codec_format, int iXcoderGUID, ni_xcoder_params_t *p_enc_params, int width, int height, ni_pix_fmt_t pix_fmt, bool check_zerocopy)
Encoder session open.
int write_av1_ivf_trailer(ni_demo_context_t *p_ctx, ni_packet_t *p_out_pkt, uint32_t meta_size, FILE *p_file)
void encoder_stat_report_and_close(ni_demo_context_t *p_ctx, ni_session_context_t *p_enc_ctx_list, int output_total)
void ni_prepare_pts_queue(ni_pts_queue *q, ni_xcoder_params_t *enc_param, int pts_start)
void set_demo_roi_map(ni_session_context_t *p_enc_ctx)
Set up hard coded demo ROI map.
void * encoder_send_thread(void *args)
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.
void write_av1_ivf_packet(ni_demo_context_t *p_ctx, ni_packet_t *p_out_pkt, uint32_t meta_size, FILE *p_file)
void ni_hw_frame_unref(uint16_t hwframe_index)
ni_pixel_planar_format get_pixel_planar(ni_pix_fmt_t pix_fmt)
bool frame_list_is_empty(ni_test_frame_list_t *list)
int frame_list_drain(ni_test_frame_list_t *list)
int scan_and_clean_hwdescriptors(void)
void ni_hw_frame_ref(const niFrameSurface1_t *p_surface)
#define NI_MAX_PTS_QUEUE_SIZE
#define MAX_OUTPUT_FILES
#define NI_TEST_RETCODE_SUCCESS
#define NI_TEST_RETCODE_SEQ_CHANGE_DONE
#define NI_ALIGN(x, a)
#define NI_TEST_RETCODE_EAGAIN
#define NI_TEST_RETCODE_END_OF_STREAM
#define NI_TEST_RETCODE_FAILURE
#define NI_TEST_RETCODE_NEXT_INPUT
void ni_log2(const void *p_context, ni_log_level_t level, const char *fmt,...)
print log message and additional information using ni_log_callback,
Definition ni_log.c:337
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_DEBUG
Definition ni_log.h:64
@ NI_LOG_TRACE
Definition ni_log.h:65
@ NI_LOG_ERROR
Definition ni_log.h:62
@ NI_LOG_INFO
Definition ni_log.h:63
struct timeval current_time
struct timeval previous_time
int ni_retrieve_xcoder_params(char xcoderParams[], ni_xcoder_params_t *params, ni_session_context_t *ctx)
retrieve encoder config parameter values from –xcoder-params
Definition ni_util.c:4501
void ni_copy_hw_descriptors(uint8_t *p_dst[NI_MAX_NUM_DATA_POINTERS], uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS])
Copy Descriptor data to Netint HW descriptor frame layout to be sent to encoder for encoding....
Definition ni_util.c:4287
void ni_get_hw_yuv420p_dim(int width, int height, int factor, int is_semiplanar, int plane_stride[NI_MAX_NUM_DATA_POINTERS], int plane_height[NI_MAX_NUM_DATA_POINTERS])
Get dimension information of Netint HW YUV420p frame to be sent to encoder for encoding....
Definition ni_util.c:2747
int ni_retrieve_xcoder_gop(char xcoderGop[], ni_xcoder_params_t *params, ni_session_context_t *ctx)
Retrieve custom gop config values from –xcoder-gop.
Definition ni_util.c:4575
void ni_usleep(int64_t usec)
Definition ni_util.c:366
uint64_t ni_gettime_ns(void)
Definition ni_util.c:2701
void ni_copy_hw_yuv420p(uint8_t *p_dst[NI_MAX_NUM_DATA_POINTERS], uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS], int frame_width, int frame_height, int factor, int is_semiplanar, int conf_win_right, int dst_stride[NI_MAX_NUM_DATA_POINTERS], int dst_height[NI_MAX_NUM_DATA_POINTERS], int src_stride[NI_MAX_NUM_DATA_POINTERS], int src_height[NI_MAX_NUM_DATA_POINTERS])
Copy YUV data to Netint HW YUV420p frame layout to be sent to encoder for encoding....
Definition ni_util.c:3060
Utility definitions.
#define ni_aligned_free(p_memptr)
Definition ni_util.h:402
ni_gop_params_t pic_param[NI_MAX_GOP_NUM]
int enc_resend[MAX_OUTPUT_FILES]
uint64_t num_packets_received[MAX_OUTPUT_FILES]
ni_pts_queue * enc_pts_queue[MAX_OUTPUT_FILES]
int enc_sos_sent[MAX_OUTPUT_FILES]
int pts[MAX_OUTPUT_FILES]
uint8_t ivf_header_written[MAX_OUTPUT_FILES]
uint32_t av1_seq_header_len[MAX_OUTPUT_FILES]
int enc_eos_received[MAX_OUTPUT_FILES]
uint8_t * p_av1_seq_header[MAX_OUTPUT_FILES]
uint64_t num_frames_sent[MAX_OUTPUT_FILES]
int enc_eos_sent[MAX_OUTPUT_FILES]
uint64_t enc_total_bytes_received[MAX_OUTPUT_FILES]
uint32_t av1_muxed_num_packets[MAX_OUTPUT_FILES]
uint64_t enc_total_bytes_sent[MAX_OUTPUT_FILES]
ni_custom_gop_params_t custom_gop_params
This is a data structure for encoding parameters that have changed.
uint16_t force_pic_qp
uint8_t color_trc
uint32_t data_len[NI_MAX_NUM_DATA_POINTERS]
uint32_t vui_time_scale
uint32_t start_of_stream
uint16_t sar_width
ni_codec_format_t src_codec
uint8_t color_primaries
unsigned int reconf_len
uint32_t vui_num_units_in_tick
uint32_t end_of_stream
uint16_t sar_height
unsigned int sei_hdr_plus_len
uint32_t video_width
long long pts
uint8_t * p_data[NI_MAX_NUM_DATA_POINTERS]
uint8_t color_space
unsigned int extra_data_len
unsigned int sei_total_len
unsigned int sei_user_data_unreg_len
ni_pic_type_t ni_pict_type
uint8_t use_cur_src_as_long_term_pic
unsigned int sei_hdr_content_light_level_info_len
unsigned int sei_hdr_mastering_display_color_vol_len
int video_full_range_flag
uint8_t use_long_term_ref
uint32_t video_height
unsigned int roi_len
int32_t framerate_denom
int32_t framerate_num
uint8_t use_cur_src_as_long_term_pic
uint32_t data_len
long long dts
uint32_t av1_data_len[MAX_AV1_ENCODER_GOP_NUM]
uint32_t end_of_stream
long long pts
ni_bitstream_features_t bitstream_features
uint8_t * av1_p_buffer[MAX_AV1_ENCODER_GOP_NUM]
uint32_t buffer_size
uint32_t frame_type
uint8_t * av1_p_data[MAX_AV1_ENCODER_GOP_NUM]
uint32_t av1_buffer_size[MAX_AV1_ENCODER_GOP_NUM]
int64_t data[NI_MAX_PTS_QUEUE_SIZE]
ni_device_handle_t sender_handle
ni_device_handle_t device_handle
ni_device_handle_t auto_dl_handle
ni_framerate_t framerate
uint32_t meta_size
Params used in VFR mode Done///.
ni_device_handle_t blk_io_handle
ni_session_run_state_t session_run_state
ni_encoder_change_params_t * enc_change_params
ni_enc_quad_roi_custom_map * roi_map
union _ni_session_data_io::@19 data
ni_session_data_io_t frames[NI_MAX_BUFFERED_FRAME]
int32_t videoFullRange
int32_t colorDescPresent
int32_t colorPrimaries
int32_t aspectRatioHeight
int32_t colorSpace
int32_t colorTrc
int32_t aspectRatioWidth
ni_encoder_cfg_params_t cfg_enc_params
int reconf_hash[NI_BITRATE_RECONFIG_FILE_MAX_LINES][NI_BITRATE_RECONFIG_FILE_MAX_ENTRIES_PER_LINE]
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
encoder AVC ROI custom map (1 MB = 8bits)
struct _ni_enc_quad_roi_custom_map::@6 field