libxcoder 5.6.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
496 if (p_enc_ctx->frame_num ==
497 api_param->reconf_hash[p_ctx->reconfig_count][0])
498 {
499 ni_force_idr_frame_type(p_enc_ctx);
500 ni_log(NI_LOG_DEBUG, "%s(): frame #%lu force IDR frame\n", __func__,
501 p_enc_ctx->frame_num);
502 p_ctx->reconfig_count++;
503 }
504 break;
506 if (p_enc_ctx->frame_num ==
507 api_param->reconf_hash[p_ctx->reconfig_count][0])
508 {
509 ni_reconfig_bitrate(p_enc_ctx,
510 api_param->reconf_hash[p_ctx->reconfig_count][1]);
511 ni_log(NI_LOG_DEBUG, "%s(): frame #%lu API reconfig BR %d\n",
512 __func__, p_enc_ctx->frame_num,
513 api_param->reconf_hash[p_ctx->reconfig_count][1]);
514 p_ctx->reconfig_count++;
515 }
516 break;
518 if (p_enc_ctx->frame_num ==
519 api_param->reconf_hash[p_ctx->reconfig_count][0]) {
520 int32_t intraprd =
521 api_param->reconf_hash[p_ctx->reconfig_count][1];
522 ni_reconfig_intraprd(p_enc_ctx, intraprd);
524 "xcoder_send_frame: frame #%lu API reconfig intraPeriod %d\n",
525 p_enc_ctx->frame_num,
526 intraprd);
527
528 p_ctx->reconfig_count++;
529 }
530 break;
532 if (p_enc_ctx->frame_num ==
533 api_param->reconf_hash[p_ctx->reconfig_count][0])
534 {
535 ni_vui_hrd_t vui;
536 vui.colorDescPresent =
537 (uint8_t)api_param->reconf_hash[p_ctx->reconfig_count][1];
538 vui.colorPrimaries =
539 (uint8_t)api_param->reconf_hash[p_ctx->reconfig_count][2];
540 vui.colorTrc =
541 (uint8_t)api_param->reconf_hash[p_ctx->reconfig_count][3];
542 vui.colorSpace =
543 (uint8_t)api_param->reconf_hash[p_ctx->reconfig_count][4];
544 vui.aspectRatioWidth =
545 (uint16_t)api_param->reconf_hash[p_ctx->reconfig_count][5];
547 (uint16_t)api_param->reconf_hash[p_ctx->reconfig_count][6];
548 vui.videoFullRange =
549 (uint8_t)api_param->reconf_hash[p_ctx->reconfig_count][7];
550
551 ni_reconfig_vui(p_enc_ctx, &vui);
552 ni_log(NI_LOG_DEBUG, "%s(): frame #%lu API reconfig VUI HRD "
553 "colorDescPresent %d colorPrimaries %d "
554 "colorTrc %d colorSpace %d aspectRatioWidth %d "
555 "aspectRatioHeight %d videoFullRange %d\n",
556 __func__, p_enc_ctx->frame_num,
557 api_param->reconf_hash[p_ctx->reconfig_count][1],
558 api_param->reconf_hash[p_ctx->reconfig_count][2],
559 api_param->reconf_hash[p_ctx->reconfig_count][3],
560 api_param->reconf_hash[p_ctx->reconfig_count][4],
561 api_param->reconf_hash[p_ctx->reconfig_count][5],
562 api_param->reconf_hash[p_ctx->reconfig_count][6],
563 api_param->reconf_hash[p_ctx->reconfig_count][7]);
564 p_ctx->reconfig_count++;
565 }
566 break;
568 if (p_enc_ctx->frame_num ==
569 api_param->reconf_hash[p_ctx->reconfig_count][0])
570 {
573 (uint8_t)api_param->reconf_hash[p_ctx->reconfig_count][1];
575 (uint8_t)api_param->reconf_hash[p_ctx->reconfig_count][2];
576
577 ni_set_ltr(p_enc_ctx, &ltr);
578 ni_log(NI_LOG_DEBUG, "%s(): frame #%lu API set LTR\n", __func__,
579 p_enc_ctx->frame_num);
580 p_ctx->reconfig_count++;
581 }
582 break;
585 if (p_enc_ctx->frame_num ==
586 api_param->reconf_hash[p_ctx->reconfig_count][0])
587 {
588 ni_rc_min_max_qp qp_info;
589 qp_info.minQpI = (int32_t)api_param->reconf_hash[p_ctx->reconfig_count][1];
590 qp_info.maxQpI = (int32_t)api_param->reconf_hash[p_ctx->reconfig_count][2];
591 qp_info.maxDeltaQp = (int32_t)api_param->reconf_hash[p_ctx->reconfig_count][3];
592 qp_info.minQpPB = (int32_t)api_param->reconf_hash[p_ctx->reconfig_count][4];
593 qp_info.maxQpPB = (int32_t)api_param->reconf_hash[p_ctx->reconfig_count][5];
594 ni_reconfig_min_max_qp(p_enc_ctx, &qp_info);
596 "%s(): frame %llu minQpI %d maxQpI %d maxDeltaQp %d minQpPB %d maxQpPB %d\n",
597 __func__, p_enc_ctx->frame_num,
598 qp_info.minQpI, qp_info.maxQpI, qp_info.maxDeltaQp, qp_info.minQpPB, qp_info.maxQpPB);
599 p_ctx->reconfig_count++;
600 }
601 break;
603 if (p_enc_ctx->frame_num ==
604 api_param->reconf_hash[p_ctx->reconfig_count][0])
605 {
606 ni_set_ltr_interval(p_enc_ctx,
607 api_param->reconf_hash[p_ctx->reconfig_count][1]);
608 ni_log(NI_LOG_DEBUG, "%s(): frame #%lu API set LTR interval %d\n",
609 __func__, p_enc_ctx->frame_num,
610 api_param->reconf_hash[p_ctx->reconfig_count][1]);
611 p_ctx->reconfig_count++;
612 }
613 break;
615 if (p_enc_ctx->frame_num ==
616 api_param->reconf_hash[p_ctx->reconfig_count][0])
617 {
619 p_enc_ctx, api_param->reconf_hash[p_ctx->reconfig_count][1]);
620 ni_log(NI_LOG_DEBUG, "%s(): frame #%lu API set frame ref invalid "
621 "%d\n",
622 __func__, p_enc_ctx->frame_num,
623 api_param->reconf_hash[p_ctx->reconfig_count][1]);
624 p_ctx->reconfig_count++;
625 }
626 break;
628 if (p_enc_ctx->frame_num ==
629 api_param->reconf_hash[p_ctx->reconfig_count][0])
630 {
631 ni_framerate_t framerate;
632 framerate.framerate_num =
633 (int32_t)api_param->reconf_hash[p_ctx->reconfig_count][1];
634 framerate.framerate_denom =
635 (int32_t)api_param->reconf_hash[p_ctx->reconfig_count][2];
636 ni_reconfig_framerate(p_enc_ctx, &framerate);
638 "%s(): frame #%lu API reconfig framerate (%d/%d)\n",
639 __func__, p_enc_ctx->frame_num,
640 api_param->reconf_hash[p_ctx->reconfig_count][1],
641 api_param->reconf_hash[p_ctx->reconfig_count][2]);
642 p_ctx->reconfig_count++;
643 }
644 break;
646 if (p_enc_ctx->frame_num ==
647 api_param->reconf_hash[p_ctx->reconfig_count][0])
648 {
650 api_param->reconf_hash[p_ctx->reconfig_count][1]);
651 ni_log(NI_LOG_DEBUG, "%s(): frame #%lu API reconfig maxFrameSize %d\n",
652 __func__, p_enc_ctx->frame_num,
653 api_param->reconf_hash[p_ctx->reconfig_count][1]);
654 p_ctx->reconfig_count++;
655 }
656 break;
658 if (p_enc_ctx->frame_num ==
659 api_param->reconf_hash[p_ctx->reconfig_count][0])
660 {
661 ni_reconfig_crf(p_enc_ctx,
662 api_param->reconf_hash[p_ctx->reconfig_count][1]);
663 ni_log(NI_LOG_DEBUG, "%s(): frame #%lu API reconfig crf %d\n",
664 __func__, p_enc_ctx->frame_num,
665 api_param->reconf_hash[p_ctx->reconfig_count][1]);
666 p_ctx->reconfig_count++;
667 }
668 break;
670 if (p_enc_ctx->frame_num ==
671 api_param->reconf_hash[p_ctx->reconfig_count][0])
672 {
673 float crf = (float)(api_param->reconf_hash[p_ctx->reconfig_count][1] +
674 (float)api_param->reconf_hash[p_ctx->reconfig_count][2] / 100.0);
675 ni_reconfig_crf2(p_enc_ctx, crf);
676 ni_log(NI_LOG_DEBUG, "%s(): frame #%lu API reconfig crf %f\n",
677 __func__, p_enc_ctx->frame_num, crf);
678 p_ctx->reconfig_count++;
679 }
680 break;
682 if (p_enc_ctx->frame_num ==
683 api_param->reconf_hash[p_ctx->reconfig_count][0])
684 {
686 p_enc_ctx, api_param->reconf_hash[p_ctx->reconfig_count][1],
687 api_param->reconf_hash[p_ctx->reconfig_count][2]);
688 ni_log(NI_LOG_DEBUG, "%s(): frame #%lu API reconfig vbvMaxRate %d vbvBufferSize %d\n",
689 __func__, p_enc_ctx->frame_num,
690 api_param->reconf_hash[p_ctx->reconfig_count][1],
691 api_param->reconf_hash[p_ctx->reconfig_count][2]);
692 p_ctx->reconfig_count++;
693 }
694 break;
696 if (p_enc_ctx->frame_num ==
697 api_param->reconf_hash[p_ctx->reconfig_count][0])
698 {
700 p_enc_ctx, api_param->reconf_hash[p_ctx->reconfig_count][1]);
702 "xcoder_send_frame: frame #%lu reconf maxFrameSizeRatio %d\n",
703 p_enc_ctx->frame_num, api_param->reconf_hash[p_ctx->reconfig_count][1]);
704
705 p_ctx->reconfig_count++;
706 }
707 break;
709 if (p_enc_ctx->frame_num ==
710 api_param->reconf_hash[p_ctx->reconfig_count][0]) {
712 p_enc_ctx, api_param->reconf_hash[p_ctx->reconfig_count][1]);
714 "xcoder_send_frame: frame #%lu API reconfig sliceArg %d\n",
715 p_enc_ctx->frame_num,
716 api_param->reconf_hash[p_ctx->reconfig_count][1]);
717
718 p_ctx->reconfig_count++;
719 }
720 break;
722 default:;
723 }
724}
725
726/*!*****************************************************************************
727 * \brief Send encoder input data, read from input file
728 *
729 * Note: For optimal performance, yuv_buf should be 4k aligned
730 *
731 * \param
732 *
733 * \return
734 ******************************************************************************/
736 ni_session_data_io_t *p_in_data, void *yuv_buf,
737 int input_video_width, int input_video_height,
738 int is_last_input)
739{
740 int oneSent;
741 ni_frame_t *p_in_frame = &p_in_data->data.frame;
742 uint8_t enc_id = p_ctx->curr_enc_index;
743
744 ni_log(NI_LOG_DEBUG, "===> encoder_send_data <===\n");
745
747 {
748 ni_log(NI_LOG_DEBUG, "encoder_send_data: Sequence Change - waiting "
749 "for previous session to end\n");
751 }
752
753 if (p_ctx->enc_eos_sent[enc_id] == 1)
754 {
755 ni_log(NI_LOG_DEBUG, "encoder_send_data: ALL data (incl. eos) sent "
756 "already!\n");
758 }
759
760 if (p_ctx->enc_resend[enc_id])
761 {
762 goto send_frame;
763 }
764
765 p_in_frame->start_of_stream = 0;
766 if (!p_ctx->enc_sos_sent[enc_id] ||
768 {
769 p_ctx->enc_sos_sent[enc_id] = 1;
770 p_in_frame->start_of_stream = 1;
771 }
772 p_in_frame->end_of_stream = 0;
773 p_in_frame->force_key_frame = 0;
774
775 p_in_frame->video_width = input_video_width;
776 p_in_frame->video_height = input_video_height;
777
778 // reset encoder change data buffer
779 memset(p_enc_ctx->enc_change_params, 0, sizeof(ni_encoder_change_params_t));
780
781 // reset various aux data size
782 p_in_frame->roi_len = 0;
783 p_in_frame->reconf_len = 0;
784 p_in_frame->sei_total_len = 0;
785 p_in_frame->pts = p_ctx->pts[enc_id];
786
787 // collect encode reconfig and demo info and save them as aux data in
788 // the input frame struct.
789 prep_reconf_demo_data(p_ctx, p_enc_ctx, p_in_frame);
790
791 if (yuv_buf == NULL)
792 {
793 if (is_last_input)
794 {
795 p_in_frame->end_of_stream = 1;
796 ni_log(NI_LOG_DEBUG, "encoder_send_data: read chunk size 0, eos!\n");
797 }
798 else
799 {
800 ni_log(NI_LOG_DEBUG, "encoder_send_data: exit to get next input\n");
802 }
803 }
804
805send_frame:
806 // simulate FFmpeg -re option, which controls process input rate to simualte real time environment
807 if (p_ctx->read_framerate > 0)
808 {
809 uint64_t abs_time_ns;
810 abs_time_ns = ni_gettime_ns();
811 if ((abs_time_ns - p_ctx->start_time) < (uint64_t)(1000000000LL / p_ctx->read_framerate * p_ctx->num_frames_sent[enc_id]))
812 {
813 if (!p_ctx->enc_resend[enc_id])
814 p_ctx->enc_resend[enc_id] = 2;
815 if (p_ctx->enc_resend[enc_id] == 2)
817 }
818 else
819 {
820 p_ctx->num_frames_sent[enc_id]++;
821 }
822 }
823
824 oneSent = ni_enc_write_from_yuv_buffer(p_enc_ctx, p_in_frame, yuv_buf);
825 if (oneSent < 0)
826 {
828 "Error: failed ni_device_session_write() for encoder\n");
829 p_ctx->enc_resend[enc_id] = 1;
831 } else if (oneSent == 0 && !p_enc_ctx->ready_to_close)
832 {
833 p_ctx->enc_resend[enc_id] = 1;
835 } else
836 {
837 p_ctx->enc_resend[enc_id] = 0;
838
839 p_ctx->enc_total_bytes_sent[enc_id] += p_in_frame->data_len[0] +
840 p_in_frame->data_len[1] + p_in_frame->data_len[2] + p_in_frame->data_len[3];
841 ni_log(NI_LOG_DEBUG, "encoder_send_data: total sent data size=%lu\n",
842 p_ctx->enc_total_bytes_sent[enc_id]);
843
844 ni_log(NI_LOG_DEBUG, "encoder_send_data: success\n");
845
846 if (p_enc_ctx->ready_to_close)
847 {
849 {
850 p_ctx->enc_eos_sent[enc_id] = 1;
851 }
852 }
853
855 {
858 "encoder_send_data: session_run_state change to %d\n",
859 p_enc_ctx->session_run_state);
860 }
861
862 ni_pts_enqueue(p_ctx->enc_pts_queue[enc_id], p_ctx->pts[enc_id]);
863 ++p_ctx->pts[enc_id];
864 }
865
866 ni_frame_wipe_aux_data(p_in_frame);
868}
869
870/*******************************************************************************
871 * @brief Send encoder input data, directly after receiving from decoder
872 *
873 * @param p_enc_ctx encoder context
874 * p_dec_ctx decoder context
875 * p_dec_out_data frame returned by decoder
876 * p_enc_in_data frame to be sent to encoder
877 *
878 * @return
879 ******************************************************************************/
881 ni_session_data_io_t *p_dec_out_data,
882 ni_session_data_io_t *p_enc_in_data,
883 int input_video_width, int input_video_height)
884{
885 int oneSent;
886 int data_len_to_send;
887 // frame pointer to data frame struct to be sent
888 ni_frame_t *p_in_frame = &(p_enc_in_data->data.frame);
889 ni_xcoder_params_t *api_params =
891 int is_semiplanar = get_pixel_planar(p_enc_ctx->pixel_format) == NI_PIXEL_PLANAR_FORMAT_SEMIPLANAR;
892 int is_hwframe = p_enc_ctx->hw_action != NI_CODEC_HW_NONE;
893 uint8_t enc_id = p_ctx->curr_enc_index;
894
895 ni_log(NI_LOG_DEBUG, "===> encoder_send_data2 <===\n");
896
897 if (p_ctx->enc_eos_sent[enc_id] == 1)
898 {
899 ni_log(NI_LOG_DEBUG, "encoder_send_data2: ALL data (incl. eos) sent "
900 "already!\n");
902 }
903
904 // don't send new data before flushing completed
906 {
908 }
909
910//#define ENCODER_FLUSH_INJECT
911// Note that this demo only supports in multi threads transcoding mode
912// For examples: sudo ./xcoder -c 0 -i input.h265 -m h2h -b 8 -o output.h265 -t
913#ifdef ENCODER_FLUSH_INJECT
914 if ((p_enc_ctx->frame_num > 0 && p_enc_ctx->frame_num % 30 == 0) &&
915 !p_dec_out_data->data.frame.end_of_stream)
916 {
917 // send the encoder flush command
919 {
920 // need to change the state
922 ni_log(NI_LOG_INFO, "encoder_send_data2 flush encoder successfully\n");
924 }
925 else
926 {
927 ni_log(NI_LOG_ERROR, "Error: encoder_send_data2 flush encoder\n");
928 return -1;
929 }
930 }
931#endif
932
933 // frame resend
934 if (p_ctx->enc_resend[enc_id])
935 {
936 goto send_frame;
937 }
938
939 // copy input frame to a new frame struct and prep for the aux data
940 p_in_frame->end_of_stream = p_dec_out_data->data.frame.end_of_stream;
941 p_in_frame->ni_pict_type = 0;
942
943 // reset encoder change data buffer
944 memset(p_enc_ctx->enc_change_params, 0,
946
947 // extra data starts with metadata header, and reset various aux data
948 // size
950 p_in_frame->roi_len = 0;
951 p_in_frame->reconf_len = 0;
952 p_in_frame->sei_total_len = 0;
953 p_in_frame->force_pic_qp = 0;
954 p_in_frame->pts = p_ctx->pts[enc_id];
955
956 // collect encode reconfig and demo info and save them in the decode out
957 // frame, to be used in the aux data prep and copy later
958 prep_reconf_demo_data(p_ctx, p_enc_ctx, &(p_dec_out_data->data.frame));
959
960 int dst_stride[NI_MAX_NUM_DATA_POINTERS] = {0};
961 int dst_height_aligned[NI_MAX_NUM_DATA_POINTERS] = {0};
962 bool alignment_2pass_wa = (
963 (api_params->cfg_enc_params.lookAheadDepth ||
964 api_params->cfg_enc_params.crf >= 0 ||
965 api_params->cfg_enc_params.crfFloat >= 0) &&
966 (p_enc_ctx->codec_format == NI_CODEC_FORMAT_H265 ||
967 p_enc_ctx->codec_format == NI_CODEC_FORMAT_AV1));
968 ni_get_hw_yuv420p_dim(input_video_width, input_video_height,
969 p_enc_ctx->bit_depth_factor, is_semiplanar,
970 dst_stride, dst_height_aligned);
971
972 if (alignment_2pass_wa && !is_hwframe) {
973 if (is_semiplanar) {
974 // for 2-pass encode output mismatch WA, need to extend (and
975 // pad) CbCr plane height, because 1st pass assume input 32
976 // align
977 dst_height_aligned[1] = (((dst_height_aligned[0] + 31) / 32) * 32) / 2;
978 } else {
979 // for 2-pass encode output mismatch WA, need to extend (and
980 // pad) Cr plane height, because 1st pass assume input 32 align
981 dst_height_aligned[2] = (((dst_height_aligned[0] + 31) / 32) * 32) / 2;
982 }
983 }
984
985 // ROI demo mode takes higher priority over aux data
986 // Note: when ROI demo modes enabled, supply ROI map for the specified
987 // range frames, and 0 map for others
988 if (api_params->roi_demo_mode && api_params->cfg_enc_params.roi_enable)
989 {
990 if (p_enc_ctx->frame_num > 90 && p_enc_ctx->frame_num < 300)
991 {
992 p_in_frame->roi_len = p_enc_ctx->roi_len;
993 } else
994 {
995 p_in_frame->roi_len = 0;
996 }
997 // when ROI enabled, always have a data buffer for ROI
998 // Note: this is handled separately from ROI through side/aux data
999 p_in_frame->extra_data_len += p_enc_ctx->roi_len;
1000 }
1001
1002 int should_send_sei_with_frame = ni_should_send_sei_with_frame(
1003 p_enc_ctx, p_in_frame->ni_pict_type, api_params);
1004
1005 // data buffer for various SEI: HDR mastering display color volume, HDR
1006 // content light level, close caption, User data unregistered, HDR10+
1007 // etc.
1008 uint8_t mdcv_data[NI_MAX_SEI_DATA];
1009 uint8_t cll_data[NI_MAX_SEI_DATA];
1010 uint8_t cc_data[NI_MAX_SEI_DATA];
1011 uint8_t udu_data[NI_MAX_SEI_DATA];
1012 uint8_t hdrp_data[NI_MAX_SEI_DATA];
1013
1014 // prep for auxiliary data (various SEI, ROI) in p_in_frame, based on
1015 // the data returned in decoded frame and also reconfig and demo modes
1016 // collected in prep_reconf_demo_data
1018 p_enc_ctx, p_in_frame, &(p_dec_out_data->data.frame),
1019 p_enc_ctx->codec_format, should_send_sei_with_frame, mdcv_data,
1020 cll_data, cc_data, udu_data, hdrp_data);
1021
1022 p_in_frame->extra_data_len += p_in_frame->sei_total_len;
1023
1024 // data layout requirement: leave space for reconfig data if at least
1025 // one of reconfig, SEI or ROI is present
1026 // Note: ROI is present when enabled, so use encode config flag instead
1027 // of frame's roi_len as it can be 0 indicating a 0'd ROI map
1028 // setting !
1029 if (p_in_frame->reconf_len || p_in_frame->sei_total_len ||
1030 (api_params->roi_demo_mode &&
1031 api_params->cfg_enc_params.roi_enable))
1032 {
1033 p_in_frame->extra_data_len += sizeof(ni_encoder_change_params_t);
1034 }
1035
1036 if (!is_hwframe)
1037 {
1039 p_in_frame, input_video_width, input_video_height, dst_stride,
1040 p_enc_ctx->codec_format == NI_CODEC_FORMAT_H264,
1041 (int)(p_in_frame->extra_data_len), alignment_2pass_wa);
1042 if (!p_in_frame->p_data[0])
1043 {
1044 ni_log(NI_LOG_ERROR, "Error: cannot allocate YUV frame buffer!");
1046 }
1047 } else
1048 {
1049 ni_frame_buffer_alloc_hwenc(p_in_frame, input_video_width,
1050 input_video_height,
1051 (int)(p_in_frame->extra_data_len));
1052 if (!p_in_frame->p_data[3])
1053 {
1054 ni_log(NI_LOG_ERROR, "Error: cannot allocate YUV frame buffer!");
1056 }
1057 }
1058
1060 "p_dst alloc linesize = %d/%d/%d src height=%d "
1061 "dst height aligned = %d/%d/%d force_key_frame=%d, "
1062 "extra_data_len=%u"
1063 " sei_size=%u (hdr_content_light_level %u hdr_mastering_display_"
1064 "color_vol %u hdr10+ %u hrd %d) reconf_size=%u roi_size=%u "
1065 "force_pic_qp=%u udu_sei_size=%u "
1066 "use_cur_src_as_long_term_pic %u use_long_term_ref %u\n",
1067 dst_stride[0], dst_stride[1], dst_stride[2], input_video_height,
1068 dst_height_aligned[0], dst_height_aligned[1], dst_height_aligned[2],
1069 p_in_frame->force_key_frame, p_in_frame->extra_data_len,
1070 p_in_frame->sei_total_len,
1073 p_in_frame->sei_hdr_plus_len, 0, /* hrd is 0 size for now */
1074 p_in_frame->reconf_len, p_in_frame->roi_len,
1075 p_in_frame->force_pic_qp, p_in_frame->sei_user_data_unreg_len,
1076 p_in_frame->use_cur_src_as_long_term_pic,
1077 p_in_frame->use_long_term_ref);
1078
1079 uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS];
1080 int src_stride[NI_MAX_NUM_DATA_POINTERS];
1081 int src_height[NI_MAX_NUM_DATA_POINTERS];
1082
1083 src_height[0] = p_dec_out_data->data.frame.video_height;
1084 src_height[1] = src_height[2] = src_height[0] / 2;
1085 src_height[3] = 0;
1086
1087 src_stride[0] =
1088 (int)(p_dec_out_data->data.frame.data_len[0]) / src_height[0];
1089 src_stride[1] =
1090 (int)(p_dec_out_data->data.frame.data_len[1]) / src_height[1];
1091 src_stride[2] = src_stride[1];
1092 if (is_semiplanar)
1093 {
1094 src_height[2] = 0;
1095 src_stride[2] = 0;
1096 }
1097 src_stride[3] = 0;
1098
1099 p_src[0] = p_dec_out_data->data.frame.p_data[0];
1100 p_src[1] = p_dec_out_data->data.frame.p_data[1];
1101 p_src[2] = p_dec_out_data->data.frame.p_data[2];
1102 p_src[3] = p_dec_out_data->data.frame.p_data[3];
1103
1104 if (!is_hwframe)
1105 { // YUV part of the encoder input data layout
1107 (uint8_t **)(p_in_frame->p_data), p_src, input_video_width,
1108 input_video_height, p_enc_ctx->bit_depth_factor, is_semiplanar,
1109 ((ni_xcoder_params_t *)p_enc_ctx->p_session_config)
1110 ->cfg_enc_params.conf_win_right,
1111 dst_stride, dst_height_aligned, src_stride, src_height);
1112 } else
1113 {
1114 ni_copy_hw_descriptors((uint8_t **)(p_in_frame->p_data), p_src);
1115 }
1116 // auxiliary data part of the encoder input data layout
1117 ni_enc_copy_aux_data(p_enc_ctx, p_in_frame,
1118 &(p_dec_out_data->data.frame),
1119 p_enc_ctx->codec_format, mdcv_data, cll_data,
1120 cc_data, udu_data, hdrp_data, is_hwframe,
1121 is_semiplanar);
1122
1123 p_in_frame->video_width = input_video_width;
1124 p_in_frame->video_height = input_video_height;
1125
1126 p_in_frame->start_of_stream = 0;
1127 if (!p_ctx->enc_sos_sent[enc_id])
1128 {
1129 p_ctx->enc_sos_sent[enc_id] = 1;
1130 p_in_frame->start_of_stream = 1;
1131 }
1132
1133send_frame:
1134 data_len_to_send = (int)(p_in_frame->data_len[0] + p_in_frame->data_len[1] +
1135 p_in_frame->data_len[2] + p_in_frame->data_len[3]);
1136
1137 if (data_len_to_send > 0 || p_in_frame->end_of_stream)
1138 {
1139 oneSent = ni_device_session_write(p_enc_ctx, p_enc_in_data,
1141 p_in_frame->end_of_stream = 0;
1142 } else
1143 {
1145 }
1146
1147 if (oneSent < 0)
1148 {
1149 ni_log(NI_LOG_ERROR, "Error: encoder_send_data2\n");
1150 p_ctx->enc_resend[enc_id] = 1;
1152 } else if (oneSent == 0)
1153 {
1154 if (p_ctx->enc_eos_sent[enc_id] == 0 && p_enc_ctx->ready_to_close)
1155 {
1156 p_ctx->enc_resend[enc_id] = 0;
1157 p_ctx->enc_eos_sent[enc_id] = 1;
1158 } else
1159 {
1160 p_ctx->enc_resend[enc_id] = 1;
1162 }
1163 } else
1164 {
1165 p_ctx->enc_resend[enc_id] = 0;
1166
1167 if (p_enc_ctx->ready_to_close)
1168 {
1169 p_ctx->enc_eos_sent[enc_id] = 1;
1170 }
1171
1172 ni_pts_enqueue(p_ctx->enc_pts_queue[enc_id], p_ctx->pts[enc_id]);
1173 ++p_ctx->pts[enc_id];
1174
1175 ni_log(NI_LOG_DEBUG, "encoder_send_data2: success\n");
1176 }
1177
1179}
1180
1181/*!*****************************************************************************
1182 * \brief Send encoder input data, read from uploader instance hwframe
1183 *
1184 * \param
1185 *
1186 * \return
1187 ******************************************************************************/
1189 ni_session_data_io_t *p_in_data,
1190 int input_video_width, int input_video_height, int eos)
1191{
1192 int oneSent;
1193 ni_frame_t *p_in_frame = &(p_in_data->data.frame);
1194 uint8_t enc_id = p_ctx->curr_enc_index;
1195
1196 ni_log(NI_LOG_DEBUG, "===> encoder_send_data3 <===\n");
1197
1198 if (p_ctx->enc_eos_sent[enc_id] == 1)
1199 {
1200 ni_log(NI_LOG_DEBUG, "encoder_send_data3: ALL data (incl. eos) sent "
1201 "already!\n");
1202 return 0;
1203 }
1204
1205 if (p_ctx->enc_resend[enc_id])
1206 {
1207 goto send_frame;
1208 }
1209
1210 p_in_frame->start_of_stream = 0;
1211 if (!p_ctx->enc_sos_sent[enc_id])
1212 {
1213 p_ctx->enc_sos_sent[enc_id] = 1;
1214 p_in_frame->start_of_stream = 1;
1215 }
1216 p_in_frame->end_of_stream = eos;
1217 p_in_frame->force_key_frame = 0;
1218 p_in_frame->video_width = input_video_width;
1219 p_in_frame->video_height = input_video_height;
1220 p_in_frame->pts = p_ctx->pts[enc_id];
1221 if (eos)
1222 {
1223 ni_log(NI_LOG_DEBUG, "encoder_send_data3: read chunk size 0, eos!\n");
1224 }
1225
1226 // only metadata header for now
1228
1229send_frame:
1230 oneSent =
1231 ni_device_session_write(p_enc_ctx, p_in_data, NI_DEVICE_TYPE_ENCODER);
1232 if (oneSent < 0)
1233 {
1235 "Error: failed ni_device_session_write() for encoder\n");
1236 p_ctx->enc_resend[enc_id] = 1;
1237 return -1;
1238 } else if (oneSent == 0 && !p_enc_ctx->ready_to_close)
1239 {
1240 p_ctx->enc_resend[enc_id] = 1;
1241 ni_log(NI_LOG_DEBUG, "NEEDED TO RESEND");
1243 } else
1244 {
1245 p_ctx->enc_resend[enc_id] = 0;
1246
1247 ni_log(NI_LOG_DEBUG, "encoder_send_data3: total sent data size=%u\n",
1248 p_in_frame->data_len[3]);
1249
1250 ni_log(NI_LOG_DEBUG, "encoder_send_data3: success\n");
1251
1252 if (p_enc_ctx->ready_to_close)
1253 {
1254 p_ctx->enc_eos_sent[enc_id] = 1;
1255 }
1256
1257 ni_pts_enqueue(p_ctx->enc_pts_queue[enc_id], p_ctx->pts[enc_id]);
1258 ++p_ctx->pts[enc_id];
1259 }
1260
1261 return 0;
1262}
1263
1264/*!*****************************************************************************
1265 * \brief Encoder session open
1266 *
1267 * \param
1268 *
1269 * \return 0 if successful, < 0 otherwise
1270 ******************************************************************************/
1271int encoder_open_session(ni_session_context_t *p_enc_ctx, int dst_codec_format,
1272 int iXcoderGUID, ni_xcoder_params_t *p_enc_params,
1273 int width, int height, ni_pix_fmt_t pix_fmt,
1274 bool check_zerocopy)
1275{
1276 int ret = 0;
1277 bool isrgba = false;
1278
1279 p_enc_ctx->p_session_config = p_enc_params;
1280 p_enc_ctx->session_id = NI_INVALID_SESSION_ID;
1281 p_enc_ctx->codec_format = dst_codec_format;
1282
1283 // assign the card GUID in the encoder context and let session open
1284 // take care of the rest
1285 p_enc_ctx->device_handle = NI_INVALID_DEVICE_HANDLE;
1286 p_enc_ctx->blk_io_handle = NI_INVALID_DEVICE_HANDLE;
1287 p_enc_ctx->hw_id = iXcoderGUID;
1288
1289 // default: little endian
1291
1292 switch (pix_fmt)
1293 {
1294 case NI_PIX_FMT_YUV420P:
1295 case NI_PIX_FMT_NV12:
1296 p_enc_ctx->src_bit_depth = 8;
1297 p_enc_ctx->bit_depth_factor = 1;
1298 break;
1300 case NI_PIX_FMT_P010LE:
1301 p_enc_ctx->src_bit_depth = 10;
1302 p_enc_ctx->bit_depth_factor = 2;
1303 break;
1304 case NI_PIX_FMT_ABGR:
1305 case NI_PIX_FMT_ARGB:
1306 case NI_PIX_FMT_RGBA:
1307 case NI_PIX_FMT_BGRA:
1308 p_enc_ctx->src_bit_depth = 8;
1309 p_enc_ctx->bit_depth_factor = 4;
1310 isrgba = true;
1311 break;
1312 default:
1313 p_enc_ctx->src_bit_depth = 8;
1314 p_enc_ctx->bit_depth_factor = 1;
1315 pix_fmt = NI_PIX_FMT_YUV420P;
1316 break;
1317 //ni_log(NI_LOG_ERROR, "%s: Invalid pixel format %s\n", __func__,
1318 // ni_pixel_format_name(pix_fmt));
1319 //return NI_RETCODE_INVALID_PARAM;
1320 }
1321
1322 // original resolution this stream started with, this is used by encoder sequence change
1323 p_enc_ctx->ori_width = width;
1324 p_enc_ctx->ori_height = height;
1325 p_enc_ctx->ori_bit_depth_factor = p_enc_ctx->bit_depth_factor;
1326 p_enc_ctx->ori_pix_fmt = pix_fmt;
1327 p_enc_ctx->pixel_format = pix_fmt;
1328
1329 int linesize_aligned = width;
1330 if (!isrgba)
1331 {
1332 if (linesize_aligned < NI_MIN_WIDTH)
1333 {
1334 p_enc_params->cfg_enc_params.conf_win_right +=
1335 (NI_MIN_WIDTH - width) / 2 * 2;
1336 linesize_aligned = NI_MIN_WIDTH;
1337 } else
1338 {
1339 linesize_aligned = ((width + 1) / 2) * 2;
1340 p_enc_params->cfg_enc_params.conf_win_right +=
1341 (linesize_aligned - width) / 2 * 2;
1342 }
1343 }
1344 p_enc_params->source_width = linesize_aligned;
1345
1346 int height_aligned = height;
1347 if (!isrgba)
1348 {
1349 if (height_aligned < NI_MIN_HEIGHT)
1350 {
1351 p_enc_params->cfg_enc_params.conf_win_bottom +=
1352 (NI_MIN_HEIGHT - height) / 2 * 2;
1353 height_aligned = NI_MIN_HEIGHT;
1354 } else
1355 {
1356 height_aligned = ((height + 1) / 2) * 2;
1357 p_enc_params->cfg_enc_params.conf_win_bottom +=
1358 (height_aligned - height) / 2 * 2;
1359 }
1360 }
1361 p_enc_params->source_height = height_aligned;
1362
1363 // default planar encoder input data
1364 p_enc_params->cfg_enc_params.planar = get_pixel_planar(pix_fmt);
1365
1366 if (check_zerocopy)
1367 {
1368
1369 // config linesize for zero copy (if input resolution is zero copy compatible)
1370 int src_stride[NI_MAX_NUM_DATA_POINTERS];
1371
1372 // NOTE - FFmpeg / Gstreamer users should use linesize array in frame structure instead of src_stride in the following sample code
1373 src_stride[0] = width * p_enc_ctx->bit_depth_factor;
1374
1375 if (isrgba)
1376 src_stride[1] = src_stride[2] = 0;
1377 else
1378 {
1379 bool isnv12frame = (p_enc_params->cfg_enc_params.planar == NI_PIXEL_PLANAR_FORMAT_SEMIPLANAR) ? true : false;
1380 src_stride[1] = isnv12frame ? src_stride[0] : src_stride[0] / 2;
1381 src_stride[2] = isnv12frame ? 0 : src_stride[0] / 2;
1382 }
1383
1385 p_enc_params, width, height,
1386 (const int *)src_stride, true);
1387 }
1388
1390 if (ret != NI_RETCODE_SUCCESS)
1391 {
1392 ni_log(NI_LOG_ERROR, "Error: %s failure!\n", __func__);
1393 } else
1394 {
1395 ni_log(NI_LOG_INFO, "Encoder device %d session open successful.\n", iXcoderGUID);
1396 }
1397
1398 // set up ROI QP map for ROI demo modes if enabled
1399 if (p_enc_params->cfg_enc_params.roi_enable &&
1400 (1 == p_enc_params->roi_demo_mode || 2 == p_enc_params->roi_demo_mode))
1401 {
1402 set_demo_roi_map(p_enc_ctx);
1403 }
1404
1405 return ret;
1406}
1407
1408/*!*****************************************************************************
1409 * \brief Reopen or reconfig encoder upon sequence change
1410 *
1411 * \param
1412 *
1413 * \return 0 - success got packet
1414 * 1 - received eos
1415 * 2 - got nothing, need retry
1416 * -1 - failure
1417 ******************************************************************************/
1419 ni_session_data_io_t *p_in_data,
1420 ni_session_data_io_t *p_out_data)
1421{
1422 int ret = NI_TEST_RETCODE_SUCCESS;
1423 int new_stride, ori_stride;
1424 bool bIsSmallPicture = false;
1425 ni_frame_t *p_buffered_frame = &(p_in_data->data.frame);
1426 ni_xcoder_params_t *p_api_param = (ni_xcoder_params_t *)p_enc_ctx->p_session_config;
1427 int new_width, new_height;
1428 ni_pix_fmt_t new_pix_fmt;
1429 bool is_semiplanar;
1430 bool is_rgba;
1431 int src_stride[NI_MAX_NUM_DATA_POINTERS];
1432
1433 new_width = p_buffered_frame->video_width;
1434 new_height = p_buffered_frame->video_height;
1435 new_pix_fmt = p_buffered_frame->pixel_format;
1436
1437 // check if resolution is zero copy compatible and set linesize according to new resolution
1438 is_semiplanar = (new_pix_fmt == NI_PIX_FMT_NV12 || new_pix_fmt == NI_PIX_FMT_P010LE);
1439
1440 is_rgba = (new_pix_fmt == NI_PIX_FMT_ABGR || new_pix_fmt == NI_PIX_FMT_ARGB
1441 || new_pix_fmt == NI_PIX_FMT_RGBA || new_pix_fmt == NI_PIX_FMT_BGRA);
1442
1443 // NOTE - FFmpeg / Gstreamer users should use linesize array in frame structure instead of src_stride in the following sample code
1444 src_stride[0] = new_width * p_enc_ctx->bit_depth_factor;
1445 if (is_rgba)
1446 {
1447 src_stride[1] = 0;
1448 src_stride[2] = 0;
1449 }
1450 else
1451 {
1452 src_stride[1] = is_semiplanar ? src_stride[0] : src_stride[0] / 2;
1453 src_stride[2] = is_semiplanar ? 0 : src_stride[0] / 2;
1454 }
1455
1456 if (ni_encoder_frame_zerocopy_check(p_enc_ctx,
1457 p_api_param, new_width, new_height,
1458 (const int *)src_stride, true) == NI_RETCODE_SUCCESS)
1459 {
1460 new_stride = p_api_param->luma_linesize; // new sequence is zero copy compatible
1461 }
1462 else
1463 {
1464 new_stride = NI_ALIGN(new_width * p_enc_ctx->bit_depth_factor, 128);
1465 }
1466
1467 if (p_enc_ctx->ori_luma_linesize && p_enc_ctx->ori_chroma_linesize)
1468 {
1469 ori_stride = p_enc_ctx->ori_luma_linesize; // previous sequence was zero copy compatible
1470 }
1471 else
1472 {
1473 ori_stride = NI_ALIGN(p_enc_ctx->ori_width * p_enc_ctx->bit_depth_factor, 128);
1474 }
1475
1476 if (p_api_param->cfg_enc_params.lookAheadDepth) {
1477 ni_log(NI_LOG_DEBUG, "xcoder_encode_reinit 2-pass "
1478 "lookaheadDepth %d\n",
1479 p_api_param->cfg_enc_params.lookAheadDepth);
1480 if ((new_width < NI_2PASS_ENCODE_MIN_WIDTH) ||
1481 (new_height < NI_2PASS_ENCODE_MIN_HEIGHT)) {
1482 bIsSmallPicture = true;
1483 }
1484 }
1485 else {
1486 if ((new_width < NI_MIN_WIDTH) ||
1487 (new_height < NI_MIN_HEIGHT)) {
1488 bIsSmallPicture = true;
1489 }
1490 }
1491
1492 if (p_api_param->cfg_enc_params.multicoreJointMode) {
1493 ni_log(NI_LOG_DEBUG, "xcoder_encode_reinit multicore "
1494 "joint mode\n");
1495 if ((new_width < NI_MULTICORE_ENCODE_MIN_WIDTH) ||
1496 (new_height < NI_MULTICORE_ENCODE_MIN_HEIGHT)) {
1497 bIsSmallPicture = true;
1498 }
1499 }
1500
1501 if (p_api_param->cfg_enc_params.crop_width || p_api_param->cfg_enc_params.crop_height) {
1502 ni_log(NI_LOG_DEBUG, "xcoder_encode_reinit needs to close and re-open "
1503 "due to crop width x height\n");
1504 bIsSmallPicture = true;
1505 }
1506
1507 ni_log(NI_LOG_DEBUG, "xcoder_encode_reinit resolution: %dx%d->%dx%d "
1508 "pix fmt: %d->%d bIsSmallPicture %d codec %d\n",
1509 ori_stride, p_enc_ctx->ori_height, new_stride, new_height,
1510 p_enc_ctx->ori_pix_fmt, new_pix_fmt, bIsSmallPicture,
1511 p_enc_ctx->codec_format);
1512
1513 // fast sequence change without close / open only if new resolution < original resolution
1514 if (ori_stride*p_enc_ctx->ori_height < new_stride*new_height ||
1515 p_enc_ctx->ori_pix_fmt != new_pix_fmt ||
1516 bIsSmallPicture ||
1517 p_enc_ctx->codec_format == NI_CODEC_FORMAT_JPEG)
1518 {
1519 ni_log(NI_LOG_INFO, "XCoder encode sequence change by close / re-open session\n");
1520 encoder_close_session(p_enc_ctx, p_in_data, p_out_data);
1521 ret = encoder_open_session(p_enc_ctx, p_enc_ctx->codec_format,
1522 p_enc_ctx->hw_id, p_api_param, new_width,
1523 new_height, new_pix_fmt, true);
1524 if (NI_RETCODE_SUCCESS != ret)
1525 {
1526 ni_log(NI_LOG_ERROR, "Failed to Re-open Encoder Session upon Sequence Change (status = %d)\n", ret);
1527 return ret;
1528 }
1529 p_out_data->data.packet.end_of_stream = 0;
1530 p_in_data->data.frame.start_of_stream = 1;
1531 // clear crop parameters upon sequence change because cropping values may not be compatible to new resolution
1532 p_api_param->cfg_enc_params.crop_width = p_api_param->cfg_enc_params.crop_height = 0;
1533 p_api_param->cfg_enc_params.hor_offset = p_api_param->cfg_enc_params.ver_offset = 0;
1534 }
1535 else
1536 {
1537 if (p_enc_ctx->codec_format == NI_CODEC_FORMAT_AV1) {
1538 // AV1 8x8 alignment HW limitation is now worked around by FW cropping input resolution
1539 if (new_width % NI_PARAM_AV1_ALIGN_WIDTH_HEIGHT)
1541 "resolution change: AV1 Picture Width not aligned to %d - picture will be cropped\n",
1543
1544 if (new_height % NI_PARAM_AV1_ALIGN_WIDTH_HEIGHT)
1546 "resolution change: AV1 Picture Height not aligned to %d - picture will be cropped\n",
1548 }
1549 ni_log(NI_LOG_INFO, "XCoder encode sequence change by re-config session (fast path)\n");
1550 ret = encoder_sequence_change(p_enc_ctx, p_in_data, p_out_data, new_width, new_height, new_pix_fmt);
1551 }
1552
1553 // this state is referenced when sending first frame after sequence change
1555
1556 ni_log(NI_LOG_DEBUG, "%s: session_run_state change to %d \n", __func__,
1557 p_enc_ctx->session_run_state);
1558
1559 return ret;
1560}
1561
1562void write_av1_ivf_header(ni_demo_context_t *p_ctx, uint32_t width, uint32_t height, uint32_t frame_num,
1563 uint32_t frame_denom, FILE *p_file)
1564{
1565 // write the global ivf start header
1566 if (!p_ctx->ivf_header_written[p_ctx->curr_enc_index] && p_file != NULL && !p_ctx->av1_output_obu)
1567 {
1568 uint8_t start_header[32] = {
1569 0x44, 0x4b, 0x49, 0x46, /* signature: 'DKIF' */
1570 0x00, 0x00, /* version: 0 */
1571 0x20, 0x00, /* length of header in bytes: 32 */
1572 0x41, 0x56, 0x30, 0x31, /* codec FourCC: AV01 */
1573 0x00, 0x07, /* width in pixels(little endian), default 1280 */
1574 0xd0, 0x02, /* height in pixels(little endian), default 720 */
1575 0x1e, 0x00, 0x00, 0x00, /* time base numerator, default 30 */
1576 0x01, 0x00, 0x00, 0x00, /* time base denominator, default 1 */
1577 0x00, 0x00, 0x00, 0x00, /* number of frames in file */
1578 0x00, 0x00, 0x00, 0x00 /* reserved */
1579 };
1580
1581 if (width && height)
1582 {
1583 start_header[12] = width & 0xff;
1584 start_header[13] = ((width >> 8) & 0xff);
1585 start_header[14] = height & 0xff;
1586 start_header[15] = ((height >> 8) & 0xff);
1587 }
1588
1589 if (frame_num && frame_denom)
1590 {
1591 start_header[16] = frame_num & 0xff;
1592 start_header[17] = ((frame_num >> 8) & 0xff);
1593 start_header[18] = ((frame_num >> 16) & 0xff);
1594 start_header[19] = ((frame_num >> 24) & 0xff);
1595 start_header[20] = frame_denom & 0xff;
1596 start_header[21] = ((frame_denom >> 8) & 0xff);
1597 start_header[22] = ((frame_denom >> 16) & 0xff);
1598 start_header[23] = ((frame_denom >> 24) & 0xff);
1599 }
1600
1601 if (fwrite(start_header, sizeof(start_header), 1, p_file) != 1)
1602 {
1603 ni_log(NI_LOG_ERROR, "Error: writing ivf start header fail!\n");
1604 ni_log(NI_LOG_ERROR, "Error: ferror rc = %d\n", ferror(p_file));
1605 }
1606
1607 p_ctx->ivf_header_written[p_ctx->curr_enc_index] = 1;
1608 }
1609}
1610
1611void write_av1_ivf_packet(ni_demo_context_t *p_ctx, ni_packet_t *p_out_pkt, uint32_t meta_size, FILE *p_file)
1612{
1613 int i;
1614 uint8_t enc_id = p_ctx->curr_enc_index;
1615
1616 if (!p_file)
1617 {
1618 return;
1619 }
1620
1621 // write ivf frame header
1622 if (!p_ctx->av1_output_obu)
1623 {
1624 uint32_t pts = p_ctx->av1_muxed_num_packets[enc_id];
1625 uint32_t pkt_size = p_out_pkt->data_len - meta_size;
1626
1627 if (p_ctx->av1_seq_header_len[enc_id] > 0)
1628 {
1629 pkt_size += p_ctx->av1_seq_header_len[enc_id] - meta_size;
1630 }
1631 for (i = 0; i < p_out_pkt->av1_buffer_index; i++)
1632 {
1633 pkt_size += p_out_pkt->av1_data_len[i] - meta_size;
1634 }
1635
1636 // ivf frame header
1637 // bytes 0-3: size of frame in bytes(not including the 12-byte header
1638 // byte 4-11: 64-bit pts (here pts=num_of_packets(32-bit), thus here only saves 32-bit
1639 uint8_t ivf_frame_header[12] = {((pkt_size & 0xff)),
1640 ((pkt_size >> 8) & 0xff),
1641 ((pkt_size >> 16) & 0xff),
1642 ((pkt_size >> 24) & 0xff),
1643 ((pts & 0xff)),
1644 ((pts >> 8) & 0xff),
1645 ((pts >> 16) & 0xff),
1646 ((pts >> 24) & 0xff),
1647 0x00, 0x00, 0x00, 0x00};
1648 if (fwrite(ivf_frame_header, 12, 1, p_file) != 1)
1649 {
1650 ni_log(NI_LOG_ERROR, "Error: writing ivf frame header fail!\n");
1651 ni_log(NI_LOG_ERROR, "Error: ferror rc = %d\n", ferror(p_file));
1652 }
1653 }
1654
1655 // write the leftover sequence header if there is any
1656 if (p_ctx->av1_seq_header_len[enc_id] > 0)
1657 {
1658 if (fwrite(p_ctx->p_av1_seq_header[enc_id] + meta_size,
1659 p_ctx->av1_seq_header_len[enc_id] - meta_size, 1, p_file) != 1)
1660 {
1661 ni_log(NI_LOG_ERROR, "Error: writing av1 sequence header fail!\n");
1662 ni_log(NI_LOG_ERROR, "Error: ferror rc = %d\n", ferror(p_file));
1663 }
1664 ni_aligned_free(p_ctx->p_av1_seq_header[enc_id]);
1665 p_ctx->av1_seq_header_len[enc_id] = 0;
1666 }
1667
1668 // write the leftover av1 packets
1669 for (i = 0; i < p_out_pkt->av1_buffer_index; i++)
1670 {
1671 if (fwrite((uint8_t *)p_out_pkt->av1_p_data[i] + meta_size,
1672 p_out_pkt->av1_data_len[i] - meta_size, 1, p_file) != 1)
1673 {
1674 ni_log(NI_LOG_ERROR, "Error: writing av1 packets fail!\n");
1675 ni_log(NI_LOG_ERROR, "Error: ferror rc = %d\n", ferror(p_file));
1676 }
1677 }
1678
1679 // write the current packet
1680 if (fwrite((uint8_t *)p_out_pkt->p_data + meta_size,
1681 p_out_pkt->data_len - meta_size, 1, p_file) != 1)
1682 {
1683 ni_log(NI_LOG_ERROR, "Error: writing av1 packets fail!\n");
1684 ni_log(NI_LOG_ERROR, "Error: ferror rc = %d\n", ferror(p_file));
1685 }
1686
1687 p_ctx->av1_muxed_num_packets[enc_id]++;
1688}
1689
1690int write_av1_ivf_trailer(ni_demo_context_t *p_ctx, ni_packet_t *p_out_pkt, uint32_t meta_size, FILE *p_file)
1691{
1692 uint32_t muxed_num_packets = p_ctx->av1_muxed_num_packets[p_ctx->curr_enc_index];
1693 if (p_file)
1694 {
1695 // write the leftover packets
1696 if (p_out_pkt->av1_buffer_index > 0)
1697 {
1698 write_av1_ivf_packet(p_ctx, p_out_pkt, meta_size, p_file);
1699 }
1700
1701 // update frame_count in ivf start header
1702 if (muxed_num_packets && !p_ctx->av1_output_obu)
1703 {
1704 uint8_t frame_cnt[4] = {
1705 (muxed_num_packets & 0xff),
1706 ((muxed_num_packets >> 8) & 0xff),
1707 ((muxed_num_packets >> 16) & 0xff),
1708 ((muxed_num_packets >> 24) & 0xff)};
1709 fseek(p_file, 24, SEEK_SET);
1710 if (fwrite(frame_cnt, 4, 1, p_file) != 1)
1711 {
1712 ni_log(NI_LOG_ERROR, "Error: failed to update frame_cnt in ivf "
1713 "header!\n");
1714 ni_log(NI_LOG_ERROR, "Error: ferror rc = %d\n", ferror(p_file));
1715 return -1;
1716 }
1717 }
1718 }
1719
1720 return 0;
1721}
1722
1723/*!*****************************************************************************
1724 * \brief Receive output data from encoder
1725 *
1726 * \param p_in_data is passed in to specify new frame resolution upon sequence
1727 * change
1728 *
1729 * \return 0 - success got packet
1730 * 1 - received eos
1731 * 2 - got nothing, need retry
1732 * -1 - failure
1733 ******************************************************************************/
1735 ni_session_data_io_t *p_out_data, int output_video_width,
1736 int output_video_height, FILE *p_file, ni_session_data_io_t * p_in_data)
1737{
1738 int packet_size = NI_MAX_TX_SZ;
1739 int rc = 0;
1740 int end_flag = 0;
1741 int rx_size = 0;
1742 uint8_t enc_id = p_ctx->curr_enc_index;
1743 ni_packet_t *p_out_pkt = &(p_out_data->data.packet);
1744 int meta_size = p_enc_ctx->meta_size;
1745 ni_xcoder_params_t *p_api_param = (ni_xcoder_params_t *)p_enc_ctx->p_session_config;
1746 int64_t pts = -1;
1747 int64_t dts = -1;
1748
1749 ni_log(NI_LOG_DEBUG, "===> encoder_receive_data <===\n");
1750 if (NI_INVALID_SESSION_ID == p_enc_ctx->session_id)
1751 {
1752 // keep-alive-thread timeout will set session_id to invalid, should exit
1754 "encode session id invalid, the session should be closed\n");
1756 }
1757
1758receive_data:
1759 rc = ni_packet_buffer_alloc(p_out_pkt, packet_size);
1760 if (rc != NI_RETCODE_SUCCESS)
1761 {
1762 ni_log(NI_LOG_ERROR, "Error: malloc packet failed, ret = %d!\n", rc);
1764 }
1765
1766 rc = ni_device_session_read(p_enc_ctx, p_out_data, NI_DEVICE_TYPE_ENCODER);
1767
1768 end_flag = p_out_pkt->end_of_stream;
1769 rx_size = rc;
1770
1771 ni_log(NI_LOG_DEBUG, "encoder_receive_data: received data size=%d\n", rx_size);
1772
1773 if (rx_size > meta_size)
1774 {
1775 if (p_enc_ctx->codec_format == NI_CODEC_FORMAT_AV1)
1776 {
1777 if (p_enc_ctx->pkt_num == 0)
1778 {
1779 write_av1_ivf_header(p_ctx, output_video_width, output_video_height,
1780 p_api_param->fps_number,
1781 p_api_param->fps_denominator, p_file);
1782 // store the sequence header for next packet writing
1783 p_ctx->p_av1_seq_header[enc_id] = (uint8_t *)p_out_pkt->p_data;
1784 p_ctx->av1_seq_header_len[enc_id] = p_out_pkt->data_len;
1785 p_out_pkt->p_buffer = NULL;
1786 p_out_pkt->p_data = NULL;
1787 p_out_pkt->buffer_size = 0;
1788 p_out_pkt->data_len = 0;
1789 } else
1790 {
1791 // store the av1 unshown frames for next packet writing
1792 if (!p_out_pkt->av1_show_frame)
1793 {
1794 p_out_pkt->av1_p_buffer[p_out_pkt->av1_buffer_index] =
1795 p_out_pkt->p_buffer;
1796 p_out_pkt->av1_p_data[p_out_pkt->av1_buffer_index] =
1797 p_out_pkt->p_data;
1798 p_out_pkt->av1_buffer_size[p_out_pkt->av1_buffer_index] =
1799 p_out_pkt->buffer_size;
1800 p_out_pkt->av1_data_len[p_out_pkt->av1_buffer_index] =
1801 p_out_pkt->data_len;
1802 p_out_pkt->av1_buffer_index++;
1803 p_out_pkt->p_buffer = NULL;
1804 p_out_pkt->p_data = NULL;
1805 p_out_pkt->buffer_size = 0;
1806 p_out_pkt->data_len = 0;
1807 if (p_out_pkt->av1_buffer_index >= MAX_AV1_ENCODER_GOP_NUM)
1808 {
1809 ni_log(NI_LOG_ERROR, "Error: recv AV1 not shown frame "
1810 "number %d >= %d\n", p_out_pkt->av1_buffer_index,
1813 }
1814 } else
1815 {
1816 ni_log(NI_LOG_DEBUG, "AV1 output packet "
1817 "pts %lld dts %lld\n", p_out_pkt->pts, p_out_pkt->dts);
1818 write_av1_ivf_packet(p_ctx, p_out_pkt, p_enc_ctx->meta_size, p_file);
1819 ni_packet_buffer_free_av1(p_out_pkt);
1820 }
1821
1822 // recycle hw frame before next read
1823 if (p_enc_ctx->hw_action)
1824 {
1825 // encoder only returns valid recycle index
1826 // when there's something to recycle.
1827 // This range is suitable for all memory bins
1828 if (p_out_pkt->recycle_index > 0 &&
1829 p_out_pkt->recycle_index <
1831 {
1832 ni_hw_frame_unref(p_out_pkt->recycle_index);
1833 p_out_pkt->recycle_index = 0; //clear to not double count
1834 }
1835 }
1836 }
1837 } else
1838 {
1839 if (p_file &&
1840 (fwrite((uint8_t *)p_out_pkt->p_data + meta_size,
1841 p_out_pkt->data_len - meta_size, 1, p_file) != 1))
1842 {
1843 ni_log(NI_LOG_ERROR, "Error: writing data %u bytes error!\n",
1844 p_out_pkt->data_len - meta_size);
1845 ni_log(NI_LOG_ERROR, "Error: ferror rc = %d\n", ferror(p_file));
1846 }
1847 }
1848
1849 p_ctx->enc_total_bytes_received[enc_id] += rx_size - meta_size;
1850
1851 if (p_enc_ctx->pkt_num == 0)
1852 {
1853 p_enc_ctx->pkt_num = 1;
1854 }
1855
1856 // The first packet is the sequence head packet and it will be read before the first frame is sent
1857 if(p_ctx->num_packets_received[enc_id] != 0)
1858 {
1859 pts = p_out_pkt->pts;
1860 ni_pts_dequeue(p_ctx->enc_pts_queue[enc_id], &dts);
1861 ni_log(NI_LOG_DEBUG, "PTS: %d, DTS: %d\n", pts, dts);
1862 }
1863
1864 (p_ctx->num_packets_received[enc_id])++;
1865
1866 ni_log(NI_LOG_DEBUG, "Got: Packets= %u\n", p_ctx->num_packets_received[enc_id]);
1867 } else if (rx_size != 0)
1868 {
1869 ni_log(NI_LOG_ERROR, "Error: received %d bytes, <= metadata size %d!\n",
1870 rx_size, meta_size);
1872 } else if (end_flag)
1873 {
1875 p_enc_ctx->session_run_state)
1876 {
1877 // after sequence change completes, reset codec state
1878 ni_log(NI_LOG_INFO, "encoder_receive_data: sequence "
1879 "change completed, return SEQ_CHANGE_DONE and will reopen "
1880 "or reconfig codec!\n");
1881 rc = encoder_reinit_session(p_enc_ctx, p_in_data, p_out_data);
1882 ni_log(NI_LOG_TRACE, "encoder_receive_data: encoder_reinit_session ret %d\n", rc);
1883 if (rc == NI_RETCODE_SUCCESS)
1884 {
1886 }
1887 else
1888 {
1890 }
1891 }
1892
1894 {
1895 // restart the encoder after sending flushing command
1896 rc = ni_device_session_restart(p_enc_ctx,
1897 p_in_data->data.frame.video_width,
1898 p_in_data->data.frame.video_height,
1900 ni_log(NI_LOG_INFO, "ni_device_session_restart() ret %d\n", rc);
1901 if (rc == NI_RETCODE_SUCCESS)
1902 {
1903 // need to reset the packet end_of_stream and run state
1904 p_out_pkt->end_of_stream = 0;
1907 }
1908 else
1909 {
1911 }
1912 }
1913
1914 if (p_enc_ctx->codec_format == NI_CODEC_FORMAT_AV1)
1915 {
1916 rc = write_av1_ivf_trailer(p_ctx, p_out_pkt, p_enc_ctx->meta_size, p_file);
1917 ni_packet_buffer_free_av1(p_out_pkt);
1918 if (rc < 0)
1919 {
1921 }
1922 }
1923 ni_log(NI_LOG_INFO, "Encoder Receiving done.\n");
1925 } else if (p_api_param->low_delay_mode && p_enc_ctx->frame_num >= p_enc_ctx->pkt_num) {
1926 ni_log(NI_LOG_DEBUG, "low delay mode and NO pkt, keep reading ..\n");
1927 ni_usleep(200);
1928 goto receive_data;
1929 } else { //rx_size == 0 && !end_flag
1930 ni_log(NI_LOG_DEBUG, "no packet received from encoder, return EAGAIN and retry\n");
1932 }
1933
1934 ni_log(NI_LOG_DEBUG, "encoder_receive_data: success\n");
1935
1937}
1938
1939/*!*****************************************************************************
1940 * \brief encoder session close
1941 *
1942 * \param
1943 *
1944 * \return 0 if successful, < 0 otherwise
1945 ******************************************************************************/
1947 ni_session_data_io_t *p_in_data,
1948 ni_session_data_io_t *p_out_data)
1949{
1950 int ret = 0;
1952
1953 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);
1954#ifdef _WIN32
1955 ni_device_close(p_enc_ctx->device_handle);
1956#elif __linux__
1957 ni_device_close(p_enc_ctx->device_handle);
1958 ni_device_close(p_enc_ctx->blk_io_handle);
1959#endif
1960
1961 if (p_enc_ctx->codec_format == NI_CODEC_FORMAT_AV1 &&
1962 p_out_data->data.packet.av1_buffer_index)
1963 {
1964 ni_packet_buffer_free_av1(&(p_out_data->data.packet));
1965 }
1966 ni_frame_buffer_free(&(p_in_data->data.frame));
1967 ni_packet_buffer_free(&(p_out_data->data.packet));
1968 return ret;
1969}
1970
1972 ni_session_data_io_t *p_in_data,
1973 ni_session_data_io_t *p_out_data,
1974 int width, int height, ni_pix_fmt_t pix_fmt)
1975{
1976 ni_retcode_t ret = 0;
1977 int bit_depth;
1978 int bit_depth_factor;
1979
1980 ni_log(NI_LOG_DEBUG, "XCoder encode sequence change (reconfig): session_run_state %d\n", p_enc_ctx->session_run_state);
1981
1982 switch (pix_fmt)
1983 {
1984 case NI_PIX_FMT_YUV420P:
1985 case NI_PIX_FMT_NV12:
1986 bit_depth = 8;
1987 bit_depth_factor = 1;
1988 break;
1990 case NI_PIX_FMT_P010LE:
1991 bit_depth = 10;
1992 bit_depth_factor = 2;
1993 break;
1994 default:
1995 bit_depth = 8;
1996 bit_depth_factor = 1;
1997 break;
1998 }
1999
2000 ret = ni_device_session_sequence_change(p_enc_ctx, width, height, bit_depth_factor, NI_DEVICE_TYPE_ENCODER);
2001 if (NI_RETCODE_SUCCESS != ret)
2002 {
2003 ni_log(NI_LOG_ERROR, "Failed to send Sequence Change to Encoder Session (status = %d)\n", ret);
2004 return ret;
2005 }
2006
2007 // update session context
2008 p_enc_ctx->bit_depth_factor = bit_depth_factor;
2009 p_enc_ctx->src_bit_depth = bit_depth;
2010 // xcoder demo only support little endian (for 10-bit pixel format)
2012 p_enc_ctx->ready_to_close = 0;
2013 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
2014 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
2015 p_enc_ctx->pixel_format = p_in_data->data.frame.pixel_format;
2016 p_out_data->data.packet.end_of_stream = 0;
2017 p_in_data->data.frame.start_of_stream = 1;
2018 return ret;
2019}
2020
2022 ni_session_context_t *enc_ctx_list,
2023 ni_xcoder_params_t *p_api_param_list,
2024 int output_total, char p_enc_conf_params[][2048],
2025 char p_enc_conf_gop[][2048],
2026 ni_frame_t *p_ni_frame, int width, int height,
2027 int fps_num, int fps_den, int bitrate,
2028 int codec_format, ni_pix_fmt_t pix_fmt,
2029 int aspect_ratio_idc, int xcoder_guid,
2030 niFrameSurface1_t *p_surface, int multi_thread,
2031 bool check_zerocopy)
2032{
2033 int i, ret = 0;
2034 int color_prim = NI_COL_PRI_UNSPECIFIED;
2035 int color_trc = NI_COL_TRC_UNSPECIFIED;
2036 int color_space = NI_COL_SPC_UNSPECIFIED;
2037 int sar_num = 0;
2038 int sar_den = 0;
2039 int video_full_range_flag = 0;
2040
2041 if (p_ni_frame != NULL)
2042 {
2043 // open the encode session when the first frame arrives and the session
2044 // is not opened yet, with the source stream and user-configured encode
2045 // info both considered when constructing VUI in the stream headers
2046 color_prim = p_ni_frame->color_primaries;
2047 color_trc = p_ni_frame->color_trc;
2048 color_space = p_ni_frame->color_space;
2049 sar_num = p_ni_frame->sar_width;
2050 sar_den = p_ni_frame->sar_height;
2051 video_full_range_flag = p_ni_frame->video_full_range_flag;
2052
2053 // calculate the source fps and set it as the default target fps, based
2054 // on the timing_info passed in from the decoded frame
2055 if (p_ni_frame->vui_num_units_in_tick && p_ni_frame->vui_time_scale)
2056 {
2057 if (NI_CODEC_FORMAT_H264 == p_ni_frame->src_codec)
2058 {
2059 if (0 == p_ni_frame->vui_time_scale % 2)
2060 {
2061 fps_num = (int)(p_ni_frame->vui_time_scale / 2);
2062 fps_den = (int)(p_ni_frame->vui_num_units_in_tick);
2063 } else
2064 {
2065 fps_num = (int)(p_ni_frame->vui_time_scale);
2066 fps_den = (int)(2 * p_ni_frame->vui_num_units_in_tick);
2067 }
2068 } else if (NI_CODEC_FORMAT_H265 == p_ni_frame->src_codec)
2069 {
2070 fps_num = p_ni_frame->vui_time_scale;
2071 fps_den = p_ni_frame->vui_num_units_in_tick;
2072 }
2073 }
2074 }
2075
2076 for (i = 0; i < output_total; i++)
2077 {
2078
2079 if(!p_ctx->enc_pts_queue[i])
2080 {
2081 p_ctx->enc_pts_queue[i] = (ni_pts_queue *)calloc(1, sizeof(ni_pts_queue));
2082 if(!p_ctx->enc_pts_queue[i])
2083 {
2084 ni_log(NI_LOG_ERROR, "Failed to allocate ni_pts_queue\n");
2085 return -1;
2086 }
2087 }
2088
2089 // set up encoder p_config, using some info from source
2090 ret = ni_encoder_init_default_params(&p_api_param_list[i], fps_num,
2091 fps_den, bitrate, width, height,
2092 enc_ctx_list[i].codec_format);
2093 if (ret < 0)
2094 {
2095 ni_log(NI_LOG_ERROR, "Error encoder[%d] init default set up error\n", i);
2096 return -1;
2097 }
2098
2099 // check and set ni_encoder_params from --xcoder-params
2100 // Note: the parameter setting has to be in this order so that user
2101 // configured values can overwrite the source/default ones if
2102 // desired.
2103 if (ni_retrieve_xcoder_params(p_enc_conf_params[i],
2104 &p_api_param_list[i], &enc_ctx_list[i]))
2105 {
2106 ni_log(NI_LOG_ERROR, "Error: encoder[%d] p_config parsing error\n", i);
2107 return -1;
2108 }
2109
2110 if (ni_retrieve_xcoder_gop(p_enc_conf_gop[i],
2111 &p_api_param_list[i], &enc_ctx_list[i]))
2112 {
2113 ni_log(NI_LOG_ERROR, "Error: encoder[%d] p_config_gop parsing error\n", i);
2114 return -1;
2115 }
2116
2117 // set async mode in enc_ctx if encoding is multi-threaded
2118 if (multi_thread)
2119 {
2120 ni_log(NI_LOG_INFO, "Encoder[%d] is multi-threaded, set async mode "
2121 "in the session context!\n", i);
2122 enc_ctx_list[i].async_mode = 1;
2123 p_api_param_list[i].cfg_enc_params.enable_acq_limit = 1;
2124 }
2125
2126 // check color primaries configuration
2127 if (color_prim != p_api_param_list[i].color_primaries &&
2128 NI_COL_PRI_UNSPECIFIED != p_api_param_list[i].color_primaries)
2129 {
2130 ni_log(NI_LOG_DEBUG, "Encoder[%d] user-configured color primaries "
2131 "%d to overwrite source %d\n",
2132 i, p_api_param_list[i].color_primaries, color_prim);
2133 color_prim = p_api_param_list[i].color_primaries;
2134 }
2135
2136 // check color transfer characteristic configuration
2137 if (color_trc != p_api_param_list[i].color_transfer_characteristic &&
2138 NI_COL_TRC_UNSPECIFIED != p_api_param_list[i].color_transfer_characteristic)
2139 {
2140 ni_log(NI_LOG_DEBUG, "Encoder[%d] user-configured color trc %d to "
2141 "overwrite source %d\n", i,
2142 p_api_param_list[i].color_transfer_characteristic, color_trc);
2143 color_trc = p_api_param_list[i].color_transfer_characteristic;
2144 }
2145
2146 // check color space configuration
2147 if (color_space != p_api_param_list[i].color_space &&
2148 NI_COL_SPC_UNSPECIFIED != p_api_param_list[i].color_space)
2149 {
2150 ni_log(NI_LOG_DEBUG, "Encoder[%d] user-configured color space %d "
2151 "to overwrite source %d\n",
2152 i, p_api_param_list[i].color_space, color_space);
2153 color_space = p_api_param_list[i].color_space;
2154 }
2155
2156 // check video full range flag configuration
2157 if (p_api_param_list[i].video_full_range_flag >= 0)
2158 {
2159 ni_log(NI_LOG_DEBUG, "Encoder[%d] user-configured video full range "
2160 "flag %d\n", i, p_api_param_list[i].video_full_range_flag);
2161 video_full_range_flag = p_api_param_list[i].video_full_range_flag;
2162 }
2163
2164 // check aspect ratio indicator configuration
2165 if (aspect_ratio_idc > 0 && aspect_ratio_idc < NI_NUM_PIXEL_ASPECT_RATIO)
2166 {
2167 sar_num = ni_h264_pixel_aspect_list[aspect_ratio_idc].num;
2168 sar_den = ni_h264_pixel_aspect_list[aspect_ratio_idc].den;
2169 } else if (p_api_param_list[i].sar_denom)
2170 {
2171 sar_num = p_api_param_list[i].sar_num;
2172 sar_den = p_api_param_list[i].sar_denom;
2173 }
2174
2175 // check hwframe configuration
2176 if (p_surface != NULL)
2177 {
2178 //Items in this else condition could be improved by being handled in libxcoder
2179 enc_ctx_list[i].hw_action = NI_CODEC_HW_ENABLE;
2180 p_api_param_list[i].hwframes = 1;
2181 enc_ctx_list[i].sender_handle =
2182 (ni_device_handle_t)(int64_t)p_surface->device_handle;
2183 p_api_param_list[i].rootBufId = p_surface->ui16FrameIdx;
2184 }
2185
2186 // VUI setting including color setting is done by specifying them in the
2187 // encoder config
2188 p_api_param_list[i].cfg_enc_params.colorDescPresent = 0;
2189 if ((color_prim != NI_COL_PRI_UNSPECIFIED) ||
2190 (color_space != NI_COL_SPC_UNSPECIFIED) ||
2191 (color_trc != NI_COL_TRC_UNSPECIFIED))
2192 {
2193 p_api_param_list[i].cfg_enc_params.colorDescPresent = 1;
2194 }
2195 p_api_param_list[i].cfg_enc_params.colorPrimaries = color_prim;
2196 p_api_param_list[i].cfg_enc_params.colorTrc = color_trc;
2197 p_api_param_list[i].cfg_enc_params.colorSpace = color_space;
2198 p_api_param_list[i].cfg_enc_params.videoFullRange = video_full_range_flag;
2199 p_api_param_list[i].cfg_enc_params.aspectRatioWidth = sar_num;
2200 p_api_param_list[i].cfg_enc_params.aspectRatioHeight = sar_den;
2201
2202 ret = encoder_open_session(&enc_ctx_list[i], codec_format, xcoder_guid,
2203 &p_api_param_list[i], width, height,
2204 pix_fmt, check_zerocopy);
2205 if (ret != 0)
2206 {
2207 ni_log(NI_LOG_ERROR, "Error encoder[%d] open session failed!\n", i);
2208 return -1;
2209 }
2210
2212 p_ctx->pts[i] = 0;
2213 ni_prepare_pts_queue(p_ctx->enc_pts_queue[i], &p_api_param_list[i], p_ctx->pts[i]);
2214 }
2215
2216 return ret;
2217}
2218
2219// encoder_open2() is used for the encoder with a scaler filter, supporting ladder encoding with multiple resolutions.
2221 ni_session_context_t *enc_ctx_list,
2222 ni_xcoder_params_t *p_api_param_list,
2223 int output_total, char p_enc_conf_params[][2048],
2224 char p_enc_conf_gop[][2048],
2225 ni_frame_t *p_ni_frame, int width[], int height[],
2226 int fps_num, int fps_den, int bitrate,
2227 int codec_format, ni_pix_fmt_t pix_fmt[],
2228 int aspect_ratio_idc, int xcoder_guid,
2229 niFrameSurface1_t *p_surface[], int multi_thread,
2230 bool check_zerocopy)
2231{
2232 int i, ret = 0;
2233 int color_prim = NI_COL_PRI_UNSPECIFIED;
2234 int color_trc = NI_COL_TRC_UNSPECIFIED;
2235 int color_space = NI_COL_SPC_UNSPECIFIED;
2236 int sar_num = 0;
2237 int sar_den = 0;
2238 int video_full_range_flag = 0;
2239
2240 if (p_ni_frame != NULL)
2241 {
2242 // open the encode session when the first frame arrives and the session
2243 // is not opened yet, with the source stream and user-configured encode
2244 // info both considered when constructing VUI in the stream headers
2245 color_prim = p_ni_frame->color_primaries;
2246 color_trc = p_ni_frame->color_trc;
2247 color_space = p_ni_frame->color_space;
2248 sar_num = p_ni_frame->sar_width;
2249 sar_den = p_ni_frame->sar_height;
2250 video_full_range_flag = p_ni_frame->video_full_range_flag;
2251
2252 // calculate the source fps and set it as the default target fps, based
2253 // on the timing_info passed in from the decoded frame
2254 if (p_ni_frame->vui_num_units_in_tick && p_ni_frame->vui_time_scale)
2255 {
2256 if (NI_CODEC_FORMAT_H264 == p_ni_frame->src_codec)
2257 {
2258 if (0 == p_ni_frame->vui_time_scale % 2)
2259 {
2260 fps_num = (int)(p_ni_frame->vui_time_scale / 2);
2261 fps_den = (int)(p_ni_frame->vui_num_units_in_tick);
2262 } else
2263 {
2264 fps_num = (int)(p_ni_frame->vui_time_scale);
2265 fps_den = (int)(2 * p_ni_frame->vui_num_units_in_tick);
2266 }
2267 } else if (NI_CODEC_FORMAT_H265 == p_ni_frame->src_codec)
2268 {
2269 fps_num = p_ni_frame->vui_time_scale;
2270 fps_den = p_ni_frame->vui_num_units_in_tick;
2271 }
2272 }
2273 }
2274
2275 for (i = 0; i < output_total; i++)
2276 {
2277
2278 if(!p_ctx->enc_pts_queue[i])
2279 {
2280 p_ctx->enc_pts_queue[i] = (ni_pts_queue *)calloc(1, sizeof(ni_pts_queue));
2281 if(!p_ctx->enc_pts_queue[i])
2282 {
2283 ni_log(NI_LOG_ERROR, "Failed to allocate ni_pts_queue\n");
2284 return -1;
2285 }
2286 }
2287
2288 // set up encoder p_config, using some info from source
2289 ret = ni_encoder_init_default_params(&p_api_param_list[i], fps_num,
2290 fps_den, bitrate, width[i], height[i],
2291 enc_ctx_list[i].codec_format);
2292 if (ret < 0)
2293 {
2294 ni_log(NI_LOG_ERROR, "Error encoder[%d] init default set up error\n", i);
2295 return -1;
2296 }
2297
2298 // check and set ni_encoder_params from --xcoder-params
2299 // Note: the parameter setting has to be in this order so that user
2300 // configured values can overwrite the source/default ones if
2301 // desired.
2302 if (ni_retrieve_xcoder_params(p_enc_conf_params[i],
2303 &p_api_param_list[i], &enc_ctx_list[i]))
2304 {
2305 ni_log(NI_LOG_ERROR, "Error: encoder[%d] p_config parsing error\n", i);
2306 return -1;
2307 }
2308
2309 if (ni_retrieve_xcoder_gop(p_enc_conf_gop[i],
2310 &p_api_param_list[i], &enc_ctx_list[i]))
2311 {
2312 ni_log(NI_LOG_ERROR, "Error: encoder[%d] p_config_gop parsing error\n", i);
2313 return -1;
2314 }
2315
2316 // set async mode in enc_ctx if encoding is multi-threaded
2317 if (multi_thread)
2318 {
2319 ni_log(NI_LOG_INFO, "Encoder[%d] is multi-threaded, set async mode "
2320 "in the session context!\n", i);
2321 enc_ctx_list[i].async_mode = 1;
2322 p_api_param_list[i].cfg_enc_params.enable_acq_limit = 1;
2323 }
2324
2325 // check color primaries configuration
2326 if (color_prim != p_api_param_list[i].color_primaries &&
2327 NI_COL_PRI_UNSPECIFIED != p_api_param_list[i].color_primaries)
2328 {
2329 ni_log(NI_LOG_DEBUG, "Encoder[%d] user-configured color primaries "
2330 "%d to overwrite source %d\n",
2331 i, p_api_param_list[i].color_primaries, color_prim);
2332 color_prim = p_api_param_list[i].color_primaries;
2333 }
2334
2335 // check color transfer characteristic configuration
2336 if (color_trc != p_api_param_list[i].color_transfer_characteristic &&
2337 NI_COL_TRC_UNSPECIFIED != p_api_param_list[i].color_transfer_characteristic)
2338 {
2339 ni_log(NI_LOG_DEBUG, "Encoder[%d] user-configured color trc %d to "
2340 "overwrite source %d\n", i,
2341 p_api_param_list[i].color_transfer_characteristic, color_trc);
2342 color_trc = p_api_param_list[i].color_transfer_characteristic;
2343 }
2344
2345 // check color space configuration
2346 if (color_space != p_api_param_list[i].color_space &&
2347 NI_COL_SPC_UNSPECIFIED != p_api_param_list[i].color_space)
2348 {
2349 ni_log(NI_LOG_DEBUG, "Encoder[%d] user-configured color space %d "
2350 "to overwrite source %d\n",
2351 i, p_api_param_list[i].color_space, color_space);
2352 color_space = p_api_param_list[i].color_space;
2353 }
2354
2355 // check video full range flag configuration
2356 if (p_api_param_list[i].video_full_range_flag >= 0)
2357 {
2358 ni_log(NI_LOG_DEBUG, "Encoder[%d] user-configured video full range "
2359 "flag %d\n", i, p_api_param_list[i].video_full_range_flag);
2360 video_full_range_flag = p_api_param_list[i].video_full_range_flag;
2361 }
2362
2363 // check aspect ratio indicator configuration
2364 if (aspect_ratio_idc > 0 && aspect_ratio_idc < NI_NUM_PIXEL_ASPECT_RATIO)
2365 {
2366 sar_num = ni_h264_pixel_aspect_list[aspect_ratio_idc].num;
2367 sar_den = ni_h264_pixel_aspect_list[aspect_ratio_idc].den;
2368 } else if (p_api_param_list[i].sar_denom)
2369 {
2370 sar_num = p_api_param_list[i].sar_num;
2371 sar_den = p_api_param_list[i].sar_denom;
2372 }
2373
2374 // check hwframe configuration
2375 if (p_surface[i] != NULL)
2376 {
2377 //Items in this else condition could be improved by being handled in libxcoder
2378 enc_ctx_list[i].hw_action = NI_CODEC_HW_ENABLE;
2379 p_api_param_list[i].hwframes = 1;
2380 enc_ctx_list[i].sender_handle =
2381 (ni_device_handle_t)(int64_t)p_surface[i]->device_handle;
2382 p_api_param_list[i].rootBufId = p_surface[i]->ui16FrameIdx;
2383 }
2384
2385 // VUI setting including color setting is done by specifying them in the
2386 // encoder config
2387 p_api_param_list[i].cfg_enc_params.colorDescPresent = 0;
2388 if ((color_prim != NI_COL_PRI_UNSPECIFIED) ||
2389 (color_space != NI_COL_SPC_UNSPECIFIED) ||
2390 (color_trc != NI_COL_TRC_UNSPECIFIED))
2391 {
2392 p_api_param_list[i].cfg_enc_params.colorDescPresent = 1;
2393 }
2394 p_api_param_list[i].cfg_enc_params.colorPrimaries = color_prim;
2395 p_api_param_list[i].cfg_enc_params.colorTrc = color_trc;
2396 p_api_param_list[i].cfg_enc_params.colorSpace = color_space;
2397 p_api_param_list[i].cfg_enc_params.videoFullRange = video_full_range_flag;
2398 p_api_param_list[i].cfg_enc_params.aspectRatioWidth = sar_num;
2399 p_api_param_list[i].cfg_enc_params.aspectRatioHeight = sar_den;
2400
2401 ret = encoder_open_session(&enc_ctx_list[i], codec_format, xcoder_guid,
2402 &p_api_param_list[i], width[i], height[i],
2403 pix_fmt[i], check_zerocopy);
2404 if (ret != 0)
2405 {
2406 ni_log(NI_LOG_ERROR, "Error encoder[%d] open session failed!\n", i);
2407 return -1;
2408 }
2409
2411 p_ctx->pts[i] = 0;
2412 ni_prepare_pts_queue(p_ctx->enc_pts_queue[i], &p_api_param_list[i], p_ctx->pts[i]);
2413 }
2414
2415 return ret;
2416}
2417
2419 ni_session_context_t *enc_ctx_list,
2420 ni_session_data_io_t *in_frame,
2421 ni_session_data_io_t *pkt, int width, int height,
2422 int output_total, FILE **pfs_list)
2423{
2424 int i, recycle_index;
2425 int recv_fin_flag = NI_TEST_RETCODE_SUCCESS;
2426 uint64_t prev_num_pkt[MAX_OUTPUT_FILES] = {0};
2427 ni_session_data_io_t *p_out_pkt = pkt;
2428
2429 for (i = 0; i < output_total; i++)
2430 {
2431 if (enc_ctx_list[i].codec_format == NI_CODEC_FORMAT_AV1)
2432 {
2433 p_out_pkt = &pkt[i];
2434 }
2435 p_out_pkt->data.packet.end_of_stream = 0;
2436 prev_num_pkt[i] = p_ctx->num_packets_received[i];
2437
2438 p_ctx->curr_enc_index = i;
2439 recv_fin_flag = encoder_receive_data(p_ctx, &enc_ctx_list[i], p_out_pkt, width,
2440 height, pfs_list[i], in_frame);
2441
2442 recycle_index = p_out_pkt->data.packet.recycle_index;
2443 if (prev_num_pkt[i] < p_ctx->num_packets_received[i] &&
2444 enc_ctx_list[i].hw_action && recycle_index > 0 &&
2445 recycle_index < NI_GET_MAX_HWDESC_FRAME_INDEX(enc_ctx_list[i].ddr_config))
2446 {
2447 //encoder only returns valid recycle index
2448 //when there's something to recycle.
2449 //This range is suitable for all memory bins
2450 ni_hw_frame_unref(recycle_index);
2451 } else
2452 {
2453 ni_log(NI_LOG_DEBUG, "enc %d recv, prev_num_pkt %llu "
2454 "number_of_packets_list %u recycle_index %u\n", i,
2455 prev_num_pkt[i], p_ctx->num_packets_received[i], recycle_index);
2456 }
2457
2458 if (prev_num_pkt[i] < p_ctx->num_packets_received[i] &&
2459 enc_ctx_list[i].codec_format == NI_CODEC_FORMAT_AV1 &&
2460 p_ctx->num_packets_received[i] > 1)
2461 {
2462 // For low delay mode encoding, only one packet is received for one
2463 // frame sent. For non low delay mode, there will be multiple
2464 // packets received for one frame sent. So we need to read out all
2465 // the packets encoded.
2466 ni_xcoder_params_t *p_api_param =
2467 (ni_xcoder_params_t *)enc_ctx_list[i].p_session_config;
2468 if (!p_api_param->low_delay_mode)
2469 {
2470 i--;
2471 continue;
2472 }
2473 }
2474
2475 p_ctx->enc_eos_received[i] = p_out_pkt->data.packet.end_of_stream;
2476
2477 if (recv_fin_flag < 0)
2478 {
2479 ni_log(NI_LOG_DEBUG, "enc %d error, quit !\n", i);
2480 break;
2481 } else if (recv_fin_flag == NI_TEST_RETCODE_EAGAIN)
2482 {
2483 ni_usleep(100);
2484 }
2485 }
2486
2487 return recv_fin_flag;
2488}
2489
2490// encoder_receive2() is used for the encoder with a scaler filter, supporting ladder encoding with multiple resolutions.
2492 ni_session_context_t *enc_ctx_list,
2493 ni_session_data_io_t *in_frame,
2494 ni_session_data_io_t *pkt, int width[], int height[],
2495 int output_total, FILE **pfs_list)
2496{
2497 int i, recycle_index;
2498 int recv_fin_flag = NI_TEST_RETCODE_SUCCESS;
2499 uint64_t prev_num_pkt[MAX_OUTPUT_FILES] = {0};
2500 ni_session_data_io_t *p_out_pkt = pkt;
2501
2502 for (i = 0; i < output_total; i++)
2503 {
2504 if (enc_ctx_list[i].codec_format == NI_CODEC_FORMAT_AV1)
2505 {
2506 p_out_pkt = &pkt[i];
2507 }
2508 p_out_pkt->data.packet.end_of_stream = 0;
2509 prev_num_pkt[i] = p_ctx->num_packets_received[i];
2510
2511 p_ctx->curr_enc_index = i;
2512 recv_fin_flag = encoder_receive_data(p_ctx, &enc_ctx_list[i], p_out_pkt, width[i],
2513 height[i], pfs_list[i], in_frame);
2514
2515 recycle_index = p_out_pkt->data.packet.recycle_index;
2516 if (prev_num_pkt[i] < p_ctx->num_packets_received[i] &&
2517 enc_ctx_list[i].hw_action && recycle_index > 0 &&
2518 recycle_index < NI_GET_MAX_HWDESC_FRAME_INDEX(enc_ctx_list[i].ddr_config))
2519 {
2520 //encoder only returns valid recycle index
2521 //when there's something to recycle.
2522 //This range is suitable for all memory bins
2523 ni_hw_frame_unref(recycle_index);
2524 } else
2525 {
2526 ni_log(NI_LOG_DEBUG, "enc %d recv, prev_num_pkt %llu "
2527 "number_of_packets_list %u recycle_index %u\n", i,
2528 prev_num_pkt[i], p_ctx->num_packets_received[i], recycle_index);
2529 }
2530
2531 if (prev_num_pkt[i] < p_ctx->num_packets_received[i] &&
2532 enc_ctx_list[i].codec_format == NI_CODEC_FORMAT_AV1 &&
2533 p_ctx->num_packets_received[i] > 1)
2534 {
2535 // For low delay mode encoding, only one packet is received for one
2536 // frame sent. For non low delay mode, there will be multiple
2537 // packets received for one frame sent. So we need to read out all
2538 // the packets encoded.
2539 ni_xcoder_params_t *p_api_param =
2540 (ni_xcoder_params_t *)enc_ctx_list[i].p_session_config;
2541 if (!p_api_param->low_delay_mode)
2542 {
2543 i--;
2544 continue;
2545 }
2546 }
2547
2548 p_ctx->enc_eos_received[i] = p_out_pkt->data.packet.end_of_stream;
2549
2550 if (recv_fin_flag < 0)
2551 {
2552 ni_log(NI_LOG_DEBUG, "enc %d error, quit !\n", i);
2553 break;
2554 } else if (recv_fin_flag == NI_TEST_RETCODE_EAGAIN)
2555 {
2556 ni_usleep(100);
2557 }
2558 }
2559
2560 return recv_fin_flag;
2561}
2562
2563void encoder_stat_report_and_close(ni_demo_context_t *p_ctx, ni_session_context_t *p_enc_ctx_list, int output_total)
2564{
2565 int i;
2566 int nb_recycled;
2567 uint64_t current_time;
2568
2570
2571 nb_recycled = scan_and_clean_hwdescriptors();
2572
2573 for (i = 0; i < output_total; i++)
2574 {
2575 ni_log(NI_LOG_ERROR, "Encoder %d closing, Got: Packets=%u FPS=%.2f Total bytes %llu\n",
2576 (int)i, p_ctx->num_packets_received[i],
2577 (float)p_enc_ctx_list[i].frame_num / (float)(current_time - p_ctx->start_time) * (float)1000000000,
2578 p_ctx->enc_total_bytes_received[i]);
2579
2580 ni_device_session_close(&p_enc_ctx_list[i], 1, NI_DEVICE_TYPE_ENCODER);
2581 }
2582
2583 ni_log(NI_LOG_DEBUG, "Cleanup recycled %d internal buffers\n",
2584 nb_recycled);
2585}
2586
2587void *encoder_send_thread(void *args)
2588{
2589 enc_send_param_t *p_enc_send_param = args;
2590 ni_demo_context_t *p_ctx = p_enc_send_param->p_ctx;
2591 ni_session_context_t *p_enc_ctx_list = p_enc_send_param->p_enc_ctx;
2592 ni_test_frame_list_t *frame_list = p_enc_send_param->frame_list;
2593 ni_session_data_io_t *p_dec_frame = NULL;
2594 ni_session_data_io_t enc_in_frame = {0};
2595 ni_frame_t *p_ni_frame = NULL;
2596 niFrameSurface1_t *p_surface;
2597 int i, ret = 0;
2598
2599 ni_log(NI_LOG_INFO, "%s start\n", __func__);
2600
2601 for (;;)
2602 {
2603 while (frame_list_is_empty(frame_list) && !p_ctx->end_all_threads)
2604 {
2605 ni_usleep(100);
2606 }
2607
2608 if (p_ctx->end_all_threads)
2609 {
2610 break;
2611 }
2612
2613 p_dec_frame = &frame_list->frames[frame_list->head];
2614 p_ni_frame = &p_dec_frame->data.frame;
2615
2616 for (i = 0; i < p_enc_send_param->output_total; i++)
2617 {
2618 p_ctx->curr_enc_index = i;
2619 ret = encoder_send_data2(p_ctx, &p_enc_ctx_list[i], p_dec_frame,
2620 &enc_in_frame,
2621 p_enc_send_param->output_width,
2622 p_enc_send_param->output_height);
2623 if (ret < 0) //Error
2624 {
2625 if (p_enc_ctx_list[i].hw_action)
2626 {
2627 //pre close cleanup will clear it out
2628 p_surface = (niFrameSurface1_t *)p_ni_frame->p_data[3];
2629 ni_hw_frame_ref(p_surface);
2630 } else
2631 {
2632 ni_decoder_frame_buffer_free(p_ni_frame);
2633 }
2634 frame_list_drain(frame_list);
2635 ni_log(NI_LOG_ERROR, "Error: encoder send frame failed\n");
2636 break;
2637 } else if (ret == NI_TEST_RETCODE_EAGAIN) {
2638 ni_usleep(100);
2639 i--; //resend frame
2640 continue;
2641 } else if (p_enc_ctx_list[0].hw_action && !p_ctx->enc_eos_sent[i])
2642 {
2643 p_surface = (niFrameSurface1_t *)p_ni_frame->p_data[3];
2644 ni_hw_frame_ref(p_surface);
2645 }
2646 }
2647
2648 if (ret < 0)
2649 {
2650 break;
2651 } else if (p_enc_ctx_list[0].hw_action)
2652 {
2653 ni_frame_wipe_aux_data(p_ni_frame); //reuse buffer
2654 } else
2655 {
2656 ni_decoder_frame_buffer_free(p_ni_frame);
2657 }
2658 frame_list_drain(frame_list);
2659
2660 if (p_enc_send_param->p_ctx->enc_eos_sent[0]) // eos
2661 {
2662 ni_log(NI_LOG_INFO, "%s EOS sent\n", __func__);
2663 break;
2664 }
2665 }
2666
2667 ni_frame_buffer_free(&enc_in_frame.data.frame);
2668
2669 // Broadcast all codec threads to quit on exception such as NVMe IO
2670 if (ret < 0)
2671 {
2672 p_ctx->end_all_threads = 1;
2673 }
2674
2675 ni_log(NI_LOG_TRACE, "%s exit\n", __func__);
2676 return (void *)(int64_t)ret;
2677}
2678
2679void *encoder_receive_thread(void *args)
2680{
2681 enc_recv_param_t *p_enc_recv_param = args;
2682 ni_demo_context_t *p_ctx = p_enc_recv_param->p_ctx;
2683 ni_session_context_t *p_enc_ctx = p_enc_recv_param->p_enc_ctx;
2684 ni_session_data_io_t out_packet[MAX_OUTPUT_FILES] = {0};
2685 int i, ret = 0;
2686 int end_of_all_streams = 0;
2687 uint64_t current_time, previous_time = p_ctx->start_time;
2688
2689 ni_log(NI_LOG_INFO, "encoder_receive_thread start\n");
2690
2691 while (!end_of_all_streams && ret >= 0 && !p_ctx->end_all_threads)
2692 {
2693 ret = encoder_receive(p_ctx, p_enc_ctx,
2694 &p_enc_recv_param->frame_list->frames[p_enc_recv_param->frame_list->head],
2695 out_packet, p_enc_recv_param->output_width,
2696 p_enc_recv_param->output_height, p_enc_recv_param->output_total,
2697 p_enc_recv_param->p_file);
2698 for (i = 0; ret >= 0 && i < p_enc_recv_param->output_total; i++)
2699 {
2700 if (!p_ctx->enc_eos_received[i])
2701 {
2702 ni_log(NI_LOG_DEBUG, "enc %d continues to read!\n", i);
2703 end_of_all_streams = 0;
2704 break;
2705 } else
2706 {
2707 ni_log(NI_LOG_DEBUG, "enc %d eos !\n", i);
2708 end_of_all_streams = 1;
2709 }
2710 }
2711
2713 if (current_time - previous_time >= (uint64_t)1000000000) {
2714 for (i = 0; i < p_enc_recv_param->output_total; i++)
2715 {
2716 ni_log(NI_LOG_INFO, "Encoder %d stats: received %u packets, fps %.2f, total bytes %u\n",
2717 i, p_ctx->num_packets_received[i],
2718 (float)p_enc_ctx[i].frame_num / (float)(current_time - p_ctx->start_time) * (float)1000000000,
2719 p_ctx->enc_total_bytes_received[i]);
2720 }
2722 }
2723 }
2724
2725 for (i = 0; i < p_enc_recv_param->output_total; i++)
2726 {
2727 ni_packet_buffer_free(&out_packet[i].data.packet);
2728 }
2729
2730 // Broadcast all codec threads to quit on exception such as NVMe IO.
2731 if (ret < 0)
2732 {
2733 p_ctx->end_all_threads = 1;
2734 }
2735
2736 ni_log(NI_LOG_TRACE, "%s exit\n", __func__);
2737 return (void *)(int64_t)ret;
2738}
2739
2741{
2742 q->front = 0;
2743 q->rear = 0;
2744 q->size = 0;
2745}
2747{
2748 return q->size == 0;
2749}
2751{
2752 return q->size == NI_MAX_PTS_QUEUE_SIZE;
2753}
2754int ni_pts_enqueue(ni_pts_queue *q, int64_t value)
2755{
2756 if(ni_pts_queue_full(q))
2757 {
2758 ni_log(NI_LOG_ERROR, "Failed to enqueue, ni_pts_queue is full\n");
2759 return 0;
2760 }
2761
2762 q->data[q->rear] = value;
2763 q->rear = (q->rear + 1) % NI_MAX_PTS_QUEUE_SIZE;
2764 ++q->size;
2765 return 1;
2766}
2767int ni_pts_dequeue(ni_pts_queue *q, int64_t *value)
2768{
2769 if(ni_pts_queue_empty(q))
2770 {
2771 ni_log(NI_LOG_ERROR, "Failed to dequeue, ni_pts_queue is empty\n");
2772 }
2773 *value = q->data[q->front];
2774 q->front = (q->front + 1) % NI_MAX_PTS_QUEUE_SIZE;
2775 --q->size;
2776 return 1;
2777}
2778
2779void ni_prepare_pts_queue(ni_pts_queue *q, ni_xcoder_params_t *enc_param, int pts_start)
2780{
2781 int dtsOffset = 0;
2782
2783 switch (enc_param->cfg_enc_params.gop_preset_index)
2784 {
2785 /* dtsOffset is the max number of non-reference frames in a GOP
2786 * (derived from x264/5 algo) In case of IBBBP the first dts of the I
2787 * frame should be input_pts-(3*ticks_per_frame) In case of IBP the
2788 * first dts of the I frame should be input_pts-(1*ticks_per_frame)
2789 * thus we ensure pts>dts in all cases
2790 * */
2791 case 1:
2792 case 9:
2793 case 10:
2794 dtsOffset = 0;
2795 break;
2796 /* ts requires dts/pts of I fraem not same when there are B frames in
2797 * streams */
2798 case 3:
2799 case 4:
2800 case 7:
2801 dtsOffset = 1;
2802 break;
2803 case 5:
2804 dtsOffset = 2;
2805 break;
2806 case -1: // adaptive GOP
2807 case 8:
2808 dtsOffset = 3;
2809 break;
2810 default:
2811 dtsOffset = 7;
2812 break;
2813 }
2814
2816 {
2817 int dts_offset;
2818 dtsOffset = 0;
2819 int has_b_frame = 0;
2820 for (int idx = 0;
2822 idx++)
2823 {
2824 if (enc_param->cfg_enc_params.custom_gop_params.pic_param[idx].poc_offset < idx + 1)
2825 {
2826 dts_offset = (idx + 1) - enc_param->cfg_enc_params.custom_gop_params.pic_param[idx].poc_offset;
2827 if (dtsOffset < dts_offset)
2828 {
2829 dtsOffset = dts_offset;
2830 }
2831 }
2832
2833 if (!has_b_frame &&
2835 {
2836 has_b_frame = 1;
2837 }
2838 }
2839
2840 if (has_b_frame && !dtsOffset)
2841 {
2842 dtsOffset = 1;
2843 }
2844 }
2845
2846 for (int i = 0; i < dtsOffset; ++i)
2847 {
2848 ni_pts_enqueue(q, i - dtsOffset + pts_start);
2849 }
2850}
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:442
@ NI_RETCODE_SUCCESS
Definition ni_defs.h:443
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
#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_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_OFF
#define NI_MIN_WIDTH
@ 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
#define NI_PARAM_AV1_ALIGN_WIDTH_HEIGHT
#define NI_INVALID_SESSION_ID
@ 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
#define NI_MULTICORE_ENCODE_MIN_HEIGHT
@ NI_SET_CHANGE_PARAM_VUI_HRD_PARAM
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_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:4416
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:4202
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:2664
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:4490
void ni_usleep(int64_t usec)
Definition ni_util.c:362
uint64_t ni_gettime_ns(void)
Definition ni_util.c:2622
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:2976
Utility definitions.
#define ni_aligned_free(p_memptr)
Definition ni_util.h:400
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
uint8_t * av1_p_buffer[MAX_AV1_ENCODER_GOP_NUM]
uint32_t buffer_size
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_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