libxcoder 5.6.0
Loading...
Searching...
No Matches
ni_av_codec.c
Go to the documentation of this file.
1/*******************************************************************************
2 *
3 * Copyright (C) 2022 NETINT Technologies
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
17 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
18 * SOFTWARE.
19 *
20 ******************************************************************************/
21
22/*!*****************************************************************************
23 * \file ni_av_codec.c
24 *
25 * \brief Audio/video related utility definitions
26 ******************************************************************************/
27
28#ifdef _WIN32
29#include <winsock2.h>
30#else
31#include <arpa/inet.h>
32#endif
33#include <limits.h>
34#include <string.h>
35#include <stdio.h>
36#include <math.h>
37#include "ni_util.h"
38#include "ni_nvme.h"
39#include "ni_bitstream.h"
40#include "ni_av_codec.h"
41#include "ni_device_api_priv.h"
42
50
75
76NI_UNUSED static const int32_t GOP_SIZE[NUM_GOP_PRESET_NUM] = {0, 1, 1, 1, 2, 4, 4,
77 4, 8, 1, 2, 4, 4};
78
79static const int32_t LT_GOP_PRESET_I_1[6] = {SLICE_TYPE_I, 1, 0, 0, 0, 0};
80static const int32_t LT_GOP_PRESET_P_1[6] = {SLICE_TYPE_MP, 1, 1, 0, 0, -1};
81static const int32_t LT_GOP_PRESET_B_1[6] = {SLICE_TYPE_B, 1, 1, 0, 0, -1};
82// gop_size = 2
83static const int32_t LT_GOP_PRESET_BP_2[12] = {
84 SLICE_TYPE_MP, 2, 1, 0, 0, -2, SLICE_TYPE_B, 1, 3, 0, 0, 2,
85};
86// gop_size = 4
87static const int32_t LT_GOP_PRESET_BBBP_4[24] = {
88 SLICE_TYPE_MP, 4, 1, 0, 0, -4, SLICE_TYPE_B, 2, 3, 0, 0, 4,
89 SLICE_TYPE_B, 1, 5, 0, 0, 2, SLICE_TYPE_B, 3, 5, 0, 2, 4,
90};
91
92static const int32_t LT_GOP_PRESET_LP_4[24] = {
93 SLICE_TYPE_MP, 1, 5, 0, 0, -4, SLICE_TYPE_MP, 2, 3, 0, 1, 0,
94 SLICE_TYPE_MP, 3, 5, 0, 2, 0, SLICE_TYPE_MP, 4, 1, 0, 3, 0,
95};
96static const int32_t LT_GOP_PRESET_LD_4[24] = {
97 SLICE_TYPE_B, 1, 5, 0, 0, -4, SLICE_TYPE_B, 2, 3, 0, 1, 0,
98 SLICE_TYPE_B, 3, 5, 0, 2, 0, SLICE_TYPE_B, 4, 1, 0, 3, 0,
99};
100
101// gop_size = 8
102static const int32_t LT_GOP_PRESET_RA_8[48] = {
103 SLICE_TYPE_B, 8, 1, 0, 0, -8, SLICE_TYPE_B, 4, 3, 0, 0, 8,
104 SLICE_TYPE_B, 2, 5, 0, 0, 4, SLICE_TYPE_B, 1, 8, 0, 0, 2,
105 SLICE_TYPE_B, 3, 8, 0, 2, 4, SLICE_TYPE_B, 6, 5, 0, 4, 8,
106 SLICE_TYPE_B, 5, 8, 0, 4, 6, SLICE_TYPE_B, 7, 8, 0, 6, 8,
107};
108// single-ref-P
109static const int32_t LT_GOP_PRESET_SP_1[6] = {SLICE_TYPE_P, 1, 1, 0, 0, -1};
110
111static const int32_t LT_GOP_PRESET_BSP_2[12] = {
112 SLICE_TYPE_P, 2, 1, 0, 0, -2, SLICE_TYPE_B, 1, 3, 0, 0, 2,
113};
114static const int32_t LT_GOP_PRESET_BBBSP_4[24] = {
115 SLICE_TYPE_P, 4, 1, 0, 0, -4, SLICE_TYPE_B, 2, 3, 0, 0, 4,
116 SLICE_TYPE_B, 1, 5, 0, 0, 2, SLICE_TYPE_B, 3, 5, 0, 2, 4,
117};
118static const int32_t LT_GOP_PRESET_LSP_4[24] = {
119 SLICE_TYPE_P, 1, 5, 0, 0, -4, SLICE_TYPE_P, 2, 3, 0, 1, 0,
120 SLICE_TYPE_P, 3, 5, 0, 2, 0, SLICE_TYPE_P, 4, 1, 0, 3, 0,
121};
122
123static const int32_t LT_GOP_PRESET_BBP_3[18] = {
124 SLICE_TYPE_MP, 3, 1, 0, 0, -3, SLICE_TYPE_B, 1, 3, 0, 0, 3,
125 SLICE_TYPE_B, 2, 6, 0, 1, 3,
126};
127
128static const int32_t LT_GOP_PRESET_BBSP_3[18] = {
129 SLICE_TYPE_P, 3, 1, 0, 0, 0, SLICE_TYPE_B, 1, 3, 0, 0, 3,
130 SLICE_TYPE_B, 2, 6, 0, 1, 3,
131};
132
133static const int32_t LT_GOP_PRESET_BBBBBBBP_8[48] = {
134 SLICE_TYPE_MP, 8, 1, 0, 0, -8, SLICE_TYPE_B, 4, 3, 0, 0, 8,
135 SLICE_TYPE_B, 2, 5, 0, 0, 4, SLICE_TYPE_B, 1, 8, 0, 0, 2,
136 SLICE_TYPE_B, 3, 8, 0, 2, 4, SLICE_TYPE_B, 6, 5, 0, 4, 8,
137 SLICE_TYPE_B, 5, 8, 0, 4, 6, SLICE_TYPE_B, 7, 8, 0, 6, 8,
138};
139
140static const int32_t LT_GOP_PRESET_BBBBBBBSP_8[48] = {
141 SLICE_TYPE_P, 8, 1, 0, 0, 0, SLICE_TYPE_B, 4, 3, 0, 0, 8,
142 SLICE_TYPE_B, 2, 5, 0, 0, 4, SLICE_TYPE_B, 1, 8, 0, 0, 2,
143 SLICE_TYPE_B, 3, 8, 0, 2, 4, SLICE_TYPE_B, 6, 5, 0, 4, 8,
144 SLICE_TYPE_B, 5, 8, 0, 4, 6, SLICE_TYPE_B, 7, 8, 0, 6, 8,
145};
146
147NI_UNUSED static const int32_t *GOP_PRESET[NUM_GOP_PRESET_NUM] = {
148 NULL,
149 LT_GOP_PRESET_I_1,
150 LT_GOP_PRESET_P_1,
151 LT_GOP_PRESET_B_1,
152 LT_GOP_PRESET_BP_2,
153 LT_GOP_PRESET_BBBP_4,
154 LT_GOP_PRESET_LP_4,
155 LT_GOP_PRESET_LD_4,
156 LT_GOP_PRESET_RA_8,
157
158 LT_GOP_PRESET_SP_1,
159 LT_GOP_PRESET_BSP_2,
160 LT_GOP_PRESET_BBBSP_4,
161 LT_GOP_PRESET_LSP_4,
162
163 LT_GOP_PRESET_BBP_3,
164 LT_GOP_PRESET_BBSP_3,
165 LT_GOP_PRESET_BBBBBBBP_8,
166 LT_GOP_PRESET_BBBBBBBSP_8,
167};
168
169#define BR_SHIFT 6
170#define CPB_SHIFT 4
171
172#define SAMPLE_SPS_MAX_SUB_LAYERS_MINUS1 0
173#define MAX_VPS_MAX_SUB_LAYERS 16
174#define MAX_CPB_COUNT 16
175#define MAX_DURATION 0.5
176
177/*!*****************************************************************************
178 * \brief Whether SEI (HDR) should be sent together with this frame to encoder
179 *
180 * \param[in] p_enc_ctx encoder session context
181 * \param[in] pic_type frame type
182 * \param[in] p_param encoder parameters
183 *
184 * \return 1 if yes, 0 otherwise
185 ******************************************************************************/
187 ni_pic_type_t pic_type,
188 ni_xcoder_params_t *p_param)
189{
190 // repeatHeaders = 0. send on first frame only (IDR)
191 // repeatHeaders = 1. send on every I-frame including I-frames generated
192 // on the intraPeriod interval as well as I-frames that are forced.
193 if (0 == p_enc_ctx->frame_num || PIC_TYPE_IDR == pic_type ||
195 p_param->cfg_enc_params.intra_period &&
196 0 ==
197 ((p_enc_ctx->frame_num + p_enc_ctx->force_idr_intra_offset) %
198 p_param->cfg_enc_params.intra_period)))
199 {
200 if (PIC_TYPE_IDR == pic_type &&
202 p_param->cfg_enc_params.intra_period &&
203 0 != (p_enc_ctx->frame_num % p_param->cfg_enc_params.intra_period))
204 {
205 p_enc_ctx->force_idr_intra_offset =
207 (p_enc_ctx->frame_num % p_param->cfg_enc_params.intra_period);
208 }
209 ni_log2(p_enc_ctx, NI_LOG_TRACE, "should send sei? %" PRIu64 " %d %d %d %u\n",
210 p_enc_ctx->frame_num, pic_type,
213 p_enc_ctx->force_idr_intra_offset);
214 return 1;
215 }
216 return 0;
217}
218
219// create a ni_rational_t
220NI_UNUSED static ni_rational_t ni_make_rational(int num, int den)
221{
222 ni_rational_t r = {num, den};
223 return r;
224}
225
226/*!*****************************************************************************
227 * \brief Retrieve auxiliary data (close caption, various SEI) associated with
228 * this frame that is returned by decoder, convert them to appropriate
229 * format and save them in the frame's auxiliary data storage for
230 * future use by encoding. Usually they would be sent together with
231 * this frame to encoder at encoding.
232 *
233 * \param[in/out] frame that is returned by decoder
234 *
235 * \return NONE
236 ******************************************************************************/
238{
239 uint8_t *sei_buf = NULL;
240 ni_aux_data_t *aux_data = NULL;
241 int start_offset = 0;
242 if (frame->data_len[3] != 0)
243 {
244 //HW frame
245 start_offset = 3;
246 }
247 // User Data Unregistered SEI if available
249 {
250 sei_buf = (uint8_t *)frame->p_data[start_offset] +
253 frame, NI_FRAME_AUX_DATA_UDU_SEI, sei_buf,
254 (int)frame->sei_user_data_unreg_len))
255 {
256 ni_log(NI_LOG_ERROR, "ni_dec_retrieve_aux_data error retrieve User data "
257 "unregisted SEI!\n");
258 }
259 }
260
261 // close caption data if available
262 if (frame->sei_cc_len && frame->sei_cc_offset)
263 {
264 sei_buf = (uint8_t *)frame->p_data[start_offset] + frame->sei_cc_offset;
266 frame, NI_FRAME_AUX_DATA_A53_CC, sei_buf,
267 (int)frame->sei_cc_len))
268 {
269 ni_log(NI_LOG_ERROR, "ni_dec_retrieve_aux_data error retrieve close "
270 "caption SEI!\n");
271 }
272 }
273
274 // hdr10 sei data if available
275
276 // mastering display metadata
279 {
280 aux_data = ni_frame_new_aux_data(
283
284 if (!aux_data)
285 {
286 ni_log(NI_LOG_ERROR, "ni_dec_retrieve_aux_data error retrieve HDR10 "
287 "mastering display color SEI!\n");
288 } else
289 {
292 const int chroma_den = MASTERING_DISP_CHROMA_DEN;
293 const int luma_den = MASTERING_DISP_LUMA_DEN;
296 *)((uint8_t *)frame->p_data[start_offset] +
298
299 // HEVC uses a g,b,r ordering, which we convert to a more natural r,
300 // g,b,this is so we are compatible with FFmpeg default soft decoder
301 mdm->display_primaries[0][0].num =
302 ntohs(pColourVolume->display_primaries[2][0]);
303 mdm->display_primaries[0][0].den = chroma_den;
304 mdm->display_primaries[0][1].num =
305 ntohs(pColourVolume->display_primaries[2][1]);
306 mdm->display_primaries[0][1].den = chroma_den;
307 mdm->display_primaries[1][0].num =
308 ntohs(pColourVolume->display_primaries[0][0]);
309 mdm->display_primaries[1][0].den = chroma_den;
310 mdm->display_primaries[1][1].num =
311 ntohs(pColourVolume->display_primaries[0][1]);
312 mdm->display_primaries[1][1].den = chroma_den;
313 mdm->display_primaries[2][0].num =
314 ntohs(pColourVolume->display_primaries[1][0]);
315 mdm->display_primaries[2][0].den = chroma_den;
316 mdm->display_primaries[2][1].num =
317 ntohs(pColourVolume->display_primaries[1][1]);
318 mdm->display_primaries[2][1].den = chroma_den;
319 mdm->white_point[0].num = ntohs(pColourVolume->white_point_x);
320 mdm->white_point[0].den = chroma_den;
321 mdm->white_point[1].num = ntohs(pColourVolume->white_point_y);
322 mdm->white_point[1].den = chroma_den;
323
324 mdm->min_luminance.num =
325 ntohl(pColourVolume->min_display_mastering_luminance);
326 mdm->min_luminance.den = luma_den;
327 mdm->max_luminance.num =
328 ntohl(pColourVolume->max_display_mastering_luminance);
329 mdm->max_luminance.den = luma_den;
330
331 mdm->has_luminance = mdm->has_primaries = 1;
332 }
333 }
334
335 // hdr10 content light level
338 {
339 aux_data =
342
343 if (!aux_data)
344 {
345 ni_log(NI_LOG_ERROR, "ni_dec_retrieve_aux_data error retrieve HDR10 "
346 "content light level SEI !\n");
347 } else
348 {
350 (ni_content_light_level_t *)aux_data->data;
353 *)((uint8_t *)frame->p_data[start_offset] +
355
356 clm->max_cll = ntohs(pLightLevel->max_content_light_level);
357 clm->max_fall = ntohs(pLightLevel->max_pic_average_light_level);
358 }
359 }
360
361 // hdr10+ sei data if available
362 if (frame->sei_hdr_plus_len && frame->sei_hdr_plus_offset)
363 {
365 sizeof(ni_dynamic_hdr_plus_t));
366
367 if (!aux_data)
368 {
369 ni_log(NI_LOG_ERROR, "ni_dec_retrieve_aux_data error retrieve HDR10+ SEI "
370 "!\n");
371 } else
372 {
373 int w, i, j, i_limit, j_limit;
375 (ni_dynamic_hdr_plus_t *)aux_data->data;
377
378 sei_buf = (uint8_t *)frame->p_data[start_offset] +
379 frame->sei_hdr_plus_offset;
380 ni_bitstream_reader_init(&br, sei_buf,
381 8 * (int)frame->sei_hdr_plus_len);
382 hdrp->itu_t_t35_country_code = 0xB5;
383 // first 6 bytes of t35 SEI data header already matched HDR10+, and:
384 ni_bs_reader_skip_bits(&br, 6 * 8);
385 // application_version u(8)
387 ni_log(NI_LOG_DEBUG, "hdr10+ application_version %u\n", hdrp->application_version);
388
389
390 // Num_windows u(2)
391 hdrp->num_windows = ni_bs_reader_get_bits(&br, 2);
392 ni_log(NI_LOG_DEBUG, "hdr10+ num_windows %u\n", hdrp->num_windows);
393 if (!(1 == hdrp->num_windows || 2 == hdrp->num_windows ||
394 3 == hdrp->num_windows))
395 {
396 // wrong format and skip this HDR10+ SEI
397 } else
398 {
399 // the following block will be skipped for hdrp->num_windows ==
400 // 1
401 for (w = 1; w < hdrp->num_windows; w++)
402 {
404 ni_make_q(ni_bs_reader_get_bits(&br, 16), 1);
406 ni_make_q(ni_bs_reader_get_bits(&br, 16), 1);
408 ni_make_q(ni_bs_reader_get_bits(&br, 16), 1);
410 ni_make_q(ni_bs_reader_get_bits(&br, 16), 1);
411 hdrp->params[w - 1].center_of_ellipse_x =
412 ni_bs_reader_get_bits(&br, 16);
413 hdrp->params[w - 1].center_of_ellipse_y =
414 ni_bs_reader_get_bits(&br, 16);
415 hdrp->params[w - 1].rotation_angle =
416 ni_bs_reader_get_bits(&br, 8);
418 ni_bs_reader_get_bits(&br, 16);
420 ni_bs_reader_get_bits(&br, 16);
422 ni_bs_reader_get_bits(&br, 16);
423 hdrp->params[w - 1].overlap_process_option =
425 ni_bs_reader_get_bits(&br, 1);
426 }
427
428 // values are scaled down according to standard spec
430 ni_bs_reader_get_bits(&br, 27);
432
434 ni_bs_reader_get_bits(&br, 1);
435
437 "hdr10+ targeted_system_display_maximum_luminance "
438 "%d\n",
441 "hdr10+ targeted_system_display_actual_peak_lumi"
442 "nance_flag %u\n",
444
446 {
447 i_limit =
449 ni_bs_reader_get_bits(&br, 5);
450
451 j_limit =
453 ni_bs_reader_get_bits(&br, 5);
454
456 "hdr10+ num_rows_targeted_system_display_actual"
457 "_peak_luminance x "
458 "num_cols_targeted_system_display_actual_"
459 "peak_luminance %d x %d\n",
460 i_limit, j_limit);
461
462 i_limit = i_limit > 25 ? 25 : i_limit;
463 j_limit = j_limit > 25 ? 25 : j_limit;
464 for (i = 0; i < i_limit; i++)
465 for (j = 0; j < j_limit; j++)
466 {
468 [i][j]
469 .num = ni_bs_reader_get_bits(&br, 4);
471 [i][j]
472 .den = 15;
474 "hdr10+ targeted_system_display_actual_peak"
475 "_luminance[%d][%d] %d\n",
476 i, j,
478 [i][j]
479 .num);
480 }
481 }
482
483 for (w = 0; w < hdrp->num_windows; w++)
484 {
485 for (i = 0; i < 3; i++)
486 {
487 hdrp->params[w].maxscl[i].num =
488 ni_bs_reader_get_bits(&br, 17);
489 hdrp->params[w].maxscl[i].den = 100000;
490 ni_log(NI_LOG_DEBUG, "hdr10+ maxscl[%d][%d] %d\n", w, i,
491 hdrp->params[w].maxscl[i].num);
492 }
493 hdrp->params[w].average_maxrgb.num =
494 ni_bs_reader_get_bits(&br, 17);
495 hdrp->params[w].average_maxrgb.den = 100000;
496 ni_log(NI_LOG_DEBUG, "hdr10+ average_maxrgb[%d] %d\n", w,
497 hdrp->params[w].average_maxrgb.num);
498
499 i_limit =
501 ni_bs_reader_get_bits(&br, 4);
503 "hdr10+ num_distribution_maxrgb_percentiles[%d] %d\n",
505
506 i_limit = i_limit > 15 ? 15 : i_limit;
507 for (i = 0; i < i_limit; i++)
508 {
510 ni_bs_reader_get_bits(&br, 7);
512 ni_bs_reader_get_bits(&br, 17);
514 100000;
516 "hdr10+ distribution_maxrgb_percentage[%d][%d] "
517 "%u\n",
518 w, i,
521 "hdr10+ distribution_maxrgb_percentile[%d][%d] "
522 "%d\n",
523 w, i,
524 hdrp->params[w]
526 .percentile.num);
527 }
528
530 ni_bs_reader_get_bits(&br, 10);
531 hdrp->params[w].fraction_bright_pixels.den = 1000;
532 ni_log(NI_LOG_DEBUG, "hdr10+ fraction_bright_pixels[%d] %d\n", w,
534 }
535
537 ni_bs_reader_get_bits(&br, 1);
539 "hdr10+ mastering_display_actual_peak_luminance_flag %u\n",
542 {
543 i_limit =
545 ni_bs_reader_get_bits(&br, 5);
546 j_limit =
548 ni_bs_reader_get_bits(&br, 5);
550 "hdr10+ num_rows_mastering_display_actual_peak_"
551 "luminance x "
552 "num_cols_mastering_display_actual_peak_luminance "
553 "%d x %d\n",
554 i_limit, j_limit);
555
556 i_limit = i_limit > 25 ? 25 : i_limit;
557 j_limit = j_limit > 25 ? 25 : j_limit;
558 for (i = 0; i < i_limit; i++)
559 for (j = 0; j < j_limit; j++)
560 {
562 .num = ni_bs_reader_get_bits(&br, 4);
564 .den = 15;
566 "hdr10+ mastering_display_actual_peak_lumi"
567 "nance[%d][%d] %d\n",
568 i, j,
569 hdrp
570 ->mastering_display_actual_peak_luminance[i]
571 [j]
572 .num);
573 }
574 }
575
576 for (w = 0; w < hdrp->num_windows; w++)
577 {
578 hdrp->params[w].tone_mapping_flag =
579 ni_bs_reader_get_bits(&br, 1);
580 ni_log(NI_LOG_DEBUG, "hdr10+ tone_mapping_flag[%d] %u\n", w,
581 hdrp->params[w].tone_mapping_flag);
582
583 if (hdrp->params[w].tone_mapping_flag)
584 {
585 hdrp->params[w].knee_point_x.num =
586 ni_bs_reader_get_bits(&br, 12);
587 hdrp->params[w].knee_point_x.den = 4095;
588 hdrp->params[w].knee_point_y.num =
589 ni_bs_reader_get_bits(&br, 12);
590 hdrp->params[w].knee_point_y.den = 4095;
591 ni_log(NI_LOG_DEBUG, "hdr10+ knee_point_x[%d] %d\n", w,
592 hdrp->params[w].knee_point_x.num);
593 ni_log(NI_LOG_DEBUG, "hdr10+ knee_point_y[%d] %d\n", w,
594 hdrp->params[w].knee_point_y.num);
595
597 ni_bs_reader_get_bits(&br, 4);
599 "hdr10+ num_bezier_curve_anchors[%d] %u\n", w,
601 for (i = 0;
602 i < hdrp->params[w].num_bezier_curve_anchors; i++)
603 {
604 hdrp->params[w].bezier_curve_anchors[i].num =
605 ni_bs_reader_get_bits(&br, 10);
606 hdrp->params[w].bezier_curve_anchors[i].den = 1023;
608 "hdr10+ bezier_curve_anchors[%d][%d] %d\n", w,
609 i, hdrp->params[w].bezier_curve_anchors[i].num);
610 }
611 }
612
614 ni_bs_reader_get_bits(&br, 1);
616 "hdr10+ color_saturation_mapping_flag[%d] %u\n", w,
619 {
621 ni_bs_reader_get_bits(&br, 6);
624 "hdr10+ color_saturation_weight[%d] %d\n", w,
626 }
627 } // num_windows
628
629 } // right number of windows
630 } // alloc memory
631 } // HDR10+ SEI
632
633 // init source stream info to default values (unspecified)
637 frame->video_full_range_flag = 0;
638 frame->aspect_ratio_idc = 0;
639 frame->sar_width = 0;
640 frame->sar_height = 0;
641 frame->vui_num_units_in_tick = 0;
642 frame->vui_time_scale = 0;
643
644 // VUI if retrieved
645 if (frame->vui_offset || frame->vui_len)
646 {
647 sei_buf = (uint8_t *)frame->p_data[start_offset] + frame->vui_offset;
648 ni_extended_dec_metadata_t *p_dec_ext_meta =
650 frame->vui_num_units_in_tick = p_dec_ext_meta->num_units_in_tick;
651 frame->vui_time_scale = p_dec_ext_meta->time_scale;
652 frame->color_primaries = p_dec_ext_meta->color_primaries;
653 frame->color_trc = p_dec_ext_meta->color_trc;
654 frame->color_space = p_dec_ext_meta->color_space;
655 frame->video_full_range_flag = p_dec_ext_meta->video_full_range_flag;
656
658 "ni_dec_retrieve_aux_data VUI "
659 "aspect_ratio_idc %u "
660 "sar_width %u sar_height %u "
661 "video_full_range_flag %d "
662 "color-pri %u color-trc %u color-space %u "
663 "vui_num_units_in_tick %u "
664 "vui_time_scale %u\n",
665 frame->aspect_ratio_idc, frame->sar_width, frame->sar_height,
667 frame->color_trc, frame->color_space,
669 }
670
671 // alternative transfer characteristics SEI if available
674 {
675 sei_buf = (uint8_t *)frame->p_data[start_offset] +
677
678 // and overwrite the color-trc in the VUI
679 ni_log(NI_LOG_DEBUG, "ni_dec_retrieve_aux_data alt trc SEI value %u over-"
680 "writting VUI color-trc value %u\n",
681 *sei_buf, frame->color_trc);
682 frame->color_trc = *sei_buf;
683 }
684}
685
686// Convert struct of ROIs to NetInt ROI map and store them inside the encoder
687// context passed in.
688// return 0 if successful, -1 otherwise
689static int set_roi_map(ni_session_context_t *p_enc_ctx,
690 ni_codec_format_t codec_format,
691 const ni_aux_data_t *aux_data, int nb_roi, int width,
692 int height, int intra_qp)
693{
694 int r;
695 uint32_t i, j, k, m;
696 const ni_region_of_interest_t *roi =
697 (const ni_region_of_interest_t *)aux_data->data;
698 uint32_t self_size = roi->self_size;
699 int32_t set_qp = 0;
700 uint32_t sumQp = 0;
701 uint8_t isAbsQp_flag = 0; // 0 for delta qp, 1 for absolute qp
702 ni_xcoder_params_t *api_params =
703 (ni_xcoder_params_t *)p_enc_ctx->p_session_config;
704
705 uint32_t max_cu_size = (codec_format == NI_CODEC_FORMAT_H264) ? 16 : 64;
706
707 // AV1 non-8x8-aligned resolution is implicitly cropped due to Quadra HW limitation
708 if (NI_CODEC_FORMAT_AV1 == codec_format)
709 {
710 width = (width / 8) * 8;
711 height = (height / 8) * 8;
712 }
713
714 // for H.264, select ROI Map Block Unit Size: 16x16
715 // for H.265, select ROI Map Block Unit Size: 64x64
716 uint32_t roiMapBlockUnitSize =
717 (codec_format == NI_CODEC_FORMAT_H264) ? 16 : 64;
718 uint32_t mbWidth = ((width + max_cu_size - 1) & (~(max_cu_size - 1))) /
719 roiMapBlockUnitSize;
720 uint32_t mbHeight = ((height + max_cu_size - 1) & (~(max_cu_size - 1))) /
721 roiMapBlockUnitSize;
722 uint32_t numMbs = mbWidth * mbHeight;
723 uint32_t subMbWidth = roiMapBlockUnitSize / 8;
724 uint32_t subMbHeight = subMbWidth;
725 uint32_t subNumMbs = subMbWidth * subMbHeight;
726
727 // (ROI map version >= 1) each QP info takes 8-bit, represent 8x8 pixel
728 // block
729 uint32_t block_size = ((width + max_cu_size - 1) & (~(max_cu_size - 1))) *
730 ((height + max_cu_size - 1) & (~(max_cu_size - 1))) / (8 * 8);
731
732 // need to align to 64 bytes
733 uint32_t customMapSize = ((block_size + 63) & (~63));
734 if (!p_enc_ctx->roi_map)
735 {
736 p_enc_ctx->roi_map =
737 (ni_enc_quad_roi_custom_map *)calloc(1, customMapSize);
738 if (!p_enc_ctx->roi_map)
739 {
740 return -1;
741 }
742 }
743
744 // init ipcm_flag to 0, roiAbsQp_falg to 0 (qp delta), and qp_info to 0
745 memset(p_enc_ctx->roi_map, 0, customMapSize);
746
747 // iterate ROI list from the last as regions are defined in order of
748 // decreasing importance.
749 for (r = nb_roi - 1; r >= 0; r--)
750 {
751 roi = (const ni_region_of_interest_t *)((uint8_t *)aux_data->data + self_size * r);
752 if (!roi->qoffset.den)
753 {
754 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_region_of_interest_t.qoffset.den must not be "
755 "zero.\n");
756 continue;
757 }
759 // set_qp in range [1, 10] mean it need to reset qp after
760 // rate control in fw when customize_roi_qp_level is 1.
761 // set_qp is the level in customize qp map, it choose dst qp
762 // in customize qp map base on the rate control qp and set_qp
763 set_qp = (int32_t)((float)roi->qoffset.num * 1.0f /
764 (float)roi->qoffset.den * NI_CUSTOMIZE_ROI_QPOFFSET_LEVEL);
765 if (set_qp > 0 && set_qp <= NI_CUSTOMIZE_ROI_QPOFFSET_LEVEL) {
766 isAbsQp_flag = api_params->cfg_enc_params.customize_roi_qp_level;
767 } else {
768 continue;
769 }
770 } else {
771 set_qp = (int32_t)((float)roi->qoffset.num * 1.0f /
772 (float)roi->qoffset.den * NI_INTRA_QP_RANGE);
773 set_qp = clip3(NI_MIN_QP_DELTA, NI_MAX_QP_DELTA, set_qp);
774 // Adjust qp delta range (-25 to 25) to (0 to 63): 0 to 0, -1 to 1, -2 to
775 // 2 ... 1 to 63, 2 to 62 ...
776 // Theoretically the possible qp delta range is (-32 to 31)
777 set_qp = (NI_MAX_QP_INFO + 1 - set_qp) % (NI_MAX_QP_INFO + 1);
778 }
779 ni_log2(p_enc_ctx, NI_LOG_DEBUG,
780 "set_roi_map: left %d right %d top %d bottom %d num %d den"
781 " %d set_qp %d\n",
782 roi->left, roi->right, roi->top, roi->bottom, roi->qoffset.num,
783 roi->qoffset.den, set_qp);
784
785 // copy ROI MBs QPs into custom map
786 for (j = 0; j < mbHeight; j++)
787 {
788 for (i = 0; i < mbWidth; i++)
789 {
790 k = j * (int)mbWidth + i;
791
792 for (m = 0; m < subNumMbs; m++)
793 {
794 if (((int)(i % mbWidth) >=
795 (int)((roi->left + roiMapBlockUnitSize - 1) /
796 roiMapBlockUnitSize) -
797 1) &&
798 ((int)(i % mbWidth) <=
799 (int)((roi->right + roiMapBlockUnitSize - 1) /
800 roiMapBlockUnitSize) -
801 1) &&
802 ((int)(j % mbHeight) >=
803 (int)((roi->top + roiMapBlockUnitSize - 1) /
804 roiMapBlockUnitSize) -
805 1) &&
806 ((int)(j % mbHeight) <=
807 (int)((roi->bottom + roiMapBlockUnitSize - 1) /
808 roiMapBlockUnitSize) -
809 1))
810 {
811 p_enc_ctx->roi_map[k * subNumMbs + m].field.ipcm_flag =
812 0; // don't force skip mode
813 p_enc_ctx->roi_map[k * subNumMbs + m]
814 .field.roiAbsQp_flag = isAbsQp_flag;
815 p_enc_ctx->roi_map[k * subNumMbs + m].field.qp_info =
816 set_qp;
817 // ni_log2(p_enc_ctx, NI_LOG_DEBUG, "## x %d y %d index %d\n", i,
818 // j, k*subNumMbs+m);
819 }
820 }
821 sumQp += p_enc_ctx->roi_map[k * subNumMbs].field.qp_info;
822 }
823 }
824 }
825
826 p_enc_ctx->roi_len = customMapSize;
827 p_enc_ctx->roi_avg_qp = (numMbs != 0 ? (sumQp + (numMbs >> 1)) / numMbs : 0) + NI_DEFAULT_INTRA_QP;
828
829 return 0;
830}
831
832/*!*****************************************************************************
833 * \brief Prepare auxiliary data that should be sent together with this frame
834 * to encoder based on the auxiliary data of the decoded frame.
835 *
836 * Note: Some of the SEI (e.g. HDR) will be updated and stored in encoder
837 * context whenever received through decoded frame; they will be sent
838 * out with the encoded frame to encoder only when appropriate, i.e.
839 * should_send_sei_with_frame is true. When a type of aux data is to be
840 * sent, its associated length will be set in the encoder frame.
841 *
842 * \param[in/out] p_enc_ctx encoder session contextwhose various SEI type
843 * header can be updated as the result of this function
844 * \param[out] p_enc_frame frame to be sent to encoder
845 * \param[in] p_dec_frame frame that is returned by decoder
846 * \param[in] codec_format H.264 or H.265
847 * \param[in] should_send_sei_with_frame if need to send a certain type of
848 * SEI with this frame
849 * \param[out] mdcv_data SEI for HDR mastering display color volume info
850 * \param[out] cll_data SEI for HDR content light level info
851 * \param[out] cc_data SEI for close caption
852 * \param[out] udu_data SEI for User data unregistered
853 * \param[out] hdrp_data SEI for HDR10+
854 *
855 * \return NONE
856 ******************************************************************************/
858 ni_frame_t *p_enc_frame, ni_frame_t *p_dec_frame,
859 ni_codec_format_t codec_format,
860 int should_send_sei_with_frame, uint8_t *mdcv_data,
861 uint8_t *cll_data, uint8_t *cc_data,
862 uint8_t *udu_data, uint8_t *hdrp_data)
863{
864 uint8_t *dst = NULL;
865 ni_aux_data_t *aux_data = NULL;
866 ni_xcoder_params_t *api_params =
868
869 // reset all auxiliary data flag and length of encode frame
871 p_enc_frame->use_cur_src_as_long_term_pic =
872 p_enc_frame->use_long_term_ref = 0;
873
874 p_enc_frame->sei_total_len = p_enc_frame->sei_cc_offset =
875 p_enc_frame->sei_cc_len =
880 p_enc_frame->sei_user_data_unreg_offset =
881 p_enc_frame->sei_user_data_unreg_len =
882 p_enc_frame->sei_hdr_plus_offset =
883 p_enc_frame->sei_hdr_plus_len = 0;
884
885 // prep for NetInt intra period reconfiguration support: when intra period
886 // setting has been requested by both frame and API, API takes priority
887 int intraprd = -1;
888 aux_data = ni_frame_get_aux_data(p_dec_frame, NI_FRAME_AUX_DATA_INTRAPRD);
889 if (aux_data)
890 {
891 intraprd = *((int32_t *)aux_data->data);
892 if (intraprd < 0 || intraprd > 1024)
893 {
894 ni_log(NI_LOG_ERROR, "ERROR: %s(): invalid intraperiod in aux data %d\n",
895 __func__, intraprd);
896 intraprd = -1;
897 }
898 }
899
900 if (p_enc_ctx->reconfig_intra_period >= 0)
901 {
902 intraprd = p_enc_ctx->reconfig_intra_period;
903 p_enc_ctx->reconfig_intra_period = -1;
904 ni_log(NI_LOG_DEBUG, "%s(): API set intraPeriod %d\n", __func__,
905 intraprd);
906 }
907
908 if (intraprd >= 0)
909 {
910 if (api_params->cfg_enc_params.intra_mb_refresh_mode ||
911 api_params->cfg_enc_params.gop_preset_index == 1)
912 {
913 ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s(): NOT allowed to reconfig intraPeriod %d in intra_mb_refresh_mode %d or gop_preset_index %d\n",
914 __func__,
915 intraprd,
917 api_params->cfg_enc_params.gop_preset_index);
918 }
919 else
920 {
921 // FW forces IDR frame when reconfig intra period, so the following steps are required for repeating SEI (and required for ni_should_send_sei_with_frame)
922 should_send_sei_with_frame = 1;
923 api_params->cfg_enc_params.intra_period = intraprd;
924
925 if (intraprd)
926 {
927 p_enc_ctx->force_idr_intra_offset =
928 intraprd - (p_enc_ctx->frame_num % intraprd);
929 }
930 else
931 {
932 p_enc_ctx->force_idr_intra_offset = 0;
933 }
934
935 p_enc_ctx->enc_change_params->enable_option |=
937 p_enc_ctx->enc_change_params->intraPeriod = intraprd;
938 ni_log(NI_LOG_INFO, "%s(): set intraPeriod %d on frame %u, update intra offset %u\n", __func__,
939 intraprd, p_enc_ctx->frame_num, p_enc_ctx->force_idr_intra_offset);
940 p_enc_frame->reconf_len = sizeof(ni_encoder_change_params_t);
941 }
942 }
943
944 // prep SEI for HDR (mastering display color volume)
945 aux_data = ni_frame_get_aux_data(
947 if (aux_data)
948 {
949 p_enc_ctx->mdcv_max_min_lum_data_len = 8;
951 8 + 6 * 2 + 2 * 2 + 2 * 4 + 1;
952 if (NI_CODEC_FORMAT_H264 == codec_format)
953 {
955 }
956
959
960 // save a copy
961 if (!p_enc_ctx->p_master_display_meta_data)
962 {
964 }
965 if (!p_enc_ctx->p_master_display_meta_data)
966 {
967 ni_log2(p_enc_ctx, NI_LOG_ERROR, "Error mem alloc for mastering display color vol\n");
968 } else
969 {
970 memcpy(p_enc_ctx->p_master_display_meta_data, p_src,
972
973 const int luma_den = MASTERING_DISP_LUMA_DEN;
974
975 uint32_t uint32_t_tmp = htonl(
976 (uint32_t)(lrint(luma_den * ni_q2d(p_src->max_luminance))));
977 memcpy(p_enc_ctx->ui8_mdcv_max_min_lum_data, &uint32_t_tmp,
978 sizeof(uint32_t));
979 uint32_t_tmp = htonl(
980 (uint32_t)(lrint(luma_den * ni_q2d(p_src->min_luminance))));
981 memcpy(p_enc_ctx->ui8_mdcv_max_min_lum_data + 4, &uint32_t_tmp,
982 sizeof(uint32_t));
983
984 // emulation prevention checking of luminance data
985 int emu_bytes_inserted = ni_insert_emulation_prevent_bytes(
986 p_enc_ctx->ui8_mdcv_max_min_lum_data, 2 * 4);
987
988 p_enc_ctx->mdcv_max_min_lum_data_len += emu_bytes_inserted;
990 emu_bytes_inserted;
991 }
992 }
993
995 p_enc_ctx->p_master_display_meta_data && should_send_sei_with_frame)
996 {
997 dst = mdcv_data;
998 dst[0] = dst[1] = dst[2] = 0;
999 dst[3] = 1;
1000
1001 if (NI_CODEC_FORMAT_H264 == codec_format)
1002 {
1003 dst[4] = 0x6;
1004 dst[5] = 0x89; // payload type=137
1005 dst[6] = 0x18; // payload size=24
1006 dst += 7;
1007 } else
1008 {
1009 dst[4] = 0x4e;
1010 dst[5] = 1;
1011 dst[6] = 0x89; // payload type=137
1012 dst[7] = 0x18; // payload size=24
1013 dst += 8;
1014 }
1015
1020 p_enc_ctx->p_master_display_meta_data;
1021
1022 const int chroma_den = MASTERING_DISP_CHROMA_DEN;
1023 const int luma_den = MASTERING_DISP_LUMA_DEN;
1024
1025 uint16_t dp00 = 0, dp01 = 0, dp10 = 0, dp11 = 0, dp20 = 0, dp21 = 0,
1026 wpx = 0, wpy = 0;
1027 // assuming p_src->has_primaries is always true
1028 // this is stored in r,g,b order and needs to be in g.b,r order
1029 // when sent to encoder
1030 dp00 = (uint16_t)lrint(chroma_den *
1031 ni_q2d(p_src->display_primaries[1][0]));
1032 p_mdcv->display_primaries[0][0] = htons(dp00);
1033 dp01 = (uint16_t)lrint(chroma_den *
1034 ni_q2d(p_src->display_primaries[1][1]));
1035 p_mdcv->display_primaries[0][1] = htons(dp01);
1036 dp10 = (uint16_t)lrint(chroma_den *
1037 ni_q2d(p_src->display_primaries[2][0]));
1038 p_mdcv->display_primaries[1][0] = htons(dp10);
1039 dp11 = (uint16_t)lrint(chroma_den *
1040 ni_q2d(p_src->display_primaries[2][1]));
1041 p_mdcv->display_primaries[1][1] = htons(dp11);
1042 dp20 = (uint16_t)lrint(chroma_den *
1043 ni_q2d(p_src->display_primaries[0][0]));
1044 p_mdcv->display_primaries[2][0] = htons(dp20);
1045 dp21 = (uint16_t)lrint(chroma_den *
1046 ni_q2d(p_src->display_primaries[0][1]));
1047 p_mdcv->display_primaries[2][1] = htons(dp21);
1048
1049 wpx = (uint16_t)lrint(chroma_den * ni_q2d(p_src->white_point[0]));
1050 p_mdcv->white_point_x = htons(wpx);
1051 wpy = (uint16_t)lrint(chroma_den * ni_q2d(p_src->white_point[1]));
1052 p_mdcv->white_point_y = htons(wpy);
1053
1054 ni_log2(p_enc_ctx, NI_LOG_DEBUG,
1055 "mastering display color volume, primaries "
1056 "%u/%u/%u/%u/%u/%u white_point_x/y %u/%u max/min_lumi %u/%u\n",
1057 (uint16_t)dp00, (uint16_t)dp01, (uint16_t)dp10, (uint16_t)dp11,
1058 (uint16_t)dp20, (uint16_t)dp21, (uint16_t)wpx, (uint16_t)wpy,
1059 (uint32_t)(luma_den * ni_q2d(p_src->max_luminance)),
1060 (uint32_t)(luma_den * ni_q2d(p_src->min_luminance)));
1061
1062 dst += 6 * 2 + 2 * 2;
1063 memcpy(dst, p_enc_ctx->ui8_mdcv_max_min_lum_data,
1064 p_enc_ctx->mdcv_max_min_lum_data_len);
1065
1066 dst += p_enc_ctx->mdcv_max_min_lum_data_len;
1067 *dst = 0x80;
1068
1071
1072 p_enc_frame->sei_total_len +=
1074 }
1075
1076 // prep SEI for HDR (content light level info)
1077 aux_data = ni_frame_get_aux_data(p_dec_frame,
1079 if (aux_data)
1080 {
1081 // size of: start code + NAL unit header + payload type byte +
1082 // payload size byte + payload + rbsp trailing bits, default HEVC
1083 p_enc_ctx->light_level_data_len = 4;
1084 p_enc_ctx->sei_hdr_content_light_level_info_len = 8 + 2 * 2 + 1;
1085 if (NI_CODEC_FORMAT_H264 == codec_format)
1086 {
1088 }
1089
1090 uint16_t max_content_light_level =
1091 htons(((ni_content_light_level_t *)aux_data->data)->max_cll);
1092 uint16_t max_pic_average_light_level =
1093 htons(((ni_content_light_level_t *)aux_data->data)->max_fall);
1094
1095 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "content light level info, MaxCLL %u MaxFALL %u\n",
1096 ((ni_content_light_level_t *)aux_data->data)->max_cll,
1097 ((ni_content_light_level_t *)aux_data->data)->max_fall);
1098
1099 memcpy(p_enc_ctx->ui8_light_level_data, &max_content_light_level,
1100 sizeof(uint16_t));
1101 memcpy(&(p_enc_ctx->ui8_light_level_data[2]),
1102 &max_pic_average_light_level, sizeof(uint16_t));
1103
1104 // emulation prevention checking
1105 int emu_bytes_inserted = ni_insert_emulation_prevent_bytes(
1106 p_enc_ctx->ui8_light_level_data, p_enc_ctx->light_level_data_len);
1107
1108 p_enc_ctx->light_level_data_len += emu_bytes_inserted;
1109 p_enc_ctx->sei_hdr_content_light_level_info_len += emu_bytes_inserted;
1110 }
1111
1112 if (p_enc_ctx->sei_hdr_content_light_level_info_len &&
1113 should_send_sei_with_frame)
1114 {
1115 dst = cll_data;
1116 dst[0] = dst[1] = dst[2] = 0;
1117 dst[3] = 1;
1118
1119 if (NI_CODEC_FORMAT_H264 == codec_format)
1120 {
1121 dst[4] = 0x6;
1122 dst[5] = 0x90; // payload type=144
1123 dst[6] = 4; // payload size=4
1124 dst += 7;
1125 } else
1126 {
1127 dst[4] = 0x4e;
1128 dst[5] = 1;
1129 dst[6] = 0x90; // payload type=144
1130 dst[7] = 4; // payload size=4
1131 dst += 8;
1132 }
1133
1134 memcpy(dst, p_enc_ctx->ui8_light_level_data,
1135 p_enc_ctx->light_level_data_len);
1136 dst += p_enc_ctx->light_level_data_len;
1137 *dst = 0x80;
1138
1141
1142 p_enc_frame->sei_total_len +=
1144 }
1145
1146 // prep SEI for close caption
1147 aux_data = ni_frame_get_aux_data(p_dec_frame, NI_FRAME_AUX_DATA_A53_CC);
1148 if (aux_data)
1149 {
1150 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_prep_aux_data sei_cc_len %d\n", aux_data->size);
1151
1152 uint8_t cc_data_emu_prevent[NI_MAX_SEI_DATA];
1153 int cc_size = aux_data->size;
1154 if (cc_size > NI_MAX_SEI_DATA)
1155 {
1156 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_prep_aux_data sei_cc_len %d > MAX %d !\n",
1157 aux_data->size, (int)NI_MAX_SEI_DATA);
1158 cc_size = NI_MAX_SEI_DATA;
1159 }
1160 memcpy(cc_data_emu_prevent, aux_data->data, cc_size);
1161 int cc_size_emu_prevent = cc_size +
1162 ni_insert_emulation_prevent_bytes(cc_data_emu_prevent, cc_size);
1163 if (cc_size_emu_prevent != cc_size)
1164 {
1165 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_prep_aux_data: close caption "
1166 "emulation prevention bytes added: %d\n",
1167 cc_size_emu_prevent - cc_size);
1168 }
1169
1170 dst = cc_data;
1171 // set header info fields and extra size based on codec
1172 if (NI_CODEC_FORMAT_H265 == codec_format)
1173 {
1174 p_enc_frame->sei_cc_len = NI_CC_SEI_HDR_HEVC_LEN +
1175 cc_size_emu_prevent + NI_CC_SEI_TRAILER_LEN;
1176 p_enc_frame->sei_total_len += p_enc_frame->sei_cc_len;
1177
1178 p_enc_ctx->itu_t_t35_cc_sei_hdr_hevc[7] = cc_size + 11;
1179 p_enc_ctx->itu_t_t35_cc_sei_hdr_hevc[16] = (cc_size / 3) | 0xc0;
1180
1181 memcpy(dst, p_enc_ctx->itu_t_t35_cc_sei_hdr_hevc,
1184 memcpy(dst, cc_data_emu_prevent, cc_size_emu_prevent);
1185 dst += cc_size_emu_prevent;
1186 memcpy(dst, p_enc_ctx->sei_trailer, NI_CC_SEI_TRAILER_LEN);
1187 } else // H.264
1188 {
1189 p_enc_frame->sei_cc_len = NI_CC_SEI_HDR_H264_LEN +
1190 cc_size_emu_prevent + NI_CC_SEI_TRAILER_LEN;
1191 p_enc_frame->sei_total_len += p_enc_frame->sei_cc_len;
1192
1193 p_enc_ctx->itu_t_t35_cc_sei_hdr_h264[6] = cc_size + 11;
1194 p_enc_ctx->itu_t_t35_cc_sei_hdr_h264[15] = (cc_size / 3) | 0xc0;
1195
1196 memcpy(dst, p_enc_ctx->itu_t_t35_cc_sei_hdr_h264,
1199 memcpy(dst, cc_data_emu_prevent, cc_size_emu_prevent);
1200 dst += cc_size_emu_prevent;
1201 memcpy(dst, p_enc_ctx->sei_trailer, NI_CC_SEI_TRAILER_LEN);
1202 }
1203 }
1204
1205 // prep SEI for HDR+
1206 aux_data = ni_frame_get_aux_data(p_dec_frame, NI_FRAME_AUX_DATA_HDR_PLUS);
1207 if (aux_data)
1208 {
1210 int w, i, j;
1212 uint32_t ui_tmp;
1213
1215
1216 // HDR10+ SEI header bytes
1217
1218 // itu_t_t35_provider_code and itu_t_t35_provider_oriented_code are
1219 // contained in the first 4 bytes of payload; pb has all the data until
1220 // start of trailer
1221 ni_bs_writer_put(&pb, 0, 8);
1222 ni_bs_writer_put(&pb, 0x3c,
1223 8); // u16 itu_t_t35_provider_code = 0x003c
1224 ni_bs_writer_put(&pb, 0, 8);
1225 // u16 itu_t_t35_provider_oriented_code = 0x0001
1226 ni_bs_writer_put(&pb, 0x01, 8);
1227 ni_bs_writer_put(&pb, 4, 8); // u8 application_identifier = 0x04
1229 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ application_version %u\n", hdrp->application_version);
1230
1231 ni_bs_writer_put(&pb, hdrp->num_windows, 2);
1232 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ num_windows %u\n", hdrp->num_windows);
1233 for (w = 1; w < hdrp->num_windows; w++)
1234 {
1236 &pb, hdrp->params[w - 1].window_upper_left_corner_x.num, 16);
1238 &pb, hdrp->params[w - 1].window_upper_left_corner_y.num, 16);
1240 &pb, hdrp->params[w - 1].window_lower_right_corner_x.num, 16);
1242 &pb, hdrp->params[w - 1].window_lower_right_corner_y.num, 16);
1243 ni_bs_writer_put(&pb, hdrp->params[w - 1].center_of_ellipse_x, 16);
1244 ni_bs_writer_put(&pb, hdrp->params[w - 1].center_of_ellipse_y, 16);
1245 ni_bs_writer_put(&pb, hdrp->params[w - 1].rotation_angle, 8);
1247 &pb, hdrp->params[w - 1].semimajor_axis_internal_ellipse, 16);
1249 &pb, hdrp->params[w - 1].semimajor_axis_external_ellipse, 16);
1251 &pb, hdrp->params[w - 1].semiminor_axis_external_ellipse, 16);
1253 1);
1254 }
1255
1256 // values are scaled up according to standard spec
1257 ui_tmp = lrint(10000 *
1259 ni_bs_writer_put(&pb, ui_tmp, 27);
1262 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ targeted_system_display_maximum_luminance "
1263 "%u\n",
1264 ui_tmp);
1265 ni_log2(p_enc_ctx, NI_LOG_DEBUG,
1266 "hdr10+ targeted_system_display_actual_peak_luminance_"
1267 "flag %u\n",
1269
1271 {
1273 &pb,
1275 5);
1277 &pb,
1279 5);
1280 ni_log2(p_enc_ctx, NI_LOG_DEBUG,
1281 "hdr10+ num_rows_targeted_system_display_actual_peak_luminance "
1282 "x num_cols_targeted_system_display_actual_peak_luminance %u x "
1283 "%u\n",
1286
1287 for (i = 0; i <
1289 i++)
1290 for (
1291 j = 0; j <
1293 j++)
1294 {
1295 ui_tmp = lrint(
1296 15 *
1297 ni_q2d(
1299 [i][j]));
1300 ni_bs_writer_put(&pb, ui_tmp, 4);
1301 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ targeted_system_display_actual_peak_"
1302 "luminance[%d][%d] %u\n",
1303 i, j, ui_tmp);
1304 }
1305 }
1306
1307 for (w = 0; w < hdrp->num_windows; w++)
1308 {
1309 for (i = 0; i < 3; i++)
1310 {
1311 ui_tmp = lrint(100000 * ni_q2d(hdrp->params[w].maxscl[i]));
1312 ni_bs_writer_put(&pb, ui_tmp, 17);
1313 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ maxscl[%d][%d] %u\n", w, i, ui_tmp);
1314 }
1315 ui_tmp = lrint(100000 * ni_q2d(hdrp->params[w].average_maxrgb));
1316 ni_bs_writer_put(&pb, ui_tmp, 17);
1317 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ average_maxrgb[%d] %u\n", w, ui_tmp);
1318
1321 ni_log2(p_enc_ctx, NI_LOG_DEBUG,
1322 "hdr10+ num_distribution_maxrgb_percentiles[%d] %d\n", w,
1324
1325 for (i = 0; i < hdrp->params[w].num_distribution_maxrgb_percentiles;
1326 i++)
1327 {
1329 &pb, hdrp->params[w].distribution_maxrgb[i].percentage, 7);
1330 ui_tmp = lrint(
1331 100000 *
1332 ni_q2d(hdrp->params[w].distribution_maxrgb[i].percentile));
1333 ni_bs_writer_put(&pb, ui_tmp, 17);
1334 ni_log2(p_enc_ctx, NI_LOG_DEBUG,
1335 "hdr10+ distribution_maxrgb_percentage[%d][%d] %u\n", w, i,
1337 ni_log2(p_enc_ctx, NI_LOG_DEBUG,
1338 "hdr10+ distribution_maxrgb_percentile[%d][%d] %u\n", w, i,
1339 ui_tmp);
1340 }
1341
1342 ui_tmp =
1343 lrint(1000 * ni_q2d(hdrp->params[w].fraction_bright_pixels));
1344 ni_bs_writer_put(&pb, ui_tmp, 10);
1345 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ fraction_bright_pixels[%d] %u\n", w, ui_tmp);
1346 }
1347
1348 ni_bs_writer_put(&pb,
1350 ni_log2(p_enc_ctx, NI_LOG_DEBUG,
1351 "hdr10+ mastering_display_actual_peak_luminance_flag %u\n",
1354 {
1359 ni_log2(p_enc_ctx, NI_LOG_DEBUG,
1360 "hdr10+ num_rows_mastering_display_actual_peak_luminance x "
1361 "num_cols_mastering_display_actual_peak_luminance %u x %u\n",
1364
1365 for (i = 0;
1367 i++)
1368 for (j = 0;
1370 j++)
1371 {
1372 ui_tmp = lrint(
1373 15 *
1374 ni_q2d(
1376 [j]));
1377 ni_bs_writer_put(&pb, ui_tmp, 4);
1378 ni_log2(p_enc_ctx, NI_LOG_DEBUG,
1379 "hdr10+ "
1380 "mastering_display_actual_peak_luminance[%d][%d] %u\n",
1381 i, j, ui_tmp);
1382 }
1383 }
1384
1385 for (w = 0; w < hdrp->num_windows; w++)
1386 {
1387 ni_bs_writer_put(&pb, hdrp->params[w].tone_mapping_flag, 1);
1388 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ tone_mapping_flag[%d] %u\n", w,
1389 hdrp->params[w].tone_mapping_flag);
1390
1391 if (hdrp->params[w].tone_mapping_flag)
1392 {
1393 ui_tmp = lrint(4095 * ni_q2d(hdrp->params[w].knee_point_x));
1394 ni_bs_writer_put(&pb, ui_tmp, 12);
1395 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ knee_point_x[%d] %u\n", w, ui_tmp);
1396
1397 ui_tmp = lrint(4095 * ni_q2d(hdrp->params[w].knee_point_y));
1398 ni_bs_writer_put(&pb, ui_tmp, 12);
1399 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ knee_point_y[%d] %u\n", w, ui_tmp);
1400
1402 4);
1403 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ num_bezier_curve_anchors[%d] %u\n", w,
1405 for (i = 0; i < hdrp->params[w].num_bezier_curve_anchors; i++)
1406 {
1407 ui_tmp = lrint(
1408 1023 * ni_q2d(hdrp->params[w].bezier_curve_anchors[i]));
1409 ni_bs_writer_put(&pb, ui_tmp, 10);
1410 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ bezier_curve_anchors[%d][%d] %u\n",
1411 w, i, ui_tmp);
1412 }
1413 }
1414
1416 1);
1417 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ color_saturation_mapping_flag[%d] %u\n", w,
1420 {
1421 ui_tmp =
1422 lrint(8 * ni_q2d(hdrp->params[w].color_saturation_weight));
1423 ni_bs_writer_put(&pb, 6, ui_tmp);
1424 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ color_saturation_weight[%d] %u\n", w,
1425 ui_tmp);
1426 }
1427 } // num_windows
1428
1429 uint64_t hdr10p_num_bytes = (ni_bs_writer_tell(&pb) + 7) / 8;
1430 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ total bits: %d -> bytes %" PRIu64 "\n",
1431 (int)ni_bs_writer_tell(&pb), hdr10p_num_bytes);
1433
1434 dst = hdrp_data;
1435
1436 // emulation prevention checking of payload
1437 int emu_bytes_inserted;
1438
1439 // set header info fields and extra size based on codec
1440 if (NI_CODEC_FORMAT_H265 == codec_format)
1441 {
1442 p_enc_ctx->itu_t_t35_hdr10p_sei_hdr_hevc[7] =
1443 (uint8_t)hdr10p_num_bytes + NI_RBSP_TRAILING_BITS_LEN;
1444
1445 memcpy(dst, p_enc_ctx->itu_t_t35_hdr10p_sei_hdr_hevc,
1448 ni_bs_writer_copy(dst, &pb);
1449
1450 emu_bytes_inserted =
1451 ni_insert_emulation_prevent_bytes(dst, (int)hdr10p_num_bytes);
1452 dst += hdr10p_num_bytes + emu_bytes_inserted;
1453 *dst = p_enc_ctx->sei_trailer[1];
1454 //dst += NI_RBSP_TRAILING_BITS_LEN;
1455
1457 (uint32_t)hdr10p_num_bytes + emu_bytes_inserted +
1459 p_enc_frame->sei_total_len += p_enc_frame->sei_hdr_plus_len;
1460 } else if (NI_CODEC_FORMAT_H264 == codec_format)
1461 {
1462 p_enc_ctx->itu_t_t35_hdr10p_sei_hdr_h264[6] =
1463 (uint8_t)hdr10p_num_bytes + NI_RBSP_TRAILING_BITS_LEN;
1464
1465 memcpy(dst, p_enc_ctx->itu_t_t35_hdr10p_sei_hdr_h264,
1468 ni_bs_writer_copy(dst, &pb);
1469
1470 emu_bytes_inserted =
1471 ni_insert_emulation_prevent_bytes(dst, (int)hdr10p_num_bytes);
1472 dst += hdr10p_num_bytes + emu_bytes_inserted;
1473 *dst = p_enc_ctx->sei_trailer[1];
1474 //dst += NI_RBSP_TRAILING_BITS_LEN;
1475
1477 (uint8_t)hdr10p_num_bytes + emu_bytes_inserted +
1479 p_enc_frame->sei_total_len += p_enc_frame->sei_hdr_plus_len;
1480 } else
1481 {
1482 ni_log2(p_enc_ctx, NI_LOG_ERROR,
1483 "ni_enc_prep_aux_data: codec %d not supported for HDR10+ "
1484 "SEI !\n",
1485 codec_format);
1486 p_enc_frame->sei_hdr_plus_len = 0;
1487 }
1488
1489 ni_bs_writer_clear(&pb);
1490 } // hdr10+
1491
1492 // prep SEI for User Data Unregistered
1493 aux_data = ni_frame_get_aux_data(p_dec_frame, NI_FRAME_AUX_DATA_UDU_SEI);
1494 if (aux_data)
1495 {
1496 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_prep_aux_data sei_user_data_unreg_len %d\n",
1497 aux_data->size);
1498
1499 // emulation prevention checking: a working buffer of size in worst case
1500 // that each two bytes comes with 1B emulation prevention byte
1501 int udu_sei_size = aux_data->size;
1502 int ext_udu_sei_size, sei_len;
1503
1504 uint8_t *sei_data = malloc(udu_sei_size * 3 / 2);
1505 if (sei_data)
1506 {
1507 memcpy(sei_data, (uint8_t *)aux_data->data, udu_sei_size);
1508 int emu_bytes_inserted =
1509 ni_insert_emulation_prevent_bytes(sei_data, udu_sei_size);
1510
1511 ext_udu_sei_size = udu_sei_size + emu_bytes_inserted;
1512
1513 if (NI_CODEC_FORMAT_H264 == codec_format)
1514 {
1515 /* 4B long start code + 1B nal header + 1B SEI type + Bytes of
1516 payload length + Bytes of SEI payload + 1B trailing */
1517 sei_len =
1518 6 + ((udu_sei_size + 0xFE) / 0xFF) + ext_udu_sei_size + 1;
1519 } else
1520 {
1521 /* 4B long start code + 2B nal header + 1B SEI type + Bytes of
1522 payload length + Bytes of SEI payload + 1B trailing */
1523 sei_len =
1524 7 + ((udu_sei_size + 0xFE) / 0xFF) + ext_udu_sei_size + 1;
1525 }
1526
1527 // discard this UDU SEI if the total SEI size exceeds the max size
1528 if (p_enc_frame->sei_total_len + sei_len > NI_ENC_MAX_SEI_BUF_SIZE)
1529 {
1530 ni_log2(p_enc_ctx, NI_LOG_ERROR,
1531 "ni_enc_prep_aux_data sei total length %u + sei_len %d "
1532 "exceeds maximum sei size %u, discarding it !\n",
1533 p_enc_frame->sei_total_len, sei_len,
1535 } else
1536 {
1537 int payload_size = udu_sei_size;
1538
1539 dst = udu_data;
1540 *dst++ = 0x00; // long start code
1541 *dst++ = 0x00;
1542 *dst++ = 0x00;
1543 *dst++ = 0x01;
1544
1545 if (NI_CODEC_FORMAT_H264 == codec_format)
1546 {
1547 *dst++ = 0x06; // nal type: SEI
1548 } else
1549 {
1550 *dst++ = 0x4e; // nal type: SEI
1551 *dst++ = 0x01;
1552 }
1553 *dst++ = 0x05; // SEI type: user data unregistered
1554
1555 // original payload size
1556 while (payload_size > 0)
1557 {
1558 *dst++ =
1559 (payload_size > 0xFF ? 0xFF : (uint8_t)payload_size);
1560 payload_size -= 0xFF;
1561 }
1562
1563 // payload data after emulation prevention checking
1564 memcpy(dst, sei_data, ext_udu_sei_size);
1565 dst += ext_udu_sei_size;
1566
1567 // trailing byte
1568 *dst = 0x80;
1569 dst++;
1570
1571 // save UDU data length
1572 p_enc_frame->sei_user_data_unreg_len = sei_len;
1573 p_enc_frame->sei_total_len += sei_len;
1574 }
1575
1576 free(sei_data);
1577 sei_data = NULL;
1578 }
1579 }
1580
1581 // supply QP map if ROI enabled and if ROIs passed in as aux data
1582 aux_data = ni_frame_get_aux_data(p_dec_frame,
1584 if (api_params->cfg_enc_params.roi_enable && aux_data)
1585 {
1586 int is_new_rois = 1;
1587 const ni_region_of_interest_t *roi = NULL;
1588 uint32_t self_size = 0;
1589
1590 roi = (const ni_region_of_interest_t *)aux_data->data;
1591 self_size = roi->self_size;
1592 if (!self_size || aux_data->size % self_size)
1593 {
1594 ni_log2(p_enc_ctx, NI_LOG_ERROR, "Invalid ni_region_of_interest_t.self_size, "
1595 "aux_data size %d self_size %u\n",
1596 aux_data->size, self_size);
1597 } else
1598 {
1599 int nb_roi = aux_data->size / (int)self_size;
1600
1601 // update ROI(s) if new/different from last one
1602 if (0 == p_enc_ctx->nb_rois || 0 == p_enc_ctx->roi_side_data_size ||
1603 !p_enc_ctx->av_rois || p_enc_ctx->nb_rois != nb_roi ||
1604 p_enc_ctx->roi_side_data_size != aux_data->size ||
1605 memcmp(p_enc_ctx->av_rois, aux_data->data, aux_data->size) != 0)
1606 {
1607 p_enc_ctx->roi_side_data_size = aux_data->size;
1608 p_enc_ctx->nb_rois = nb_roi;
1609
1610 free(p_enc_ctx->av_rois);
1611 p_enc_ctx->av_rois = malloc(aux_data->size);
1612 if (!p_enc_ctx->av_rois)
1613 {
1614 ni_log2(p_enc_ctx, NI_LOG_ERROR, "malloc ROI aux_data failed.\n");
1615 is_new_rois = 0;
1616 } else
1617 {
1618 memcpy(p_enc_ctx->av_rois, aux_data->data, aux_data->size);
1619 }
1620 } else
1621 {
1622 is_new_rois = 0;
1623 }
1624
1625 if (is_new_rois)
1626 {
1627 if (set_roi_map(p_enc_ctx, codec_format, aux_data, nb_roi,
1628 api_params->source_width,
1629 api_params->source_height,
1630 api_params->cfg_enc_params.rc.intra_qp))
1631 {
1632 ni_log2(p_enc_ctx, NI_LOG_ERROR, "set_roi_map failed\n");
1633 }
1634 }
1635 }
1636
1637 // ROI data in the frame
1638 p_enc_frame->roi_len = p_enc_ctx->roi_len;
1639 }
1640
1641 // when ROI is enabled, a QP map is always supplied with each frame, and
1642 // we use frame->roi_len value to: when 0, supply a zeroed map; when non-0,
1643 // supply the map stored in p_enc_ctx->roi_map.
1644 // - if ROI aux data is present, use it, otherwise:
1645 // - if cacheRoi, use map if exists, use 0 map otherwise
1646 // - if !cacheRoi, use 0 map
1647 // Note: the above excludes the demo modes which is handled separately in
1648 // application (e.g. nienc, xcoder)
1649 if (api_params->cfg_enc_params.roi_enable && !api_params->roi_demo_mode)
1650 {
1651 if (aux_data && p_enc_ctx->roi_map)
1652 {
1653 p_enc_frame->roi_len = p_enc_ctx->roi_len;
1654 } else
1655 {
1656 if (api_params->cacheRoi)
1657 {
1658 p_enc_frame->roi_len =
1659 (p_enc_ctx->roi_map ? p_enc_ctx->roi_len : 0);
1660 } else
1661 {
1662 p_enc_frame->roi_len = 0;
1663 }
1664 }
1665
1666 p_enc_frame->extra_data_len += p_enc_ctx->roi_len;
1667
1668 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_prep_aux_data: supply QP map, cacheRoi %d "
1669 "aux_data %d ctx->roi_map %d frame->roi_len %u ctx->roi_len %u\n",
1670 api_params->cacheRoi, aux_data != NULL,
1671 p_enc_ctx->roi_map != NULL, p_enc_frame->roi_len, p_enc_ctx->roi_len);
1672 }
1673
1674 // prep for NetInt long term reference frame support setting: when this has
1675 // been requested by both frame and API, API takes priority
1676 ni_long_term_ref_t ltr = {0};
1677 aux_data =
1679 if (aux_data)
1680 {
1681 ltr = *((ni_long_term_ref_t *)aux_data->data);
1682 ni_log2(p_enc_ctx, NI_LOG_DEBUG,
1683 "%s(): frame aux data LTR use_cur_src_as_ltr %u "
1684 "use_ltr %u\n",
1685 __func__, ltr.use_cur_src_as_long_term_pic,
1686 ltr.use_long_term_ref);
1687 }
1688
1689 if (p_enc_ctx->ltr_to_set.use_cur_src_as_long_term_pic > 0)
1690 {
1691 ltr = p_enc_ctx->ltr_to_set;
1693 p_enc_ctx->ltr_to_set.use_long_term_ref = 0;
1694
1695 ni_log2(p_enc_ctx, NI_LOG_DEBUG,
1696 "%s(): frame API set LTR use_cur_src_as_ltr %u "
1697 "use_ltr %u\n",
1698 __func__, ltr.use_cur_src_as_long_term_pic,
1699 ltr.use_long_term_ref);
1700 }
1701
1702 if (ltr.use_cur_src_as_long_term_pic > 0)
1703 {
1704 p_enc_frame->use_cur_src_as_long_term_pic =
1706 p_enc_frame->use_long_term_ref = ltr.use_long_term_ref;
1707 }
1708
1709 // prep for NetInt target max/min QP reconfiguration support: when max/min QP
1710 // setting has been requested by both frame and API, API takes priority
1711 ni_rc_min_max_qp qp_info = {0};
1712 aux_data = ni_frame_get_aux_data(p_dec_frame, NI_FRAME_AUX_DATA_MAX_MIN_QP);
1713 if (aux_data)
1714 {
1715 qp_info = *(ni_rc_min_max_qp *)aux_data->data;
1716 ni_log2(p_enc_ctx, NI_LOG_DEBUG,
1717 "%s(): frame aux data qp info max/min I qp <%d %d> maxDeltaQp <%d> max/min PB qp <%d %d>",
1718 __func__, qp_info.maxQpI, qp_info.minQpI, qp_info.maxDeltaQp, qp_info.maxQpPB, qp_info.minQpPB);
1719 }
1720 if (qp_info.maxQpI > 0)
1721 {
1722 p_enc_ctx->enc_change_params->minQpI = qp_info.minQpI;
1723 p_enc_ctx->enc_change_params->maxQpI = qp_info.maxQpI;
1724 p_enc_ctx->enc_change_params->maxDeltaQp = qp_info.maxDeltaQp;
1725 p_enc_ctx->enc_change_params->minQpPB = qp_info.minQpPB;
1726 p_enc_ctx->enc_change_params->maxQpPB = qp_info.maxQpPB;
1727 p_enc_ctx->enc_change_params->enable_option |=
1729 p_enc_frame->reconf_len = sizeof(ni_encoder_change_params_t);
1730 }
1731
1732 // prep for NetInt target bitrate reconfiguration support: when bitrate
1733 // setting has been requested by both frame and API, API takes priority
1734 int32_t bitrate = -1;
1735 aux_data = ni_frame_get_aux_data(p_dec_frame, NI_FRAME_AUX_DATA_BITRATE);
1736 if (aux_data)
1737 {
1738 bitrate = *((int32_t *)aux_data->data);
1739 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): frame aux data bitrate %d\n", __func__,
1740 bitrate);
1741 }
1742
1743 if (p_enc_ctx->target_bitrate > 0)
1744 {
1745 bitrate = p_enc_ctx->target_bitrate;
1746 p_enc_ctx->target_bitrate = -1;
1747 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): API set bitrate %d\n", __func__, bitrate);
1748 }
1749
1750 if (bitrate > 0)
1751 {
1752 p_enc_ctx->enc_change_params->enable_option |=
1754
1755 p_enc_ctx->enc_change_params->bitRate = bitrate;
1756 p_enc_frame->reconf_len = sizeof(ni_encoder_change_params_t);
1757
1758 // update last bitrate with reconfigured bitrate
1759 p_enc_ctx->last_bitrate = bitrate;
1760 ni_log2(p_enc_ctx, NI_LOG_INFO, "%s: bitrate %d updated for reconfig\n", __func__, bitrate);
1761 }
1762
1763 // prep for NetInt API force frame type
1764 if (p_enc_ctx->force_idr_frame)
1765 {
1766 p_enc_frame->force_key_frame = 1;
1767 p_enc_frame->ni_pict_type = PIC_TYPE_IDR;
1768
1769 p_enc_ctx->force_idr_frame = 0;
1770 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): API force IDR frame\n", __func__);
1771 }
1772
1773 // prep for NetInt VUI reconfiguration support: when VUI HRD
1774 // setting has been requested by both frame and API, API takes priority
1775 ni_vui_hrd_t vui = {0};
1776 aux_data = ni_frame_get_aux_data(p_dec_frame, NI_FRAME_AUX_DATA_VUI);
1777 if (aux_data)
1778 {
1779 ni_vui_hrd_t *aux_vui_ptr = (ni_vui_hrd_t *)aux_data->data;
1780
1781 if (aux_vui_ptr->colorDescPresent < 0 || aux_vui_ptr->colorDescPresent > 1)
1782 {
1783 ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s(): invalid colorDescPresent in aux data %d\n",
1784 __func__, aux_vui_ptr->colorDescPresent);
1785 }
1786 else
1787 {
1788 vui.colorDescPresent = aux_vui_ptr->colorDescPresent;
1789 }
1790
1791 if((aux_vui_ptr->aspectRatioWidth > NI_MAX_ASPECTRATIO) || (aux_vui_ptr->aspectRatioHeight > NI_MAX_ASPECTRATIO))
1792 {
1793 ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s(): invalid aspect ratio in aux data %dx%d\n",
1794 __func__, aux_vui_ptr->aspectRatioWidth, aux_vui_ptr->aspectRatioHeight);
1795 }
1796 else
1797 {
1798 vui.colorDescPresent = aux_vui_ptr->colorDescPresent;
1799 vui.colorPrimaries = aux_vui_ptr->colorPrimaries;
1800 vui.colorTrc = aux_vui_ptr->colorTrc;
1801 vui.colorSpace = aux_vui_ptr->colorSpace;
1802 vui.aspectRatioWidth = aux_vui_ptr->aspectRatioWidth;
1803 vui.aspectRatioHeight = aux_vui_ptr->aspectRatioHeight;
1804 }
1805
1806 if (aux_vui_ptr->videoFullRange < 0 || aux_vui_ptr->videoFullRange > 1)
1807 {
1808 ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s(): invalid videoFullRange in aux data %d\n",
1809 __func__, aux_vui_ptr->videoFullRange);
1810 }
1811 else
1812 {
1813 vui.videoFullRange = aux_vui_ptr->videoFullRange;
1814 }
1815 }
1816
1817 if (p_enc_ctx->vui.aspectRatioWidth > 0)
1818 {
1819 vui = p_enc_ctx->vui;
1820 p_enc_ctx->vui.colorDescPresent =
1821 p_enc_ctx->vui.colorPrimaries =
1822 p_enc_ctx->vui.colorTrc =
1823 p_enc_ctx->vui.colorSpace =
1824 p_enc_ctx->vui.aspectRatioWidth =
1825 p_enc_ctx->vui.aspectRatioHeight =
1826 p_enc_ctx->vui.videoFullRange = 0;
1827 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): API set VUI "
1828 "colorDescPresent %d colorPrimaries %d "
1829 "colorTrc %d colorSpace %d aspectRatioWidth %d "
1830 "aspectRatioHeight %d videoFullRange %d\n",
1831 __func__, vui.colorDescPresent,
1832 vui.colorPrimaries, vui.colorTrc,
1835 }
1836
1837 if (vui.aspectRatioWidth > 0)
1838 {
1839 p_enc_ctx->enc_change_params->enable_option |=
1841
1844 p_enc_ctx->enc_change_params->colorTrc = vui.colorTrc;
1845 p_enc_ctx->enc_change_params->colorSpace = vui.colorSpace;
1849 p_enc_frame->reconf_len = sizeof(ni_encoder_change_params_t);
1850 }
1851
1852 // prep for NetInt long term reference interval reconfiguration support:
1853 // when LTR has been requested by both frame and API, API takes priority
1854 int32_t ltr_interval = -1;
1855 aux_data =
1857 if (aux_data)
1858 {
1859 ltr_interval = *((int32_t *)aux_data->data);
1860 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): frame aux data LTR interval %d\n", __func__,
1861 ltr_interval);
1862 }
1863
1864 if (p_enc_ctx->ltr_interval > 0)
1865 {
1866 ltr_interval = p_enc_ctx->ltr_interval;
1867 p_enc_ctx->ltr_interval = -1;
1868 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): API set LTR interval %d\n", __func__,
1869 ltr_interval);
1870 }
1871
1872 if (ltr_interval > 0)
1873 {
1874 p_enc_ctx->enc_change_params->enable_option |=
1876
1877 p_enc_ctx->enc_change_params->ltrInterval = ltr_interval;
1878 p_enc_frame->reconf_len = sizeof(ni_encoder_change_params_t);
1879 }
1880
1881 // prep for NetInt target framerate reconfiguration support: when framerate
1882 // setting has been requested by both frame aux data and API, API takes priority
1883 ni_framerate_t framerate = {0};
1884 aux_data = ni_frame_get_aux_data(p_dec_frame, NI_FRAME_AUX_DATA_FRAMERATE);
1885 if (aux_data)
1886 {
1887 ni_framerate_t *aux_framerate_ptr = (ni_framerate_t *)aux_data->data;
1888 int32_t framerate_num = aux_framerate_ptr->framerate_num;
1889 int32_t framerate_denom = aux_framerate_ptr->framerate_denom;
1890 if ((framerate_num <= 0) || (framerate_denom <= 0))
1891 {
1892 ni_log2(p_enc_ctx, NI_LOG_ERROR,
1893 "ERROR: %s(): invalid framerate in aux data (%d/%d)\n",
1894 __func__, framerate_num, framerate_denom);
1895 } else
1896 {
1897 if ((framerate_num % framerate_denom) != 0)
1898 {
1899 uint32_t numUnitsInTick = 1000;
1900 framerate_num = framerate_num / framerate_denom;
1901 framerate_denom = numUnitsInTick + 1;
1902 framerate_num += 1;
1903 framerate_num *= numUnitsInTick;
1904 } else
1905 {
1906 framerate_num = framerate_num / framerate_denom;
1907 framerate_denom = 1;
1908 }
1909 if (((framerate_num + framerate_denom - 1) / framerate_denom) >
1911 {
1912 ni_log2(p_enc_ctx, NI_LOG_ERROR,
1913 "ERROR: %s(): invalid framerate in aux data (%d/%d)\n",
1914 __func__, aux_framerate_ptr->framerate_num,
1915 aux_framerate_ptr->framerate_denom);
1916 } else
1917 {
1918 framerate.framerate_num = framerate_num;
1919 framerate.framerate_denom = framerate_denom;
1920 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): frame aux data framerate (%d/%d)\n",
1921 __func__, framerate_num, framerate_denom);
1922 }
1923 }
1924 }
1925
1926 if (p_enc_ctx->framerate.framerate_num > 0)
1927 {
1928 framerate = p_enc_ctx->framerate;
1929 p_enc_ctx->framerate.framerate_num =
1930 p_enc_ctx->framerate.framerate_denom = 0;
1931 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): API set framerate (%d/%d)\n", __func__,
1932 framerate.framerate_num, framerate.framerate_denom);
1933 }
1934
1935 if (framerate.framerate_num > 0)
1936 {
1937 p_enc_ctx->enc_change_params->enable_option |=
1939
1940 p_enc_ctx->enc_change_params->frameRateNum = framerate.framerate_num;
1941 p_enc_ctx->enc_change_params->frameRateDenom =
1942 framerate.framerate_denom;
1943 p_enc_frame->reconf_len = sizeof(ni_encoder_change_params_t);
1944
1945 // update last framerate with reconfigured framerate
1946 p_enc_ctx->last_framerate.framerate_num = framerate.framerate_num;
1947 p_enc_ctx->last_framerate.framerate_denom = framerate.framerate_denom;
1948 ni_log2(p_enc_ctx, NI_LOG_INFO, "%s: framerate num %d denom %d updated for reconfig\n",
1949 __func__, framerate.framerate_num, framerate.framerate_denom);
1950 }
1951
1952 // prep for NetInt frame reference invalidation support: when this setting
1953 // has been requested by both frame and API, API takes priority
1954 int32_t frame_num = -1;
1955 aux_data =
1957 if (aux_data)
1958 {
1959 frame_num = *((int32_t *)aux_data->data);
1960 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): frame aux data frame ref invalid %d\n",
1961 __func__, frame_num);
1962 }
1963
1964 if (p_enc_ctx->ltr_frame_ref_invalid > 0)
1965 {
1966 frame_num = p_enc_ctx->ltr_frame_ref_invalid;
1967 p_enc_ctx->ltr_frame_ref_invalid = -1;
1968 ni_log2(p_enc_ctx, NI_LOG_ERROR, "%s(): API set frame ref invalid %d\n", __func__,
1969 frame_num);
1970 }
1971
1972 if (frame_num >= 0)
1973 {
1974 p_enc_ctx->enc_change_params->enable_option |=
1976
1977 p_enc_ctx->enc_change_params->invalidFrameNum = frame_num;
1978 p_enc_frame->reconf_len = sizeof(ni_encoder_change_params_t);
1979 }
1980
1981 // prep for alternative preferred transfer characteristics SEI
1983 should_send_sei_with_frame)
1984 {
1985 if (NI_CODEC_FORMAT_H264 == codec_format)
1986 {
1987 p_enc_frame->preferred_characteristics_data_len = 9;
1988 } else
1989 {
1990 p_enc_frame->preferred_characteristics_data_len = 10;
1991 }
1992
1994 (uint8_t)
1996 p_enc_frame->sei_total_len +=
1998 }
1999
2000 // prep for NetInt maxFrameSize reconfiguration support: when maxFrameSize
2001 // setting has been requested by both frame aux data and API, API takes priority
2002 int32_t max_frame_size = 0;
2004 if (aux_data)
2005 {
2006 max_frame_size = *((int32_t *)aux_data->data);
2007 uint32_t maxFrameSize = (uint32_t)max_frame_size / 2000;
2008 uint32_t min_maxFrameSize;
2009 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): frame aux data max_frame_size %d\n", __func__,
2010 max_frame_size);
2011
2012 if (!api_params->low_delay_mode)
2013 {
2014 ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s(): max_frame_size %d is valid only when lowDelay mode is enabled\n",
2015 __func__, max_frame_size);
2016 max_frame_size = 0;
2017 }
2018 else
2019 {
2020 int32_t tmp_bitrate, tmp_framerate_num, tmp_framerate_denom;
2021 tmp_bitrate = (p_enc_ctx->enc_change_params->bitRate > 0) ? p_enc_ctx->enc_change_params->bitRate : api_params->bitrate;
2022
2023 if ((p_enc_ctx->enc_change_params->frameRateNum > 0) && (p_enc_ctx->enc_change_params->frameRateDenom > 0))
2024 {
2025 tmp_framerate_num = p_enc_ctx->enc_change_params->frameRateNum;
2026 tmp_framerate_denom = p_enc_ctx->enc_change_params->frameRateDenom;
2027 }
2028 else
2029 {
2030 tmp_framerate_num = (int32_t)api_params->fps_number;
2031 tmp_framerate_denom = (int32_t)api_params->fps_denominator;
2032 }
2033
2034 min_maxFrameSize = (((uint32_t)tmp_bitrate / tmp_framerate_num * tmp_framerate_denom) / 8) / 2000;
2035
2036 if (maxFrameSize < min_maxFrameSize)
2037 {
2038 ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s(): max_frame_size %d is too small (invalid)\n",
2039 __func__, max_frame_size);
2040 max_frame_size = 0;
2041 }
2042
2043 if (max_frame_size > NI_MAX_FRAME_SIZE) {
2044 max_frame_size = NI_MAX_FRAME_SIZE;
2045 }
2046 }
2047 }
2048
2049 if (p_enc_ctx->max_frame_size > 0)
2050 {
2051 max_frame_size = p_enc_ctx->max_frame_size;
2052 p_enc_ctx->max_frame_size = 0;
2053 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): API set max_frame_size %d\n", __func__, max_frame_size);
2054 }
2055
2056 if (max_frame_size > 0)
2057 {
2058 p_enc_ctx->enc_change_params->enable_option |=
2060
2061 p_enc_ctx->enc_change_params->maxFrameSize = (uint16_t)(max_frame_size / 2000);
2062 p_enc_frame->reconf_len = sizeof(ni_encoder_change_params_t);
2063 }
2064
2065 // prep for NetInt crf reconfiguration support: when crf
2066 // setting has been requested by both frame aux data and API, API takes priority
2067 float crf = -1.0f;
2068 aux_data = ni_frame_get_aux_data(p_dec_frame, NI_FRAME_AUX_DATA_CRF);
2069 if (aux_data)
2070 {
2071 crf = (float)(*((int32_t *)aux_data->data));
2072 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): frame aux data crf %d\n", __func__,
2073 crf);
2074
2075 if (api_params->cfg_enc_params.crf < 0)
2076 {
2077 ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s(): reconfigure crf value %d is valid only in CRF mode\n",
2078 __func__, crf);
2079 crf = -1;
2080 }
2081 else
2082 {
2083 if (crf < 0 || crf > 51)
2084 {
2085 ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s(): crf value %d is invalid (valid range in [0..51])\n",
2086 __func__, crf);
2087 crf = -1;
2088 }
2089 }
2090 }
2091 aux_data = ni_frame_get_aux_data(p_dec_frame, NI_FRAME_AUX_DATA_CRF_FLOAT);
2092 if (aux_data)
2093 {
2094 crf = *((float *)aux_data->data);
2095 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): frame aux data crf %f\n", __func__,
2096 crf);
2097
2098 if (api_params->cfg_enc_params.crfFloat < 0)
2099 {
2100 ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s(): reconfigure crf value %f is valid only in CRF mode\n",
2101 __func__, crf);
2102 crf = -1;
2103 }
2104 else
2105 {
2106 if (crf < 0 || crf > 51)
2107 {
2108 ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s(): crf value %f is invalid (valid range in [0..51])\n",
2109 __func__, crf);
2110 crf = -1;
2111 }
2112 }
2113 }
2114
2115 if (p_enc_ctx->reconfig_crf >= 0 || p_enc_ctx->reconfig_crf_decimal > 0)
2116 {
2117 crf = (float)(p_enc_ctx->reconfig_crf +
2118 (float)p_enc_ctx->reconfig_crf_decimal / 100.0);
2119 p_enc_ctx->reconfig_crf = -1;
2120 p_enc_ctx->reconfig_crf_decimal = 0;
2121 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): API set reconfig_crf %f\n", __func__, crf);
2122 }
2123
2124 if (crf >= 0)
2125 {
2126 p_enc_ctx->enc_change_params->enable_option |=
2128
2129 p_enc_ctx->enc_change_params->crf = (uint8_t)crf;
2130 p_enc_ctx->enc_change_params->crfDecimal =
2131 (uint8_t)((crf - (float)p_enc_ctx->enc_change_params->crf) * 100);
2132 p_enc_frame->reconf_len = sizeof(ni_encoder_change_params_t);
2133 }
2134
2135 int32_t vbvMaxRate = 0;
2137 if (aux_data)
2138 {
2139 vbvMaxRate = *((int32_t *)aux_data->data);
2140 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): frame aux data vbvMaxRate %d\n", __func__,
2141 vbvMaxRate);
2142 }
2143
2144 if (p_enc_ctx->reconfig_vbv_max_rate > 0)
2145 {
2146 vbvMaxRate = p_enc_ctx->reconfig_vbv_max_rate;
2147 p_enc_ctx->reconfig_vbv_max_rate = 0;
2148 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): API set reconfig_vbv_max_rate %d\n", __func__, vbvMaxRate);
2149 }
2150
2151 if (vbvMaxRate)
2152 {
2153 p_enc_ctx->enc_change_params->enable_option |=
2155
2156 p_enc_ctx->enc_change_params->vbvMaxRate = vbvMaxRate;
2157 p_enc_frame->reconf_len = sizeof(ni_encoder_change_params_t);
2158 }
2159
2160 int32_t vbvBufferSize = 0;
2162 if (aux_data)
2163 {
2164 vbvBufferSize = *((int32_t *)aux_data->data);
2165 if ((vbvBufferSize < 10 && vbvBufferSize != 0) || vbvBufferSize > 3000)
2166 {
2167 ni_log2(p_enc_ctx, NI_LOG_ERROR, "%s(): invalid frame aux data vbvBufferSize %d\n", __func__,
2168 vbvBufferSize);
2169 vbvBufferSize = 0;
2170 }
2171 else
2172 {
2173 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): frame aux data vbvBufferSize %d\n", __func__,
2174 vbvBufferSize);
2175 }
2176 }
2177
2178 if (p_enc_ctx->reconfig_vbv_buffer_size > 0)
2179 {
2180 vbvBufferSize = p_enc_ctx->reconfig_vbv_buffer_size;
2181 p_enc_ctx->reconfig_vbv_buffer_size = 0;
2182 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): API set reconfig_vbv_max_rate %d\n", __func__, vbvBufferSize);
2183 }
2184
2185 if (vbvBufferSize)
2186 {
2187 p_enc_ctx->enc_change_params->enable_option |=
2189
2190 p_enc_ctx->enc_change_params->vbvBufferSize = vbvBufferSize;
2191 p_enc_frame->reconf_len = sizeof(ni_encoder_change_params_t);
2192 }
2193
2194 int16_t sliceArg = 0;
2195 aux_data = ni_frame_get_aux_data(p_dec_frame, NI_FRAME_AUX_DATA_SLICE_ARG);
2196 if (aux_data)
2197 {
2198 sliceArg = *((int16_t *)aux_data->data);
2199 ni_encoder_cfg_params_t *p_enc = &api_params->cfg_enc_params;
2200 if (p_enc->slice_mode == 0)
2201 {
2202 ni_log2(p_enc_ctx, NI_LOG_ERROR, "%s():not support to reconfig slice_arg when slice_mode disable.\n",
2203 __func__);
2204 sliceArg = 0;
2205 }
2206 if (NI_CODEC_FORMAT_JPEG == p_enc_ctx->codec_format || NI_CODEC_FORMAT_AV1 == p_enc_ctx->codec_format)
2207 {
2208 ni_log2(p_enc_ctx, NI_LOG_ERROR, "%s():sliceArg is only supported for H.264 or H.265.\n",
2209 __func__);
2210 sliceArg = 0;
2211 }
2212 int ctu_mb_size = (NI_CODEC_FORMAT_H264 == p_enc_ctx->codec_format) ? 16 : 64;
2213 int max_num_ctu_mb_row = (api_params->source_height + ctu_mb_size - 1) / ctu_mb_size;
2214 if (sliceArg < 1 || sliceArg > max_num_ctu_mb_row)
2215 {
2216 ni_log2(p_enc_ctx, NI_LOG_ERROR, "%s(): invalid frame aux data sliceArg %d\n", __func__,
2217 sliceArg);
2218 sliceArg = 0;
2219 }
2220 else
2221 {
2222 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): frame aux data sliceArg %d\n", __func__,
2223 sliceArg);
2224 }
2225 }
2226
2227 if (p_enc_ctx->reconfig_slice_arg > 0)
2228 {
2229 sliceArg = p_enc_ctx->reconfig_slice_arg;
2230 p_enc_ctx->reconfig_slice_arg = 0;
2231 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): API set reconfig_slice_arg %d\n", __func__, sliceArg);
2232 }
2233
2234 if (sliceArg)
2235 {
2236 if (sliceArg > NI_MAX_SLICE_SIZE) {
2237 ni_log2(p_enc_ctx, NI_LOG_INFO, "%s(): slice arg > NI_MAX_SLICE_SIZE, change from %d to %d\n",
2238 __func__, sliceArg, NI_MAX_SLICE_SIZE);
2239 sliceArg = NI_MAX_SLICE_SIZE;
2240 }
2241 p_enc_ctx->enc_change_params->enable_option |=
2243
2244 p_enc_ctx->enc_change_params->sliceArg = sliceArg;
2245 p_enc_frame->reconf_len = sizeof(ni_encoder_change_params_t);
2246 }
2247}
2248
2249/*!*****************************************************************************
2250 * \brief Copy auxiliary data that should be sent together with this frame
2251 * to encoder.
2252 *
2253 * \param[in] p_enc_ctx encoder session context
2254 * \param[out] p_enc_frame frame to be sent to encoder
2255 * \param[in] p_dec_frame frame returned by decoder
2256 * \param[in] mdcv_data SEI for HDR mastering display color volume info
2257 * \param[in] cll_data SEI for HDR content light level info
2258 * \param[in] cc_data SEI for close caption
2259 * \param[in] udu_data SEI for User data unregistered
2260 * \param[in] hdrp_data SEI for HDR10+
2261 * \param[in] is_hwframe, must be 0 (sw frame) or 1 (hw frame)
2262 * \param[in] is_semiplanar, must be 1 (semiplanar frame) or 0 (not)
2263 *
2264 * \return NONE
2265 ******************************************************************************/
2267 ni_frame_t *p_enc_frame, ni_frame_t *p_dec_frame,
2268 ni_codec_format_t codec_format,
2269 const uint8_t *mdcv_data, const uint8_t *cll_data,
2270 const uint8_t *cc_data, const uint8_t *udu_data,
2271 const uint8_t *hdrp_data, int is_hwframe,
2272 int is_semiplanar)
2273{
2274 ni_xcoder_params_t *api_params =
2276
2277 // fill in extra data (skipping meta data header)
2278 if (is_hwframe != 0 && is_hwframe != 1 && is_semiplanar != 0 &&
2279 is_semiplanar != 1)
2280 {
2281 ni_log2(p_enc_ctx, NI_LOG_ERROR,
2282 "ni_enc_copy_aux_data: error, illegal hwframe or nv12frame\n");
2283 return;
2284 }
2285
2286 uint32_t frame_metadata_size = NI_APP_ENC_FRAME_META_DATA_SIZE;
2288 "6Q") < 0)
2289 {
2291 }
2293 "6rc") < 0)
2294 {
2296 }
2297
2298
2299 uint8_t *dst = (uint8_t *)p_enc_frame->p_data[2 + is_hwframe] +
2300 p_enc_frame->data_len[2 + is_hwframe] + frame_metadata_size;
2301
2302 if (!is_hwframe)
2303 {
2304 dst = (uint8_t *)p_enc_frame->p_data[2 - is_semiplanar] +
2305 p_enc_frame->data_len[2 - is_semiplanar] +
2306 frame_metadata_size;
2307 }
2308
2309 // Separate metadata buffer (not contiguous with YUV buffer)
2310 if (p_enc_frame->separate_metadata)
2311 {
2312 dst = p_enc_frame->p_metadata_buffer + frame_metadata_size;
2313 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_copy_aux_data: p_metadata_buffer %p frame_metadata_size %u dst %p\n",
2314 p_enc_frame->p_metadata_buffer, frame_metadata_size, dst);
2315 }
2316
2317 // fill in reconfig data if enabled; even if it's disabled, keep the space
2318 // for it if SEI or ROI is present;
2319 if (p_enc_frame->reconf_len || api_params->cfg_enc_params.roi_enable ||
2320 p_enc_frame->sei_total_len)
2321 {
2322 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_copy_aux_data: keep reconfig space: %"
2323 PRId64 " to %p\n", sizeof(ni_encoder_change_params_t), dst);
2324
2325 memset(dst, 0, sizeof(ni_encoder_change_params_t));
2326
2327 if (p_enc_frame->reconf_len && p_enc_ctx->enc_change_params)
2328 {
2329 memcpy(dst, p_enc_ctx->enc_change_params, p_enc_frame->reconf_len);
2330 }
2331
2332 dst += sizeof(ni_encoder_change_params_t);
2333 }
2334
2335 // fill in ROI map, if ROI is enabled; the ROI map could be:
2336 // - a zeroed one, e.g. in the case of no any ROI specified yet at session
2337 // start, or
2338 // - one generated by ROI auxiliary data coming with the frame, or
2339 // - a hardcoded one created in nienc/xcoder by ROI demo modes
2340 if (api_params->cfg_enc_params.roi_enable)
2341 {
2342 if (p_enc_frame->roi_len && p_enc_ctx->roi_map)
2343 {
2344 memcpy(dst, p_enc_ctx->roi_map, p_enc_frame->roi_len);
2345 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_copy_aux_data: ROI size: %u to %p\n",
2346 p_enc_frame->roi_len, dst);
2347
2348 } else
2349 {
2350 memset(dst, 0, p_enc_ctx->roi_len);
2351 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_copy_aux_data: zeroed ROI size: %u to %p\n",
2352 p_enc_ctx->roi_len, dst);
2353 }
2354 // for QUADRA, when ROI enabled, requires ROI map included in input buffer and data transferred for every frame
2355 dst += p_enc_ctx->roi_len;
2356 // reset frame ROI len to the actual map size
2357 p_enc_frame->roi_len = p_enc_ctx->roi_len;
2358 }
2359
2360 // HDR SEI: mastering display color volume
2362 {
2363 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_copy_aux_data: HDR SEI mdcv size: %u to %p\n",
2364 p_enc_frame->sei_hdr_mastering_display_color_vol_len, dst);
2365 memcpy(dst, mdcv_data,
2367 dst += p_enc_frame->sei_hdr_mastering_display_color_vol_len;
2368 }
2369
2370 // HDR SEI: content light level info
2371 if (p_enc_frame->sei_hdr_content_light_level_info_len)
2372 {
2373 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_copy_aux_data: HDR SEI cll size: %u to %p\n",
2374 p_enc_frame->sei_hdr_content_light_level_info_len, dst);
2375
2376 memcpy(dst, cll_data,
2378 dst += p_enc_frame->sei_hdr_content_light_level_info_len;
2379 }
2380
2381 // HLG SEI: preferred characteristics
2382 if (p_enc_frame->preferred_characteristics_data_len)
2383 {
2384 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_copy_aux_data: preferred characteristics size: %u to %p\n",
2385 p_enc_frame->preferred_characteristics_data_len, dst);
2386
2387 dst[0] = dst[1] = dst[2] = 0;
2388 dst[3] = 1;
2389 if (NI_CODEC_FORMAT_H265 == codec_format)
2390 {
2391 dst[4] = 0x4e;
2392 dst[5] = 1;
2393 dst[6] = 0x93; // payload type=147
2394 dst[7] = 1; // payload size=1
2395 dst += 8;
2396 } else
2397 {
2398 dst[4] = 0x6;
2399 dst[5] = 0x93; // payload type=147
2400 dst[6] = 1; // payload size=1
2401 dst += 7;
2402 }
2403 *dst = p_enc_ctx->preferred_characteristics_data;
2404 dst++;
2405 *dst = 0x80;
2406 dst++;
2407 }
2408
2409 // close caption
2410 if (p_enc_frame->sei_cc_len)
2411 {
2412 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_copy_aux_data: close caption size: %u to %p\n",
2413 p_enc_frame->sei_cc_len, dst);
2414
2415 memcpy(dst, cc_data, p_enc_frame->sei_cc_len);
2416 dst += p_enc_frame->sei_cc_len;
2417 }
2418
2419 // HDR10+
2420 if (p_enc_frame->sei_hdr_plus_len)
2421 {
2422 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_copy_aux_data: HDR10+ size: %u to %p\n",
2423 p_enc_frame->sei_hdr_plus_len, dst);
2424
2425 memcpy(dst, hdrp_data, p_enc_frame->sei_hdr_plus_len);
2426 dst += p_enc_frame->sei_hdr_plus_len;
2427 }
2428
2429 // User data unregistered SEI
2430 if (p_enc_frame->sei_user_data_unreg_len)
2431 {
2432 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_copy_aux_data: UDU size: %u to %p\n",
2433 p_enc_frame->sei_user_data_unreg_len, dst);
2434 memcpy(dst, udu_data, p_enc_frame->sei_user_data_unreg_len);
2435 //dst += p_enc_frame->sei_user_data_unreg_len;
2436 }
2437}
2438
2439/*!*****************************************************************************
2440 * \brief Insert timecode data into picture timing SEI (H264) or time code SEI (H265)
2441 *
2442 * \note This function must be callled after all other aux data has been processed by
2443 * ni_enc_prep_aux_data and ni_enc_copy_aux_data. Otherwise the timecode SEI data
2444 * might be overwritten
2445 *
2446 * \param[in] p_enc_ctx encoder session context
2447 * \param[out] p_enc_frame frame to be sent to encoder
2448 * \param[in] p_timecode the timecode data to be written along with the frame
2449 *
2450 * \return NI_RETCODE_SUCCESS on success, NI_RETCODE_FAILURE on failure
2451 ******************************************************************************/
2453 ni_timecode_t *p_timecode)
2454{
2455 uint8_t timecode_data[NI_MAX_SEI_DATA];
2456 uint8_t *dst = timecode_data;
2458 uint32_t header_len, payload_len, total_len;
2459 int emu_bytes_inserted, is_hwframe, is_semiplanar;
2460
2461 if (!p_enc_ctx || !p_enc_frame || !p_timecode) {
2462 ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s received NULL parameter\n", __func__);
2463 return NI_RETCODE_FAILURE;
2464 }
2465
2466 if (p_enc_ctx->codec_format != NI_CODEC_FORMAT_H264 && p_enc_ctx->codec_format != NI_CODEC_FORMAT_H265) {
2467 ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s insertion of timecode in SEI is only supported on H264 and H265 encoder\n", __func__);
2468 return NI_RETCODE_FAILURE;
2469 }
2470
2472
2473 // NAL start code
2474 ni_bs_writer_put(&pb, 0x00, 8);
2475 ni_bs_writer_put(&pb, 0x00, 8);
2476 ni_bs_writer_put(&pb, 0x00, 8);
2477 ni_bs_writer_put(&pb, 0x01, 8);
2478
2479 // NAL type: SEI
2480 if (p_enc_ctx->codec_format == NI_CODEC_FORMAT_H264) {
2481 ni_bs_writer_put(&pb, 0x06, 8);
2482 } else {
2483 ni_bs_writer_put(&pb, 0x4e, 8);
2484 ni_bs_writer_put(&pb, 0x01, 8);
2485 }
2486
2487 // SEI type: picture timing (1) for H264, time code (136) for H265
2488 if (p_enc_ctx->codec_format == NI_CODEC_FORMAT_H264) {
2489 ni_bs_writer_put(&pb, 0x01, 8);
2490 header_len = 7;
2491 } else {
2492 ni_bs_writer_put(&pb, 0x88, 8);
2493 header_len = 8;
2494 }
2495
2496 // SEI payload size, to be set later
2497 ni_bs_writer_put(&pb, 0x00, 8);
2498
2499 if (p_enc_ctx->codec_format == NI_CODEC_FORMAT_H264) {
2500 ni_bs_writer_put(&pb, 0x0, 4); // pic_struct, always 0 (progressive)
2501 } else {
2502 ni_bs_writer_put(&pb, 0x1, 2); // num_clock_ts, only support inserting 1
2503 }
2504
2505 // actual timestamp data below, retrieve the values from ni_timecode_t passed in
2506 ni_bs_writer_put(&pb, 0x1, 1); // clock_timestamp_flag = 1
2507 if (p_enc_ctx->codec_format == NI_CODEC_FORMAT_H264) {
2508 ni_bs_writer_put(&pb, 0x0, 2); // ct_type, always 0 (progressive)
2509 }
2510 ni_bs_writer_put(&pb, p_timecode->nuit_field_based_flag, 1);
2511 ni_bs_writer_put(&pb, p_timecode->counting_type, 5);
2512 ni_bs_writer_put(&pb, p_timecode->full_timestamp_flag, 1);
2513 ni_bs_writer_put(&pb, p_timecode->discontinuity_flag, 1);
2514 ni_bs_writer_put(&pb, p_timecode->cnt_dropped_flag, 1);
2515 if (p_enc_ctx->codec_format == NI_CODEC_FORMAT_H264) {
2516 ni_bs_writer_put(&pb, p_timecode->n_frames, 8);
2517 } else {
2518 ni_bs_writer_put(&pb, p_timecode->n_frames, 9);
2519 }
2520 if (p_timecode->full_timestamp_flag) {
2521 ni_bs_writer_put(&pb, p_timecode->seconds_value, 6);
2522 ni_bs_writer_put(&pb, p_timecode->minutes_value, 6);
2523 ni_bs_writer_put(&pb, p_timecode->hours_value, 5);
2524 } else {
2525 ni_bs_writer_put(&pb, p_timecode->seconds_flag, 1);
2526 if (p_timecode->seconds_flag) {
2527 ni_bs_writer_put(&pb, p_timecode->seconds_value, 6);
2528 ni_bs_writer_put(&pb, p_timecode->minutes_flag, 1);
2529 if (p_timecode->minutes_flag) {
2530 ni_bs_writer_put(&pb, p_timecode->minutes_value, 6);
2531 ni_bs_writer_put(&pb, p_timecode->hours_flag, 1);
2532 if (p_timecode->hours_flag) {
2533 ni_bs_writer_put(&pb, p_timecode->hours_value, 5);
2534 }
2535 }
2536 }
2537 }
2538 if (p_enc_ctx->codec_format == NI_CODEC_FORMAT_H265) {
2539 ni_bs_writer_put(&pb, p_timecode->time_offset_length, 5);
2540 if (p_timecode->time_offset_length) {
2541 ni_bs_writer_put(&pb, p_timecode->time_offset_value, p_timecode->time_offset_length);
2542 }
2543 } else {
2544 // for H264, time_offset_length is stored in HRD parameters in VUI, which can only be set
2545 // in the FW when HRD is enabled, so we assume that it is not present, in which case it
2546 // should be intepreted as 24 by default
2547 ni_bs_writer_put(&pb, p_timecode->time_offset_value, 24);
2548 }
2549
2550 ni_bs_writer_put(&pb, 1, 1);
2552 payload_len = (uint32_t)((ni_bs_writer_tell(&pb) + 7) / 8) - header_len;
2553 ni_bs_writer_copy(dst, &pb);
2554 ni_bs_writer_clear(&pb);
2555
2556 // set the SEI payload size
2557 if (p_enc_ctx->codec_format == NI_CODEC_FORMAT_H264) {
2558 dst[6] = payload_len;
2559 } else {
2560 dst[7] = payload_len;
2561 }
2562 dst += header_len;
2563
2564 // insert emulation prevention bytes to the SEI payload data and write trailing bits
2565 emu_bytes_inserted = ni_insert_emulation_prevent_bytes(dst, (int)payload_len);
2566 dst += payload_len + emu_bytes_inserted;
2567 *dst = 0x80;
2568
2569 // total size of the timecode_data buffer to be copied
2570 total_len = header_len + payload_len + emu_bytes_inserted + 1;
2571
2572 is_hwframe = p_enc_ctx->hw_action != NI_CODEC_HW_NONE;
2573 is_semiplanar = p_enc_ctx->pixel_format == NI_PIX_FMT_NV12 ||
2574 p_enc_ctx->pixel_format == NI_PIX_FMT_P010LE;
2575 dst = (uint8_t *)p_enc_frame->p_data[2 + is_hwframe] +
2576 p_enc_frame->data_len[2 + is_hwframe] + p_enc_frame->extra_data_len;
2577 if (!is_hwframe)
2578 {
2579 dst = (uint8_t *)p_enc_frame->p_data[2 - is_semiplanar] +
2580 p_enc_frame->data_len[2 - is_semiplanar] + p_enc_frame->extra_data_len;
2581 }
2582
2583 // separate metadata buffer (not contiguous with YUV buffer)
2584 if (p_enc_frame->separate_metadata)
2585 {
2586 dst = p_enc_frame->p_metadata_buffer + p_enc_frame->extra_data_len;
2587 }
2588
2589 // copy formatted SEI NAL unit data to the proper buffer
2590 memcpy(dst, timecode_data, total_len);
2591
2592 // finally, update the relevant data size counters in ni_frame_t
2593 p_enc_frame->sei_total_len += total_len;
2594 p_enc_frame->extra_data_len += total_len;
2595
2596 return NI_RETCODE_SUCCESS;
2597}
2598
2599/*!*****************************************************************************
2600 * \brief Send an input data frame to the encoder with YUV data given in
2601 * the inputs.
2602 *
2603 * For ideal performance memory should be 4k aligned. If it is not 4K aligned
2604 * then a temporary 4k aligned memory will be used to copy data to and from
2605 * when writing and reading. This will negatively impact performance.
2606 *
2607 * Any metadata to be sent with the frame should be attached to p_enc_frame
2608 * as aux data (e.g. using ni_frame_new_aux_data()).
2609 *
2610 * \param[in] p_ctx Encoder session context
2611 * \param[in] p_enc_frame Struct holding information about the frame
2612 * to be sent to the encoder
2613 * \param[in] p_yuv_buffer Caller allocated buffer holding YUV data
2614 * for the frame
2615 *
2616 * \return On success
2617 * Total number of bytes written
2618 * On failure
2619 * NI_RETCODE_INVALID_PARAM
2620 * NI_RETCODE_ERROR_MEM_ALOC
2621 * NI_RETCODE_ERROR_NVME_CMD_FAILED
2622 * NI_RETCODE_ERROR_INVALID_SESSION
2623 *****************************************************************************/
2625 ni_frame_t *p_enc_frame, uint8_t *p_yuv_buffer)
2626{
2627 int frame_width;
2628 int frame_height;
2629 bool need_copy = true;
2630 ni_xcoder_params_t *p_param;
2632 bool alignment_2pass_wa = false;
2633 int is_hwframe;
2634
2635 if (!p_ctx || !p_enc_frame)
2636 {
2637 ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s passed parameters are null, return\n",
2638 __func__);
2640 }
2641
2642 if (!p_yuv_buffer)
2643 {
2644 // send EOS
2645 p_enc_frame->end_of_stream = 1;
2646 goto send_frame;
2647 }
2648
2649 if (((uintptr_t)p_yuv_buffer) % NI_MEM_PAGE_ALIGNMENT)
2650 {
2651 ni_log2(p_ctx, NI_LOG_INFO, "WARNING: %s passed buffer ptr %p is not 4k aligned\n",
2652 __func__, p_yuv_buffer);
2653
2654 }
2655
2656 is_hwframe = p_ctx->hw_action != NI_CODEC_HW_NONE;
2657 frame_width = p_enc_frame->video_width;
2658 frame_height = p_enc_frame->video_height;
2659 p_param = (ni_xcoder_params_t *)p_ctx->p_session_config;
2660
2661 // extra data starts with metadata header
2663
2664 if (!p_enc_frame->start_of_stream &&
2665 (p_enc_frame->video_width != p_ctx->actual_video_width ||
2666 p_enc_frame->video_height != p_ctx->active_video_height ||
2667 p_enc_frame->pixel_format != p_ctx->pixel_format))
2668 {
2669 ni_log2(p_ctx, NI_LOG_INFO,
2670 "%s: resolution change %dx%d -> %dx%d "
2671 "or pixel format change %d -> %d\n",
2672 __func__, p_ctx->actual_video_width, p_ctx->active_video_height,
2673 p_enc_frame->video_width, p_enc_frame->video_height,
2674 p_ctx->pixel_format, p_enc_frame->pixel_format);
2675
2676 // change run state
2678
2679 ni_log2(p_ctx, NI_LOG_DEBUG, "%s: session_run_state change to %d \n", __func__,
2680 p_ctx->session_run_state);
2681
2682 // send EOS
2683 p_enc_frame->end_of_stream = 1;
2684 goto send_frame;
2685 }
2686
2687 // ROI demo mode takes higher priority over aux data
2688 // Note: when ROI demo modes enabled, supply ROI map for the specified range
2689 // frames, and 0 map for others
2690 if (p_param->roi_demo_mode && p_param->cfg_enc_params.roi_enable)
2691 {
2692 if (p_ctx->frame_num > 90 && p_ctx->frame_num < 300)
2693 {
2694 p_enc_frame->roi_len = p_ctx->roi_len;
2695 } else
2696 {
2697 p_enc_frame->roi_len = 0;
2698 }
2699 // when ROI enabled, always have a data buffer for ROI
2700 // Note: this is handled separately from ROI through side/aux data
2701 p_enc_frame->extra_data_len += p_ctx->roi_len;
2702 }
2703
2704 int should_send_sei_with_frame =
2706
2707 uint8_t mdcv_data[NI_MAX_SEI_DATA];
2708 uint8_t cll_data[NI_MAX_SEI_DATA];
2709 uint8_t cc_data[NI_MAX_SEI_DATA];
2710 uint8_t udu_data[NI_MAX_SEI_DATA];
2711 uint8_t hdrp_data[NI_MAX_SEI_DATA];
2712
2713 // Convert aux data attached to input frame into required format,
2714 // and store in local arrays
2715 ni_enc_prep_aux_data(p_ctx, p_enc_frame, p_enc_frame, p_ctx->codec_format,
2716 should_send_sei_with_frame, mdcv_data, cll_data,
2717 cc_data, udu_data, hdrp_data);
2718
2719 p_enc_frame->extra_data_len += p_enc_frame->sei_total_len;
2720
2721 // data layout requirement: leave space for reconfig data if at least one of
2722 // reconfig, SEI or ROI is present
2723 // Note: ROI is present when enabled, so use encode config flag instead of
2724 // frame's roi_len as it can be 0 indicating a 0'd ROI map setting !
2725 if (p_enc_frame->reconf_len || p_enc_frame->sei_total_len ||
2726 (p_param->roi_demo_mode && p_param->cfg_enc_params.roi_enable))
2727 {
2728 p_enc_frame->extra_data_len += sizeof(ni_encoder_change_params_t);
2729 }
2730
2731 // Check whether line-by-line copy is needed
2732 int dst_stride[NI_MAX_NUM_DATA_POINTERS] = {0};
2733 int dst_height_aligned[NI_MAX_NUM_DATA_POINTERS] = {0};
2734 int is_semiplanar = !ni_get_planar_from_pixfmt(p_ctx->pixel_format);
2735 ni_get_hw_yuv420p_dim(frame_width, frame_height, p_ctx->bit_depth_factor,
2736 is_semiplanar, dst_stride, dst_height_aligned);
2737
2738 int src_stride[NI_MAX_NUM_DATA_POINTERS];
2739 int src_height[NI_MAX_NUM_DATA_POINTERS];
2740 uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS];
2741
2742 bool isrgba = (p_ctx->pixel_format == NI_PIX_FMT_ABGR || p_ctx->pixel_format == NI_PIX_FMT_ARGB
2743 || p_ctx->pixel_format == NI_PIX_FMT_RGBA || p_ctx->pixel_format == NI_PIX_FMT_BGRA);
2744
2745 // NOTE - FFmpeg / Gstreamer users should use linesize array in frame structure instead of src_stride in the following sample code
2746 src_stride[0] = frame_width * p_ctx->bit_depth_factor;
2747 src_height[0] = frame_height;
2748 p_src[0] = p_yuv_buffer;
2749
2750 if (isrgba)
2751 {
2752 src_stride[1] = 0;
2753 src_stride[2] = 0;
2754
2755 src_height[1] = 0;
2756 src_height[2] = 0;
2757
2758 p_src[1] = NULL;
2759 p_src[2] = NULL;
2760 }
2761 else
2762 {
2763 src_stride[1] = is_semiplanar ? src_stride[0] : src_stride[0] / 2;
2764 src_stride[2] = is_semiplanar ? 0 : src_stride[0] / 2;
2765
2766 src_height[1] = src_height[0] / 2;
2767 src_height[2] = is_semiplanar ? 0 : src_height[1];
2768
2769 p_src[1] = p_src[0] + src_stride[0] * src_height[0];
2770 p_src[2] = p_src[1] + src_stride[1] * src_height[1];
2771 }
2772
2773 alignment_2pass_wa = (
2774 (p_param->cfg_enc_params.lookAheadDepth ||
2775 p_param->cfg_enc_params.crf >= 0 ||
2776 p_param->cfg_enc_params.crfFloat >= 0) &&
2779
2780 if (alignment_2pass_wa && !is_hwframe) {
2781 if (is_semiplanar) {
2782 // for 2-pass encode output mismatch WA, need to extend (and
2783 // pad) CbCr plane height, because 1st pass assume input 32
2784 // align
2785 dst_height_aligned[1] = (((dst_height_aligned[0] + 31) / 32) * 32) / 2;
2786 } else {
2787 // for 2-pass encode output mismatch WA, need to extend (and
2788 // pad) Cr plane height, because 1st pass assume input 32 align
2789 dst_height_aligned[2] = (((dst_height_aligned[0] + 31) / 32) * 32) / 2;
2790 }
2791 }
2792
2793 // check input resolution zero copy compatible or not
2795 p_param, frame_width, frame_height,
2796 (const int *)src_stride, false) == NI_RETCODE_SUCCESS)
2797 {
2798 need_copy = false;
2799 //alloc metadata buffer etc. (if needed)
2801 p_enc_frame, frame_width,
2802 frame_height, (const int *)src_stride, (const uint8_t **)p_src,
2803 (int)(p_enc_frame->extra_data_len));
2804 if (retval != NI_RETCODE_SUCCESS)
2805 goto end;
2806 }
2807 else
2808 {
2809 // if linesize changes (while resolution remains the same), copy to previously configured linesizes
2810 if (p_param->luma_linesize && p_param->chroma_linesize)
2811 {
2812 dst_stride[0] = p_param->luma_linesize;
2813 dst_stride[1] = p_param->chroma_linesize;
2814 dst_stride[2] = is_semiplanar ? 0 : p_param->chroma_linesize;
2815 }
2817 p_param->cfg_enc_params.planar, p_enc_frame, frame_width,
2818 dst_height_aligned[0], dst_stride,
2820 (int)(p_enc_frame->extra_data_len), alignment_2pass_wa);
2821 if (retval != NI_RETCODE_SUCCESS)
2822 {
2823 return retval;
2824 }
2825 }
2826
2827 ni_log2(p_ctx, NI_LOG_TRACE,
2828 "%s: src_stride %d dst_stride "
2829 "%d dst_height_aligned %d src_height %d need_copy %d\n",
2830 __func__, src_stride[0],
2831 dst_stride[0], dst_height_aligned[0],
2832 src_height[0], need_copy);
2833
2834 if (need_copy)
2835 {
2836 ni_copy_hw_yuv420p((uint8_t **)(p_enc_frame->p_data), p_src,
2837 frame_width, frame_height, p_ctx->bit_depth_factor,
2838 is_semiplanar,
2839 p_param->cfg_enc_params.conf_win_right, dst_stride,
2840 dst_height_aligned, src_stride, src_height);
2841 p_enc_frame->separate_metadata = 0;
2842 }
2843
2844 ni_log2(p_ctx, NI_LOG_DEBUG,
2845 "p_dst alloc linesize = %d/%d/%d src height=%d "
2846 "dst height aligned = %d/%d/%d force_key_frame=%d, "
2847 "extra_data_len=%u"
2848 " sei_size=%u (hdr_content_light_level %u hdr_mastering_display_"
2849 "color_vol %u hdr10+ %u hrd %d) reconf_size=%u roi_size=%u "
2850 "force_pic_qp=%u udu_sei_size=%u "
2851 "use_cur_src_as_long_term_pic %u use_long_term_ref %u\n",
2852 dst_stride[0], dst_stride[1], dst_stride[2], frame_height,
2853 dst_height_aligned[0], dst_height_aligned[1], dst_height_aligned[2],
2854 p_enc_frame->force_key_frame, p_enc_frame->extra_data_len,
2855 p_enc_frame->sei_total_len,
2858 p_enc_frame->sei_hdr_plus_len, 0, /* hrd is 0 size for now */
2859 p_enc_frame->reconf_len, p_enc_frame->roi_len,
2860 p_enc_frame->force_pic_qp, p_enc_frame->sei_user_data_unreg_len,
2861 p_enc_frame->use_cur_src_as_long_term_pic,
2862 p_enc_frame->use_long_term_ref);
2863
2864 ni_enc_copy_aux_data(p_ctx, p_enc_frame, p_enc_frame, p_ctx->codec_format,
2865 mdcv_data, cll_data, cc_data, udu_data, hdrp_data,
2866 0 /*swframe*/, is_semiplanar);
2867
2868send_frame:
2869 retval = ni_device_session_write(p_ctx, (ni_session_data_io_t *)p_enc_frame,
2871end:
2872 if (!need_copy)
2873 {
2874 // Don't want to accidentally free or reuse user-allocated YUV buffer, so remove from frame
2875 p_enc_frame->p_buffer = NULL;
2876 p_enc_frame->buffer_size = 0;
2877 for (int i = 0; i < NI_MAX_NUM_DATA_POINTERS; i++)
2878 {
2879 p_enc_frame->data_len[i] = 0;
2880 p_enc_frame->p_data[i] = NULL;
2881 }
2882 }
2883
2884 return retval;
2885}
2886
2887/*!*****************************************************************************
2888 * \brief Find the next start code
2889 *
2890 * \param[in] p pointer to buffer start address.
2891 * \param[in] end pointer to buffer end address.
2892 * \param[state] state pointer to nalu type address
2893 *
2894 * \return search end address
2895 ******************************************************************************/
2896const uint8_t *ni_find_start_code (const uint8_t *p, const uint8_t *end, uint32_t *state)
2897{
2898 int i;
2899
2900 if (p >= end)
2901 return end;
2902
2903 for (i = 0; i < 3; i++) {
2904 uint32_t tmp = *state << 8;
2905 *state = tmp + *(p++);
2906 if (tmp == 0x100 || p == end)
2907 return p;
2908 }
2909
2910 while (p < end) {
2911 if (p[-1] > 1)
2912 p += 3;
2913 else if (p[-2])
2914 p += 2;
2915 else if (p[-3] | (p[-1] - 1))
2916 p++;
2917 else {
2918 p++;
2919 break;
2920 }
2921 }
2922
2923 p = ((p) < (end) ? (p - 4) : (end - 4)); // min
2924 *state =
2925 (((uint32_t) (p)[0] << 24) | ((p)[1] << 16) | ((p)[2] << 8) | (p)[3]);
2926
2927 return p + 4;
2928}
2929
2930/*!******************************************************************************
2931 * \brief Extract custom sei payload data from pkt_data,
2932 * and save it to ni_packet_t
2933 *
2934 * \param uint8_t *pkt_data - FFmpeg AVPacket data
2935 * \param int pkt_size - packet size
2936 * \param long index - pkt data index of custom sei first byte after SEI type
2937 * \param ni_packet_t *p_packet - libxcoder internal packet
2938 * \param uint8_t sei_type - type of SEI
2939 * \param int vcl_found - whether got vcl in the pkt data, 1 means got
2940 *
2941 * \return - 0 on success, non-0 on failure
2942 ********************************************************************************/
2943int ni_extract_custom_sei(uint8_t *pkt_data, int pkt_size, long index,
2944 ni_packet_t *p_packet, uint8_t sei_type, int vcl_found)
2945{
2946 int i, len;
2947 uint8_t *udata;
2948 uint8_t *sei_data;
2949 int sei_size;
2950 int sei_index;
2951 ni_custom_sei_t *p_custom_sei;
2952
2953 ni_log(NI_LOG_TRACE, "%s() enter\n", __FUNCTION__);
2954
2955 if (p_packet->p_custom_sei_set == NULL)
2956 {
2957 /* max size */
2958 p_packet->p_custom_sei_set = (ni_custom_sei_set_t *)malloc(sizeof(ni_custom_sei_set_t));
2959 if (p_packet->p_custom_sei_set == NULL)
2960 {
2961 ni_log(NI_LOG_ERROR, "failed to allocate all custom sei buffer.\n");
2963 }
2964 memset(p_packet->p_custom_sei_set, 0, sizeof(ni_custom_sei_set_t));
2965 }
2966
2967 sei_index = p_packet->p_custom_sei_set->count;
2968 p_custom_sei = &p_packet->p_custom_sei_set->custom_sei[sei_index];
2969 if (sei_index >= NI_MAX_CUSTOM_SEI_CNT)
2970 {
2971 ni_log(NI_LOG_INFO, "number of custom sei in current frame is out of limit(%d).\n",
2973 return 0;
2974 }
2975 sei_data = &p_custom_sei->data[0];
2976
2984 sei_size = 0;
2985 while (index < pkt_size && pkt_data[index] == 0xff)
2986 {
2987 sei_size += pkt_data[index++];
2988 }
2989
2990 if (index >= pkt_size)
2991 {
2992 ni_log(NI_LOG_INFO, "custom sei corrupted: length truncated.\n");
2993 return NI_RETCODE_FAILURE;
2994 }
2995 sei_size += pkt_data[index++];
2996
2997 if (sei_size > NI_MAX_CUSTOM_SEI_DATA)
2998 {
2999 ni_log(NI_LOG_INFO, "custom sei corrupted: size(%d) out of limit(%d).\n",
3000 sei_size, NI_MAX_CUSTOM_SEI_DATA);
3001 return 0;
3002 }
3003
3004 udata = &pkt_data[index];
3005
3006 /* set SEI payload type at the first byte */
3007 sei_data[0] = sei_type;
3008
3009 /* extract SEI payload data
3010 * SEI payload data in NAL is EBSP(Encapsulated Byte Sequence Payload),
3011 * need change EBSP to RBSP(Raw Byte Sequence Payload) for exact size
3012 */
3013 for (i = 0, len = 0; (i < pkt_size - index) && len < sei_size; i++, len++)
3014 {
3015 /* if the latest 3-byte data pattern matchs '00 00 03' which means udata[i] is an escaping byte,
3016 * discard udata[i]. */
3017 if (i >= 2 && udata[i - 2] == 0 && udata[i - 1] == 0 && udata[i] == 3)
3018 {
3019 len--;
3020 continue;
3021 }
3022 sei_data[len] = udata[i];
3023 }
3024
3025 if (len != sei_size)
3026 {
3027 ni_log(NI_LOG_INFO, "custom sei corrupted: data truncated, "
3028 "required size:%d, actual size:%d.\n", sei_size, len);
3029 return NI_RETCODE_FAILURE;
3030 }
3031
3032 p_custom_sei->type = sei_type;
3033 p_custom_sei->size = sei_size;
3035
3036 p_packet->p_custom_sei_set->count++;
3037
3038 ni_log(NI_LOG_TRACE, "%s() exit, custom sei size=%d type=%d\n",
3039 __FUNCTION__, sei_size, sei_type);
3040
3041 return 0;
3042}
3043
3044/*!******************************************************************************
3045 * \brief Decode parse packet
3046 *
3047 * \param[in] p_session_ctx Pointer to a caller allocated
3048 * ni_session_context_t struct
3049 * \param[in] p_param Pointer to a caller allocated
3050 * ni_xcoder_params_t struct
3051 * \param[in] *data FFmpeg AVPacket data
3052 * \param[in] size packet size
3053 * \param[in] p_packet Pointer to a caller allocated
3054 * ni_packet_t struct
3055 * \param[in] low_delay FFmpeg lowdelay
3056 * \param[in] codec_format enum ni_codec_format_t
3057 * \param[in] pkt_nal_bitmap pkt_nal_bitmap
3058 * \param[in] custom_sei_type custom_sei_type
3059 * \param[in] *svct_skip_next_packet svct_skip_next_packet int*
3060 * \param[in] *is_lone_sei_pkt is_lone_sei_pkt int*
3061 *
3062 * \return - 0 on success, non-0 on failure
3063 ********************************************************************************/
3065 uint8_t *data, int size, ni_packet_t *p_packet, int low_delay,
3066 int codec_format, int pkt_nal_bitmap, int custom_sei_type,
3067 int *svct_skip_next_packet, int *is_lone_sei_pkt)
3068{
3069 int pkt_sei_alone = 1;
3070 int vcl_found = 0;
3071 int tmp_low_delay =
3072 (p_session_ctx->decoder_low_delay == -1) ? 0 : low_delay;
3073 int svct_layer = (codec_format == NI_CODEC_FORMAT_H264) ?
3076 // int pkt_nal_bitmap = ni_dec_ctx->pkt_nal_bitmap;
3077 const uint8_t *ptr = data;
3078 const uint8_t *end = data + size;
3079 uint32_t stc;
3080 int nalu_type;
3081 uint8_t sei_type = 0;
3082 int ret = 0;
3083 int nalu_count = 0;
3085 int temporal_id;
3086 const uint8_t *next = NULL;
3087 int sei_size = 0, i = 0;
3088
3089 if (pkt_nal_bitmap & NI_GENERATE_ALL_NAL_HEADER_BIT)
3090 {
3091 ni_log2(p_session_ctx, NI_LOG_TRACE,
3092 "ni_dec_packet_parse(): already find the header of streams.\n");
3093 low_delay = 0;
3094 }
3095
3096 while (
3097 (custom_sei_type != NI_INVALID_SEI_TYPE ||
3099 svct_layer != NI_INVALID_SVCT_DECODING_LAYER || tmp_low_delay ||
3101 ptr < end)
3102 {
3103 stc = -1;
3104 ptr = ni_find_start_code(ptr, end, &stc);
3105 if (ptr == end)
3106 {
3107 if (0 == nalu_count)
3108 {
3109 pkt_sei_alone = 0;
3110 ni_log2(p_session_ctx, NI_LOG_TRACE, "%s(): no NAL found in pkt.\n",
3111 __FUNCTION__);
3112 }
3113 break;
3114 }
3115 nalu_count++;
3116
3117 if (NI_CODEC_FORMAT_H264 == codec_format)
3118 {
3119 nalu_type = (int)stc & 0x1f;
3120
3121 //check whether the packet is sei alone
3122 pkt_sei_alone = (pkt_sei_alone && 6 /*H264_NAL_SEI */ == nalu_type);
3123
3124 // Enable decoder low delay mode on sequence change
3125 if (low_delay)
3126 {
3127 switch (nalu_type)
3128 {
3129 case 7 /*H264_NAL_SPS */:
3130 pkt_nal_bitmap |= NI_NAL_SPS_BIT;
3131 break;
3132 case 8 /*H264_NAL_PPS */:
3133 pkt_nal_bitmap |= NI_NAL_PPS_BIT;
3134 break;
3135 default:
3136 break;
3137 }
3138
3139 if (pkt_nal_bitmap == (NI_NAL_SPS_BIT | NI_NAL_PPS_BIT))
3140 {
3141 ni_log2(p_session_ctx, NI_LOG_TRACE,
3142 "ni_dec_packet_parse(): Detect SPS, PPS and IDR, "
3143 "enable decoder low delay mode.\n");
3144 p_session_ctx->decoder_low_delay = low_delay;
3145 pkt_nal_bitmap |= NI_GENERATE_ALL_NAL_HEADER_BIT;
3146 low_delay = 0;
3147 }
3148 }
3149 // check whether the packet contains SEI NAL after VCL units
3150 if (6 /*H264_NAL_SEI */ == nalu_type)
3151 {
3152 // Find the end of the SEI NAL unit
3153 next = ni_find_start_code(ptr, end, &stc);
3154 if (*(next - 5) == 0)
3155 next -= 5; // long start code
3156 else
3157 next -= 4; // short start code
3158
3159 // More SEI messages in the NAL unit if remaining data larger than 1 byte
3160 while (next - ptr > 1)
3161 {
3162 sei_type = *ptr;
3163 if (vcl_found ||
3164 custom_sei_type == sei_type ||
3165 p_param->dec_input_params.custom_sei_passthru == sei_type ||
3167 {
3168 // SEI after VCL found or SEI type indicated then extract
3169 // the SEI unit;
3170 // ret = ni_quadra_extract_custom_sei(ni_dec_ctx, data, size,
3171 // ptr + 1 - data, p_packet,
3172 // sei_type, vcl_found);
3173 ret = ni_extract_custom_sei(data, size,
3174 (long)(ptr + 1 - data), p_packet,
3175 sei_type, vcl_found);
3176 if (ret != 0)
3177 {
3178 return ret;
3179 }
3180 }
3181
3182 // Skip the current SEI message including any emulation prevention bytes
3183 ptr++;
3184 sei_size = 0;
3185 while (ptr < next && *ptr == 0xff)
3186 {
3187 sei_size += *ptr++;
3188 }
3189 sei_size += *ptr++;
3190 for (i = 0; i < sei_size; i++)
3191 {
3192 if (i >= 2 && *(ptr - 2) == 0 && *(ptr - 1) == 0 && *ptr == 3)
3193 sei_size++;
3194 ptr++;
3195 }
3196 }
3197 } else if (nalu_type >= 1 /* H264_NAL_SLICE */ &&
3198 nalu_type <= 5 /* H264_NAL_IDR_SLICE */)
3199 {
3200 vcl_found = 1;
3201 } else if (14 /*H264_NAL_PREFIX */ == nalu_type)
3202 {
3203 ni_bitstream_reader_init(&br, ptr,
3204 48); // 3 * 2 bytes * 8 = 48 bits
3205 // skip some header
3206 ni_bs_reader_skip_bits(&br, 16);
3207 temporal_id = ni_bs_reader_get_bits(&br, 3);
3208 if (temporal_id > svct_layer)
3209 {
3210 // H264_NAL_PREFIX UNIT will be sent with the last packet.
3211 // So, the H264_NAL_PREFIX here is used for the next packet.
3212 *svct_skip_next_packet = 1;
3213 ni_log2(p_session_ctx, NI_LOG_TRACE,
3214 "ni_dec_packet_parse(): temporal_id %d"
3215 " is bigger than decoded layer %d, skip the next "
3216 "packet\n",
3217 temporal_id, svct_layer);
3218 }
3219 }
3220 } else if (NI_CODEC_FORMAT_H265 == codec_format)
3221 {
3222 nalu_type = (int)(stc >> 1) & 0x3F;
3223
3224 //check whether the packet is sei alone
3225 pkt_sei_alone = (pkt_sei_alone &&
3226 (39 /* HEVC_NAL_SEI_PREFIX */ == nalu_type ||
3227 40 /* HEVC_NAL_SEI_SUFFIX */ == nalu_type));
3228
3229 // Enable decoder low delay mode on sequence change
3230 if (low_delay)
3231 {
3232 switch (nalu_type)
3233 {
3234 case 32 /* HEVC_NAL_VPS */:
3235 pkt_nal_bitmap |= NI_NAL_VPS_BIT;
3236 break;
3237 case 33 /* HEVC_NAL_SPS */:
3238 pkt_nal_bitmap |= NI_NAL_SPS_BIT;
3239 break;
3240 case 34 /* HEVC_NAL_PPS */:
3241 pkt_nal_bitmap |= NI_NAL_PPS_BIT;
3242 break;
3243 default:
3244 break;
3245 }
3246
3247 if (pkt_nal_bitmap ==
3249 {
3250 // Packets before the header is sent cannot be decoded.
3251 // So set packet num to zero here.
3252 ni_log2(p_session_ctx, NI_LOG_TRACE,
3253 "ni_dec_packet_parse(): Detect VPS, SPS, PPS and "
3254 "IDR enable decoder low delay mode.\n");
3255 p_session_ctx->decoder_low_delay = low_delay;
3256 pkt_nal_bitmap |= NI_GENERATE_ALL_NAL_HEADER_BIT;
3257 low_delay = 0;
3258 }
3259 }
3260 // check whether the packet contains SEI NAL after VCL units
3261 if (39 /* HEVC_NAL_SEI_PREFIX */ == nalu_type ||
3262 40 /* HEVC_NAL_SEI_SUFFIX */ == nalu_type)
3263 {
3264 // Find the end of the SEI NAL unit
3265 next = ni_find_start_code(ptr, end, &stc);
3266 if (*(next - 5) == 0)
3267 next -= 5; // long start code
3268 else
3269 next -= 4; // short start code
3270
3271 // Skip NAL unit header
3272 ptr++;
3273
3274 // More SEI messages in the NAL unit if remaining data larger than 1 byte
3275 while (next - ptr > 1)
3276 {
3277 sei_type = *ptr;
3278 if (vcl_found ||
3279 custom_sei_type == sei_type ||
3280 p_param->dec_input_params.custom_sei_passthru == sei_type ||
3282 {
3283 // SEI after VCL found or SEI type indicated then extract
3284 // the SEI unit;
3285 // ret = ni_quadra_extract_custom_sei(ni_dec_ctx, data, size,
3286 // ptr + 2 - data, p_packet,
3287 // sei_type, vcl_found);
3288 ret = ni_extract_custom_sei(data, size, (long)(ptr + 1 - data), p_packet,
3289 sei_type, vcl_found);
3290 if (ret != 0)
3291 {
3292 return ret;
3293 }
3294 }
3295
3296 // Skip the current SEI message including any emulation prevention bytes
3297 ptr++;
3298 sei_size = 0;
3299 while (ptr < next && *ptr == 0xff)
3300 {
3301 sei_size += *ptr++;
3302 }
3303 sei_size += *ptr++;
3304 for (i = 0; i < sei_size; i++)
3305 {
3306 if (i >= 2 && *(ptr - 2) == 0 && *(ptr - 1) == 0 && *ptr == 3)
3307 sei_size++;
3308 ptr++;
3309 }
3310 }
3311 } else if (nalu_type >= 0 /* HEVC_NAL_TRAIL_N */ &&
3312 nalu_type <= 31 /* HEVC_NAL_RSV_VCL31 */)
3313 {
3314 vcl_found = 1;
3315 }
3316 } else
3317 {
3318 ni_log2(p_session_ctx,NI_LOG_DEBUG, "%s() wrong codec %d !\n", __FUNCTION__, codec_format);
3319 pkt_sei_alone = 0;
3320 break;
3321 }
3322 }
3323
3324 if (nalu_count > 0)
3325 {
3326 *is_lone_sei_pkt = pkt_sei_alone;
3327 }
3328
3329 return 0;
3330}
3331
3332/*!******************************************************************************
3333 * \brief Expand frame form src frame
3334 *
3335 * \param[in] dst Pointer to a caller allocated ni_frame_t struct
3336 * \param[in] src Pointer to a caller allocated ni_frame_t struct
3337 * \param[in] dst_stride int dst_stride[]
3338 * \param[in] raw_width frame width
3339 * \param[in] raw_height frame height
3340 * \param[in] ni_fmt ni_pix_fmt_t type for ni pix_fmt
3341 * \param[in] nb_planes int nb_planes
3342 *
3343 * \return - 0 on success, NI_RETCODE_FAILURE on failure
3344 ********************************************************************************/
3345int ni_expand_frame(ni_frame_t *dst, ni_frame_t *src, int dst_stride[],
3346 int raw_width, int raw_height, int ni_fmt, int nb_planes)
3347{
3348 int i, j, h, tenBit = 0;
3349 int vpad[3], hpad[3], src_height[3], src_width[3], src_stride[3];
3350 uint8_t *src_line, *dst_line, *sample, *dest, YUVsample;
3351 uint16_t lastidx;
3352
3353 switch (ni_fmt)
3354 {
3355 case NI_PIX_FMT_YUV420P:
3356 /* width of source frame for each plane in pixels */
3357 src_width[0] = NIALIGN(raw_width, 2);
3358 src_width[1] = NIALIGN(raw_width, 2) / 2;
3359 src_width[2] = NIALIGN(raw_width, 2) / 2;
3360
3361 /* height of source frame for each plane in pixels */
3362 src_height[0] = NIALIGN(raw_height, 2);
3363 src_height[1] = NIALIGN(raw_height, 2) / 2;
3364 src_height[2] = NIALIGN(raw_height, 2) / 2;
3365
3366 /* stride of source frame for each plane in bytes */
3367 src_stride[0] = NIALIGN(src_width[0], 128);
3368 src_stride[1] = NIALIGN(src_width[1], 128);
3369 src_stride[2] = NIALIGN(src_width[2], 128);
3370
3371 tenBit = 0;
3372
3373 /* horizontal padding needed for each plane in bytes */
3374 hpad[0] = dst_stride[0] - src_width[0];
3375 hpad[1] = dst_stride[1] - src_width[1];
3376 hpad[2] = dst_stride[2] - src_width[2];
3377
3378 /* vertical padding needed for each plane in pixels */
3379 vpad[0] = NI_MIN_HEIGHT - src_height[0];
3380 vpad[1] = NI_MIN_HEIGHT / 2 - src_height[1];
3381 vpad[2] = NI_MIN_HEIGHT / 2 - src_height[2];
3382
3383 break;
3384
3386 /* width of source frame for each plane in pixels */
3387 src_width[0] = NIALIGN(raw_width, 2);
3388 src_width[1] = NIALIGN(raw_width, 2) / 2;
3389 src_width[2] = NIALIGN(raw_width, 2) / 2;
3390
3391 /* height of source frame for each plane in pixels */
3392 src_height[0] = NIALIGN(raw_height, 2);
3393 src_height[1] = NIALIGN(raw_height, 2) / 2;
3394 src_height[2] = NIALIGN(raw_height, 2) / 2;
3395
3396 /* stride of source frame for each plane in bytes */
3397 src_stride[0] = NIALIGN(src_width[0] * 2, 128);
3398 src_stride[1] = NIALIGN(src_width[1] * 2, 128);
3399 src_stride[2] = NIALIGN(src_width[2] * 2, 128);
3400
3401 tenBit = 1;
3402
3403 /* horizontal padding needed for each plane in bytes */
3404 hpad[0] = dst_stride[0] - src_width[0] * 2;
3405 hpad[1] = dst_stride[1] - src_width[1] * 2;
3406 hpad[2] = dst_stride[2] - src_width[2] * 2;
3407
3408 /* vertical padding needed for each plane in pixels */
3409 vpad[0] = NI_MIN_HEIGHT - src_height[0];
3410 vpad[1] = NI_MIN_HEIGHT / 2 - src_height[1];
3411 vpad[2] = NI_MIN_HEIGHT / 2 - src_height[2];
3412
3413 break;
3414
3415 case NI_PIX_FMT_NV12:
3416 /* width of source frame for each plane in pixels */
3417 src_width[0] = NIALIGN(raw_width, 2);
3418 src_width[1] = NIALIGN(raw_width, 2);
3419 src_width[2] = 0;
3420
3421 /* height of source frame for each plane in pixels */
3422 src_height[0] = NIALIGN(raw_height, 2);
3423 src_height[1] = NIALIGN(raw_height, 2) / 2;
3424 src_height[2] = 0;
3425
3426 /* stride of source frame for each plane in bytes */
3427 src_stride[0] = NIALIGN(src_width[0], 128);
3428 src_stride[1] = NIALIGN(src_width[1], 128);
3429 src_stride[2] = 0;
3430
3431 tenBit = 0;
3432
3433 /* horizontal padding needed for each plane in bytes */
3434 hpad[0] = dst_stride[0] - src_width[0];
3435 hpad[1] = dst_stride[1] - src_width[1];
3436 hpad[2] = 0;
3437
3438 /* vertical padding for each plane in pixels */
3439 vpad[0] = NI_MIN_HEIGHT - src_height[0];
3440 vpad[1] = NI_MIN_HEIGHT / 2 - src_height[1];
3441 vpad[2] = 0;
3442
3443 break;
3444
3445 case NI_PIX_FMT_P010LE:
3446 /* width of source frame for each plane in pixels */
3447 src_width[0] = NIALIGN(raw_width, 2);
3448 src_width[1] = NIALIGN(raw_width, 2);
3449 src_width[2] = 0;
3450
3451 /* height of source frame for each plane in pixels */
3452 src_height[0] = NIALIGN(raw_height, 2);
3453 src_height[1] = NIALIGN(raw_height, 2) / 2;
3454 src_height[2] = 0;
3455
3456 /* stride of source frame for each plane in bytes */
3457 src_stride[0] = NIALIGN(src_width[0] * 2, 128);
3458 src_stride[1] = NIALIGN(src_width[1] * 2, 128);
3459 src_stride[2] = 0;
3460
3461 tenBit = 1;
3462
3463 /* horizontal padding needed for each plane in bytes */
3464 hpad[0] = dst_stride[0] - src_width[0] * 2;
3465 hpad[1] = dst_stride[1] - src_width[1] * 2;
3466 hpad[2] = 0;
3467
3468 /* vertical padding for each plane in pixels */
3469 vpad[0] = NI_MIN_HEIGHT - src_height[0];
3470 vpad[1] = NI_MIN_HEIGHT / 2 - src_height[1];
3471 vpad[2] = 0;
3472
3473 break;
3474
3475 default:
3476 ni_log(NI_LOG_ERROR, "Invalid pixel format %d\n",ni_fmt);
3477 return NI_RETCODE_FAILURE;
3478 }
3479
3480 for (i = 0; i < nb_planes && nb_planes < NI_MAX_NUM_DATA_POINTERS; i++)
3481 {
3482 dst_line = dst->p_data[i];
3483 src_line = src->p_data[i];
3484
3485 for (h = 0; i < 3 && h < src_height[i]; h++)
3486 {
3487 memcpy(dst_line, src_line, src_width[i] * (tenBit + 1));
3488
3489 /* Add horizontal padding */
3490 if (hpad[i])
3491 {
3492 lastidx = src_width[i];
3493
3494 if (tenBit)
3495 {
3496 sample = &src_line[(lastidx - 1) * 2];
3497 dest = &dst_line[lastidx * 2];
3498
3499 /* two bytes per sample */
3500 for (j = 0; j < hpad[i] / 2; j++)
3501 {
3502 memcpy(dest, sample, 2);
3503 dest += 2;
3504 }
3505 } else
3506 {
3507 YUVsample = dst_line[lastidx - 1];
3508 memset(&dst_line[lastidx], YUVsample, hpad[i]);
3509 }
3510 }
3511
3512 src_line += src_stride[i];
3513 dst_line += dst_stride[i];
3514 }
3515
3516 /* Pad the height by duplicating the last line */
3517 src_line = dst_line - dst_stride[i];
3518
3519 for (h = 0; h < vpad[i]; h++)
3520 {
3521 memcpy(dst_line, src_line, dst_stride[i]);
3522 dst_line += dst_stride[i];
3523 }
3524 }
3525
3526 return 0;
3527}
3528
3529/*!******************************************************************************
3530 * \brief Reset decoder ppu resolution
3531 *
3532 * \param[in] p_session_ctx Pointer to a caller allocated
3533 * ni_session_context_t struct
3534 * \param[in] p_param Pointer to a caller allocated
3535 * ni_xcoder_params_t struct
3536 * \param[in] ppu_config Pointer to a caller allocated
3537 * ni_ppu_config_t struct
3538 *
3539 * \return - 0 on success, NI_RETCODE_FAILURE on failure
3540 ********************************************************************************/
3542 ni_xcoder_params_t *p_param, ni_ppu_config_t *ppu_config)
3543{
3544 int sei_size, size, len;
3545 int ret = 0, i = 0, j = 0;
3546 uint8_t *p_src_sei_data, *p_dst_sei_data;
3547 ni_custom_sei_t *p_dst_custom_sei;
3548
3549 if (!p_session_ctx || !p_param || !ppu_config)
3550 {
3552 return ret;
3553 }
3554
3555 // check fw revision
3557 (char*) &p_session_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX],
3558 "6rx") < 0)
3559 {
3560 ni_log2(p_session_ctx, NI_LOG_ERROR, "%s: not supported on device with FW API version < 6rx\n", __func__);
3562 }
3563
3564 if (NI_CODEC_FORMAT_H264 != p_session_ctx->codec_format &&
3565 NI_CODEC_FORMAT_H265 != p_session_ctx->codec_format)
3566 {
3567 ni_log2(p_session_ctx, NI_LOG_ERROR, "%s(): Ppu reconfig only support "
3568 "h264 and h265 decoder\n", __func__);
3570 }
3571
3572 ni_decoder_input_params_t *p_dec_input_param = &(p_param->dec_input_params);
3573 if (p_dec_input_param->hwframes != 1)
3574 {
3575 ni_log2(p_session_ctx, NI_LOG_ERROR, "%s(): Not hw mode, "
3576 "So can't reconfig ppu\n", __func__);
3578 }
3579 if (p_dec_input_param->enable_out1 == 0 &&
3580 ppu_config->ppu_set_enable & (0x01 << 1))
3581 {
3582 ni_log2(p_session_ctx, NI_LOG_ERROR, "%s(): Warning Not enable ppu1, "
3583 "So can't reconfig ppu1\n", __func__);
3585 }
3586 if (p_dec_input_param->enable_out2 == 0 &&
3587 ppu_config->ppu_set_enable & (0x01 << 2))
3588 {
3589 ni_log2(p_session_ctx, NI_LOG_ERROR, "%s(): Warning Not enable ppu2, "
3590 "So can't reconfig ppu2\n", __func__);
3592 }
3593 for (i = 0; i < NI_MAX_NUM_OF_DECODER_OUTPUTS; i++)
3594 {
3595 if (ppu_config->ppu_set_enable & (0x01 << i))
3596 {
3597 if (ppu_config->ppu_w[i] > NI_MAX_RESOLUTION_WIDTH ||
3598 ppu_config->ppu_h[i] > NI_MAX_RESOLUTION_HEIGHT ||
3599 ppu_config->ppu_w[i] < NI_MIN_RESOLUTION_WIDTH_SCALER ||
3600 ppu_config->ppu_h[i] < NI_MIN_RESOLUTION_WIDTH_SCALER)
3601 {
3602 ni_log2(p_session_ctx, NI_LOG_ERROR, "%s(): ppu width x height %dx%d "
3603 "out of range\n", __func__, ppu_config->ppu_w[i], ppu_config->ppu_h[i]);
3605 return ret;
3606 }
3607 if ((ppu_config->ppu_w[i] & 1) || (ppu_config->ppu_h[i] & 1))
3608 {
3609 ni_log2(p_session_ctx, NI_LOG_ERROR, "%s(): ppu wxh %dx%d not align to 2!\n",
3610 __func__, ppu_config->ppu_w[i], ppu_config->ppu_h[i]);
3612 return ret;
3613 }
3614 }
3615 }
3616 p_dst_custom_sei = malloc(sizeof(ni_custom_sei_t));
3617 if (p_dst_custom_sei == NULL)
3618 {
3619 ni_log2(p_session_ctx, NI_LOG_ERROR, "%s(): failed "
3620 "to allocate memory for custom sei data\n", __func__);
3622 return ret;
3623 }
3624 memset(p_dst_custom_sei, 0, sizeof(ni_custom_sei_t));
3625
3626
3627 sei_size = sizeof(ni_ppu_config_t);
3628
3629 p_src_sei_data = (uint8_t *)ppu_config;
3630 p_dst_sei_data = &p_dst_custom_sei->data[0];
3631 size = 0;
3632
3633 // long start code
3634 p_dst_sei_data[size++] = 0x00;
3635 p_dst_sei_data[size++] = 0x00;
3636 p_dst_sei_data[size++] = 0x00;
3637 p_dst_sei_data[size++] = 0x01;
3638
3639 if (NI_CODEC_FORMAT_H264 == p_session_ctx->codec_format)
3640 {
3641 p_dst_sei_data[size++] = 0x06; //nal type: SEI
3642 }
3643 else
3644 {
3645 p_dst_sei_data[size++] = 0x4e; //nal type: SEI
3646 p_dst_sei_data[size++] = 0x01;
3647 }
3648
3649 // SEI type
3650 p_dst_sei_data[size++] = NI_SEI_TYPE_PPU_RECONFIG;
3651
3652 // original payload size
3653 len = sei_size;
3654 while (len >= 0)
3655 {
3656 p_dst_sei_data[size++] = len > 0xff ? 0xff : len;
3657 len -= 0xff;
3658 }
3659
3660 // payload data
3661 for (j = 0; j < sei_size && size < NI_MAX_CUSTOM_SEI_DATA - 1; j++)
3662 {
3663 if (j >= 2 && !p_dst_sei_data[size - 2] && !p_dst_sei_data[size - 1] && p_src_sei_data[j] <= 0x03)
3664 {
3665 /* insert 0x3 as emulation_prevention_three_byte */
3666 p_dst_sei_data[size++] = 0x03;
3667 }
3668 p_dst_sei_data[size++] = p_src_sei_data[j];
3669 }
3670
3671 if (j != sei_size)
3672 {
3673 ni_log2(p_session_ctx, NI_LOG_ERROR, "%s(): sei RBSP size out of limit(%d), "
3674 "idx=%u, size=%d\n", __func__,
3675 NI_MAX_CUSTOM_SEI_DATA, i, sei_size);
3676 free(p_dst_custom_sei);
3677 return NI_RETCODE_FAILURE;
3678 }
3679
3680 // trailing byte
3681 p_dst_sei_data[size++] = 0x80;
3682
3683 memcpy(p_session_ctx->p_leftover + p_session_ctx->prev_size,
3684 p_dst_sei_data, size);
3685 p_session_ctx->prev_size += size;
3686 free(p_dst_custom_sei);
3687
3688 return ret;
3689}
void ni_dec_retrieve_aux_data(ni_frame_t *frame)
Retrieve auxiliary data (close caption, various SEI) associated with this frame that is returned by d...
int ni_extract_custom_sei(uint8_t *pkt_data, int pkt_size, long index, ni_packet_t *p_packet, uint8_t sei_type, int vcl_found)
Extract custom sei payload data from pkt_data, and save it to ni_packet_t.
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...
const uint8_t * ni_find_start_code(const uint8_t *p, const uint8_t *end, uint32_t *state)
Find the next start code.
int ni_expand_frame(ni_frame_t *dst, ni_frame_t *src, int dst_stride[], int raw_width, int raw_height, int ni_fmt, int nb_planes)
Expand frame form src frame.
int ni_reconfig_ppu_output(ni_session_context_t *p_session_ctx, ni_xcoder_params_t *p_param, ni_ppu_config_t *ppu_config)
Reset decoder ppu resolution.
gop_preset_t
Definition ni_av_codec.c:52
@ GOP_PRESET_BSP_2
Definition ni_av_codec.c:64
@ GOP_PRESET_BBSP_3
Definition ni_av_codec.c:70
@ NUM_GOP_PRESET_NUM
Definition ni_av_codec.c:73
@ GOP_PRESET_BBP_3
Definition ni_av_codec.c:69
@ GOP_PRESET_LP_4
Definition ni_av_codec.c:59
@ GOP_PRESET_SP_1
Definition ni_av_codec.c:63
@ GOP_PRESET_BBBP_3
Definition ni_av_codec.c:58
@ GOP_PRESET_CUSTOM
Definition ni_av_codec.c:53
@ GOP_PRESET_BP_2
Definition ni_av_codec.c:57
@ GOP_PRESET_B_1
Definition ni_av_codec.c:56
@ GOP_PRESET_P_1
Definition ni_av_codec.c:55
@ GOP_PRESET_BBBSP_3
Definition ni_av_codec.c:65
@ GOP_PRESET_BBBBBBBP_8
Definition ni_av_codec.c:71
@ GOP_PRESET_BBBBBBBSP_8
Definition ni_av_codec.c:72
@ GOP_PRESET_RA_8
Definition ni_av_codec.c:61
@ GOP_PRESET_LD_4
Definition ni_av_codec.c:60
@ GOP_PRESET_LSP_4
Definition ni_av_codec.c:66
@ GOP_PRESET_I_1
Definition ni_av_codec.c:54
LIB_API int ni_enc_insert_timecode(ni_session_context_t *p_enc_ctx, ni_frame_t *p_enc_frame, ni_timecode_t *p_timecode)
Insert timecode data into picture timing SEI (H264) or time code SEI (H265)
int ni_dec_packet_parse(ni_session_context_t *p_session_ctx, ni_xcoder_params_t *p_param, uint8_t *data, int size, ni_packet_t *p_packet, int low_delay, int codec_format, int pkt_nal_bitmap, int custom_sei_type, int *svct_skip_next_packet, int *is_lone_sei_pkt)
Decode parse packet.
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.
slice_type_t
Definition ni_av_codec.c:44
@ SLICE_TYPE_I
Definition ni_av_codec.c:47
@ SLICE_TYPE_P
Definition ni_av_codec.c:46
@ SLICE_TYPE_MP
Definition ni_av_codec.c:48
@ SLICE_TYPE_B
Definition ni_av_codec.c:45
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
#define NI_NAL_VPS_BIT
Definition ni_av_codec.h:39
@ NI_COL_PRI_UNSPECIFIED
Definition ni_av_codec.h:99
#define NI_SEI_TYPE_PPU_RECONFIG
Definition ni_av_codec.h:50
enum _ni_hdr_plus_overlap_process_option ni_hdr_plus_overlap_process_option_t
#define MASTERING_DISP_LUMA_DEN
#define MASTERING_DISP_CHROMA_DEN
#define NI_NAL_SPS_BIT
Definition ni_av_codec.h:40
#define NI_NAL_PPS_BIT
Definition ni_av_codec.h:41
#define NI_GENERATE_ALL_NAL_HEADER_BIT
Definition ni_av_codec.h:42
void ni_bitstream_writer_init(ni_bitstream_writer_t *stream)
init a bitstream writer
void ni_bs_writer_copy(uint8_t *dst, const ni_bitstream_writer_t *stream)
copy bitstream data to dst Note: caller must ensure sufficient space in dst
void ni_bs_writer_align_zero(ni_bitstream_writer_t *stream)
align the bitstream with zero
void ni_bitstream_reader_init(ni_bitstream_reader_t *br, const uint8_t *data, int bit_size)
init a bitstream reader Note: bitstream_reader takes reading ownership of the data
uint32_t ni_bs_reader_get_bits(ni_bitstream_reader_t *br, int n)
read bits (up to 32) from the bitstream reader, after reader init
void ni_bs_writer_clear(ni_bitstream_writer_t *stream)
clear and reset bitstream
uint64_t ni_bs_writer_tell(const ni_bitstream_writer_t *const stream)
return the number of bits written to bitstream so far
void ni_bs_writer_put(ni_bitstream_writer_t *stream, uint32_t data, uint8_t bits)
write a specified number (<= 32) of bits to bitstream, buffer individual bits until a full byte is ma...
void ni_bs_reader_skip_bits(ni_bitstream_reader_t *br, int n)
skip a number of bits ahead in the bitstream reader
Utility definitions to operate on bits in a bitstream.
#define NI_INVALID_SEI_TYPE
Definition ni_defs.h:314
#define NI_XCODER_REVISION_API_MAJOR_VER_IDX
Definition ni_defs.h:99
#define NI_MAX_NUM_DATA_POINTERS
Definition ni_defs.h:244
#define NI_APP_ENC_FRAME_META_DATA_SIZE_UNDER_MAJOR_6_MINOR_rc
Definition ni_defs.h:325
#define NI_APP_ENC_FRAME_META_DATA_SIZE
Definition ni_defs.h:322
#define NI_MAX_CUSTOM_SEI_CNT
Definition ni_defs.h:317
#define NI_MAX_NUM_OF_DECODER_OUTPUTS
Definition ni_defs.h:255
@ NI_DEVICE_TYPE_ENCODER
Definition ni_defs.h:361
#define NI_APP_ENC_FRAME_META_DATA_SIZE_UNDER_MAJOR_6_MINOR_Q
Definition ni_defs.h:324
#define NI_MEM_PAGE_ALIGNMENT
Definition ni_defs.h:263
ni_retcode_t
Definition ni_defs.h:442
@ NI_RETCODE_FAILURE
Definition ni_defs.h:444
@ NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION
Definition ni_defs.h:537
@ NI_RETCODE_SUCCESS
Definition ni_defs.h:443
@ NI_RETCODE_PARAM_INVALID_VALUE
Definition ni_defs.h:453
@ NI_RETCODE_ERROR_MEM_ALOC
Definition ni_defs.h:447
@ NI_RETCODE_INVALID_PARAM
Definition ni_defs.h:445
#define NI_UNUSED
Definition ni_defs.h:67
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_encoder_frame_zerocopy_buffer_alloc(ni_frame_t *p_frame, int video_width, int video_height, const int linesize[], const uint8_t *data[], int extra_len)
Allocate memory for encoder zero copy (metadata, etc.) for encoding based on given parameters,...
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_aux_data_t * ni_frame_get_aux_data(const ni_frame_t *frame, ni_aux_data_type_t type)
Retrieve from the frame auxiliary data of a given type if exists.
ni_aux_data_t * ni_frame_new_aux_data_from_raw_data(ni_frame_t *frame, ni_aux_data_type_t type, const uint8_t *raw_data, int data_size)
Add a new auxiliary data to a frame and copy in the raw data.
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,...
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...
#define NI_MIN_HEIGHT
@ SESSION_RUN_STATE_SEQ_CHANGE_DRAINING
@ NI_CUSTOM_SEI_LOC_AFTER_VCL
@ NI_CUSTOM_SEI_LOC_BEFORE_VCL
#define NI_CC_SEI_TRAILER_LEN
#define NI_MAX_SEI_DATA
#define NI_CC_SEI_HDR_H264_LEN
#define NI_MAX_CUSTOM_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_MASTERING_DISPLAY_METADATA
@ NI_FRAME_AUX_DATA_BITRATE
@ NI_FRAME_AUX_DATA_SLICE_ARG
@ NI_FRAME_AUX_DATA_CRF_FLOAT
@ NI_FRAME_AUX_DATA_UDU_SEI
@ NI_FRAME_AUX_DATA_MAX_MIN_QP
@ NI_FRAME_AUX_DATA_FRAMERATE
@ NI_FRAME_AUX_DATA_LTR_INTERVAL
@ NI_FRAME_AUX_DATA_HDR_PLUS
@ 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_VUI
@ NI_FRAME_AUX_DATA_INVALID_REF_FRAME
@ NI_FRAME_AUX_DATA_A53_CC
@ NI_FRAME_AUX_DATA_CONTENT_LIGHT_LEVEL
@ NI_FRAME_AUX_DATA_REGIONS_OF_INTEREST
@ NI_FRAME_AUX_DATA_LONG_TERM_REF
@ NI_FRAME_AUX_DATA_VBV_BUFFER_SIZE
#define NI_MAX_RESOLUTION_WIDTH
#define NI_MAX_SLICE_SIZE
#define NI_ENC_MAX_SEI_BUF_SIZE
struct _ni_ppu_config ni_ppu_config_t
#define NI_HDR10P_SEI_HDR_H264_LEN
#define NI_DEFAULT_INTRA_QP
#define NI_MAX_QP_DELTA
#define NI_MIN_QP_DELTA
#define NI_CUSTOMIZE_ROI_QPOFFSET_LEVEL
Max number of lines supported for qpoffset level.
enum _ni_codec_format ni_codec_format_t
This is an enumeration for supported codec formats.
#define NI_MAX_QP_INFO
#define NI_MIN_RESOLUTION_WIDTH_SCALER
#define NI_MAX_FRAMERATE
#define NI_HDR10P_SEI_HDR_HEVC_LEN
@ NI_CODEC_HW_NONE
@ NI_CODEC_FORMAT_H265
@ NI_CODEC_FORMAT_AV1
@ NI_CODEC_FORMAT_H264
@ NI_CODEC_FORMAT_JPEG
@ 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
#define NI_MAX_ASPECTRATIO
ni_pic_type_t
@ PIC_TYPE_IDR
@ PIC_TYPE_P
@ NI_CUS_ROI_MAPFILE
#define NI_MAX_RESOLUTION_HEIGHT
#define NI_INTRA_QP_RANGE
@ NI_SET_CHANGE_PARAM_INVALID_REF_FRAME
@ NI_SET_CHANGE_PARAM_RC_TARGET_RATE
@ NI_SET_CHANGE_PARAM_RC_FRAMERATE
@ NI_SET_CHANGE_PARAM_CRF
@ NI_SET_CHANGE_PARAM_LTR_INTERVAL
@ NI_SET_CHANGE_PARAM_VBV
@ NI_SET_CHANGE_PARAM_VUI_HRD_PARAM
@ NI_SET_CHANGE_PARAM_RC_MIN_MAX_QP
@ NI_SET_CHANGE_PARAM_SLICE_ARG
@ NI_SET_CHANGE_PARAM_INTRA_PERIOD
@ NI_SET_CHANGE_PARAM_MAX_FRAME_SIZE
#define NI_INVALID_SVCT_DECODING_LAYER
#define NI_CC_SEI_HDR_HEVC_LEN
#define NI_RBSP_TRAILING_BITS_LEN
int ni_get_planar_from_pixfmt(int pix_fmt)
Grab planar info from NI_PIX_FMT.
Private definitions used by ni_device_api.c for video processing tasks.
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
@ 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
Private definitions for interfacing with NETINT video processing devices over NVMe.
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_insert_emulation_prevent_bytes(uint8_t *buf, int size)
Insert emulation prevention byte(s) as needed into the data buffer.
Definition ni_util.c:3215
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
int ni_cmp_fw_api_ver(const char ver1[], const char ver2[])
Compare two 3 character strings containing a FW API version. Handle comparision when FW API version f...
Definition ni_util.c:4302
Utility definitions.
#define NIALIGN(x, a)
Definition ni_util.h:100
payload format of HDR SEI content light level info
ni_custom_sei_t custom_sei[NI_MAX_CUSTOM_SEI_CNT]
custom sei payload passthrough
uint8_t data[NI_MAX_CUSTOM_SEI_DATA]
ni_custom_sei_location_t location
decoded payload format of HDR SEI mastering display colour volume
uint8_t targeted_system_display_actual_peak_luminance_flag
uint8_t num_cols_targeted_system_display_actual_peak_luminance
uint8_t num_rows_mastering_display_actual_peak_luminance
uint8_t num_rows_targeted_system_display_actual_peak_luminance
uint8_t num_cols_mastering_display_actual_peak_luminance
ni_rational_t targeted_system_display_maximum_luminance
ni_rational_t mastering_display_actual_peak_luminance[25][25]
uint8_t itu_t_t35_country_code
uint8_t mastering_display_actual_peak_luminance_flag
ni_hdr_plus_color_transform_params_t params[3]
ni_rational_t targeted_system_display_actual_peak_luminance[25][25]
encoded payload format of HDR SEI mastering display colour volume
struct _ni_encoder_cfg_params::@16 rc
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]
unsigned int sei_hdr_mastering_display_color_vol_offset
uint8_t * p_buffer
uint32_t vui_time_scale
uint32_t start_of_stream
unsigned int sei_hdr_content_light_level_info_offset
uint16_t sar_width
uint8_t color_primaries
unsigned int vui_len
unsigned int reconf_len
uint8_t preferred_characteristics_data_len
uint32_t vui_num_units_in_tick
uint8_t aspect_ratio_idc
uint32_t end_of_stream
uint16_t sar_height
uint8_t separate_metadata
unsigned int sei_hdr_plus_len
unsigned int vui_offset
uint32_t video_width
unsigned int sei_hdr_plus_offset
uint8_t * p_data[NI_MAX_NUM_DATA_POINTERS]
uint8_t color_space
unsigned int extra_data_len
uint32_t buffer_size
unsigned int sei_total_len
unsigned int sei_cc_len
unsigned int sei_cc_offset
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
uint8_t * p_metadata_buffer
unsigned int sei_hdr_mastering_display_color_vol_len
int video_full_range_flag
unsigned int sei_user_data_unreg_offset
uint8_t use_long_term_ref
uint32_t video_height
unsigned int roi_len
unsigned int sei_alt_transfer_characteristics_len
unsigned int sei_alt_transfer_characteristics_offset
int32_t framerate_denom
int32_t framerate_num
ni_hdr_plus_percentile_t distribution_maxrgb[15]
ni_hdr_plus_overlap_process_option_t overlap_process_option
ni_rational_t percentile
uint8_t use_cur_src_as_long_term_pic
ni_rational_t display_primaries[3][2]
ni_custom_sei_set_t * p_custom_sei_set
uint16_t ppu_h[NI_MAX_NUM_OF_DECODER_OUTPUTS]
uint16_t ppu_w[NI_MAX_NUM_OF_DECODER_OUTPUTS]
uint8_t itu_t_t35_hdr10p_sei_hdr_hevc[NI_HDR10P_SEI_HDR_HEVC_LEN]
uint8_t preferred_characteristics_data
uint8_t ui8_light_level_data[5]
int sei_hdr_mastering_display_color_vol_len
uint8_t sei_trailer[NI_CC_SEI_TRAILER_LEN]
ni_framerate_t framerate
uint8_t ui8_mdcv_max_min_lum_data[9]
uint8_t itu_t_t35_cc_sei_hdr_hevc[NI_CC_SEI_HDR_HEVC_LEN]
uint8_t itu_t_t35_cc_sei_hdr_h264[NI_CC_SEI_HDR_H264_LEN]
ni_framerate_t last_framerate
uint32_t force_idr_intra_offset
ni_long_term_ref_t ltr_to_set
ni_session_run_state_t session_run_state
ni_encoder_change_params_t * enc_change_params
uint8_t itu_t_t35_hdr10p_sei_hdr_h264[NI_HDR10P_SEI_HDR_H264_LEN]
ni_enc_quad_roi_custom_map * roi_map
ni_region_of_interest_t * av_rois
uint8_t minutes_value
uint32_t time_offset_value
uint8_t counting_type
uint8_t hours_flag
uint16_t n_frames
uint8_t minutes_flag
uint8_t hours_value
uint8_t full_timestamp_flag
uint8_t nuit_field_based_flag
uint8_t time_offset_length
uint8_t seconds_flag
uint8_t discontinuity_flag
uint8_t seconds_value
uint8_t cnt_dropped_flag
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
ni_decoder_input_params_t dec_input_params
encoder AVC ROI custom map (1 MB = 8bits)